Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / apps / ephemeral_app_launcher.cc
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/apps/ephemeral_app_launcher.h"
6
7 #include "chrome/browser/chrome_notification_types.h"
8 #include "chrome/browser/extensions/extension_install_prompt.h"
9 #include "chrome/browser/extensions/extension_service.h"
10 #include "chrome/browser/extensions/extension_util.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/ui/extensions/application_launch.h"
13 #include "chrome/browser/ui/extensions/extension_enable_flow.h"
14 #include "content/public/browser/notification_details.h"
15 #include "content/public/browser/notification_source.h"
16 #include "content/public/browser/web_contents.h"
17 #include "content/public/browser/web_contents_view.h"
18 #include "extensions/browser/extension_system.h"
19 #include "extensions/common/permissions/permissions_data.h"
20
21 using content::WebContents;
22 using extensions::Extension;
23 using extensions::ExtensionSystem;
24 using extensions::WebstoreInstaller;
25
26 namespace {
27
28 const char kInvalidManifestError[] = "Invalid manifest";
29 const char kExtensionTypeError[] = "Ephemeral extensions are not permitted";
30 const char kLaunchAbortedError[] = "Launch aborted";
31
32 Profile* ProfileForWebContents(content::WebContents* contents) {
33   if (!contents)
34     return NULL;
35
36   return Profile::FromBrowserContext(contents->GetBrowserContext());
37 }
38
39 gfx::NativeWindow NativeWindowForWebContents(content::WebContents* contents) {
40   if (!contents)
41     return NULL;
42
43   return contents->GetView()->GetTopLevelNativeWindow();
44 }
45
46 }  // namespace
47
48 // static
49 scoped_refptr<EphemeralAppLauncher>
50 EphemeralAppLauncher::CreateForLauncher(
51     const std::string& webstore_item_id,
52     Profile* profile,
53     gfx::NativeWindow parent_window,
54     const Callback& callback) {
55   scoped_refptr<EphemeralAppLauncher> installer =
56       new EphemeralAppLauncher(webstore_item_id,
57                                profile,
58                                parent_window,
59                                callback);
60   installer->set_install_source(WebstoreInstaller::INSTALL_SOURCE_APP_LAUNCHER);
61   return installer;
62 }
63
64 // static
65 scoped_refptr<EphemeralAppLauncher>
66 EphemeralAppLauncher::CreateForLink(
67     const std::string& webstore_item_id,
68     content::WebContents* web_contents) {
69   scoped_refptr<EphemeralAppLauncher> installer =
70       new EphemeralAppLauncher(webstore_item_id,
71                                web_contents,
72                                Callback());
73   installer->set_install_source(WebstoreInstaller::INSTALL_SOURCE_OTHER);
74   return installer;
75 }
76
77 void EphemeralAppLauncher::Start() {
78   ExtensionService* extension_service =
79       extensions::ExtensionSystem::Get(profile())->extension_service();
80   DCHECK(extension_service);
81
82   const Extension* extension = extension_service->GetInstalledExtension(id());
83   if (extension) {
84     if (extensions::util::IsAppLaunchableWithoutEnabling(extension->id(),
85                                                          profile())) {
86       LaunchApp(extension);
87       InvokeCallback(std::string());
88       return;
89     }
90
91     // The ephemeral app may have been updated and disabled as it requests
92     // more permissions. In this case we should always prompt before
93     // launching.
94     extension_enable_flow_.reset(
95         new ExtensionEnableFlow(profile(), extension->id(), this));
96     if (web_contents())
97       extension_enable_flow_->StartForWebContents(web_contents());
98     else
99       extension_enable_flow_->StartForNativeWindow(parent_window_);
100
101     // Keep this object alive until the enable flow is complete.
102     AddRef();  // Balanced in WebstoreStandaloneInstaller::CompleteInstall.
103     return;
104   }
105
106   // Fetch the app from the webstore.
107   StartObserving();
108   BeginInstall();
109 }
110
111 EphemeralAppLauncher::EphemeralAppLauncher(
112     const std::string& webstore_item_id,
113     Profile* profile,
114     gfx::NativeWindow parent_window,
115     const Callback& callback)
116         : WebstoreStandaloneInstaller(
117               webstore_item_id,
118               profile,
119               callback),
120           parent_window_(parent_window),
121           dummy_web_contents_(
122               WebContents::Create(WebContents::CreateParams(profile))) {
123 }
124
125 EphemeralAppLauncher::EphemeralAppLauncher(
126     const std::string& webstore_item_id,
127     content::WebContents* web_contents,
128     const Callback& callback)
129         : WebstoreStandaloneInstaller(
130               webstore_item_id,
131               ProfileForWebContents(web_contents),
132               callback),
133           content::WebContentsObserver(web_contents),
134           parent_window_(NativeWindowForWebContents(web_contents)) {
135 }
136
137 EphemeralAppLauncher::~EphemeralAppLauncher() {}
138
139 void EphemeralAppLauncher::StartObserving() {
140   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
141                  content::Source<Profile>(profile()->GetOriginalProfile()));
142 }
143
144 void EphemeralAppLauncher::LaunchApp(const Extension* extension) const {
145   DCHECK(extension);
146   if (!extension->is_app()) {
147     LOG(ERROR) << "Unable to launch extension " << extension->id()
148                << ". It is not an app.";
149     return;
150   }
151
152   AppLaunchParams params(profile(), extension, NEW_FOREGROUND_TAB);
153   params.desktop_type =
154       chrome::GetHostDesktopTypeForNativeWindow(parent_window_);
155   OpenApplication(params);
156 }
157
158 bool EphemeralAppLauncher::CheckRequestorAlive() const {
159   return dummy_web_contents_.get() != NULL || web_contents() != NULL;
160 }
161
162 const GURL& EphemeralAppLauncher::GetRequestorURL() const {
163   return GURL::EmptyGURL();
164 }
165
166 bool EphemeralAppLauncher::ShouldShowPostInstallUI() const {
167   return false;
168 }
169
170 bool EphemeralAppLauncher::ShouldShowAppInstalledBubble() const {
171   return false;
172 }
173
174 WebContents* EphemeralAppLauncher::GetWebContents() const {
175   return web_contents() ? web_contents() : dummy_web_contents_.get();
176 }
177
178 scoped_ptr<ExtensionInstallPrompt::Prompt>
179 EphemeralAppLauncher::CreateInstallPrompt() const {
180   DCHECK(extension_.get() != NULL);
181
182   // Skip the prompt by returning null if the app does not need to display
183   // permission warnings.
184   extensions::PermissionMessages permissions =
185       extensions::PermissionsData::GetPermissionMessages(extension_.get());
186   if (permissions.empty())
187     return scoped_ptr<ExtensionInstallPrompt::Prompt>();
188
189   return make_scoped_ptr(new ExtensionInstallPrompt::Prompt(
190       ExtensionInstallPrompt::LAUNCH_PROMPT));
191 }
192
193 bool EphemeralAppLauncher::CheckInlineInstallPermitted(
194     const base::DictionaryValue& webstore_data,
195     std::string* error) const {
196   *error = "";
197   return true;
198 }
199
200 bool EphemeralAppLauncher::CheckRequestorPermitted(
201     const base::DictionaryValue& webstore_data,
202     std::string* error) const {
203   *error = "";
204   return true;
205 }
206
207 bool EphemeralAppLauncher::CheckInstallValid(
208     const base::DictionaryValue& manifest,
209     std::string* error) {
210   extension_ = Extension::Create(
211       base::FilePath(),
212       extensions::Manifest::INTERNAL,
213       manifest,
214       Extension::REQUIRE_KEY |
215           Extension::FROM_WEBSTORE |
216           Extension::IS_EPHEMERAL,
217       id(),
218       error);
219   if (!extension_.get()) {
220     *error = kInvalidManifestError;
221     return false;
222   }
223
224   if (!extension_->is_app()) {
225     *error = kExtensionTypeError;
226     return false;
227   }
228
229   return true;
230 }
231
232 scoped_ptr<ExtensionInstallPrompt>
233 EphemeralAppLauncher::CreateInstallUI() {
234   if (web_contents())
235     return make_scoped_ptr(new ExtensionInstallPrompt(web_contents()));
236
237   return make_scoped_ptr(
238       new ExtensionInstallPrompt(profile(), parent_window_, NULL));
239 }
240
241 scoped_ptr<WebstoreInstaller::Approval>
242 EphemeralAppLauncher::CreateApproval() const {
243   scoped_ptr<WebstoreInstaller::Approval> approval =
244       WebstoreStandaloneInstaller::CreateApproval();
245   approval->is_ephemeral = true;
246   return approval.Pass();
247 }
248
249 void EphemeralAppLauncher::CompleteInstall(const std::string& error) {
250   if (!error.empty())
251     WebstoreStandaloneInstaller::CompleteInstall(error);
252
253   // If the installation succeeds, we reach this point as a result of
254   // chrome::NOTIFICATION_EXTENSION_INSTALLED, but this is broadcasted before
255   // ExtensionService has added the extension to its list of installed
256   // extensions and is too early to launch the app. Instead, we will launch at
257   // chrome::NOTIFICATION_EXTENSION_LOADED.
258   // TODO(tmdiep): Refactor extensions/WebstoreInstaller or
259   // WebstoreStandaloneInstaller to support this cleanly.
260 }
261
262 void EphemeralAppLauncher::WebContentsDestroyed(
263     content::WebContents* web_contents) {
264   AbortInstall();
265 }
266
267 void EphemeralAppLauncher::Observe(
268     int type,
269     const content::NotificationSource& source,
270     const content::NotificationDetails& details) {
271   switch (type) {
272     case chrome::NOTIFICATION_EXTENSION_LOADED: {
273       const extensions::Extension* extension =
274           content::Details<const extensions::Extension>(details).ptr();
275       DCHECK(extension);
276       if (extension->id() == id()) {
277         LaunchApp(extension);
278         WebstoreStandaloneInstaller::CompleteInstall(std::string());
279       }
280       break;
281     }
282
283     default:
284       NOTREACHED();
285   }
286 }
287
288 void EphemeralAppLauncher::ExtensionEnableFlowFinished() {
289   ExtensionService* extension_service =
290       extensions::ExtensionSystem::Get(profile())->extension_service();
291   DCHECK(extension_service);
292
293   const Extension* extension = extension_service->GetExtensionById(id(), false);
294   if (extension) {
295     LaunchApp(extension);
296     WebstoreStandaloneInstaller::CompleteInstall(std::string());
297   } else {
298     WebstoreStandaloneInstaller::CompleteInstall(kLaunchAbortedError);
299   }
300 }
301
302 void EphemeralAppLauncher::ExtensionEnableFlowAborted(bool user_initiated) {
303   WebstoreStandaloneInstaller::CompleteInstall(kLaunchAbortedError);
304 }