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