[Metrics] Make MetricsStateManager take a callback param to check if UMA is enabled.
[chromium-blink-merge.git] / chrome / browser / apps / ephemeral_app_launcher.cc
blobd0f4c70605d6646142021d2519bf6fc0a98287c3
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.
5 #include "chrome/browser/apps/ephemeral_app_launcher.h"
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"
18 using content::WebContents;
19 using extensions::Extension;
20 using extensions::ExtensionSystem;
21 using extensions::WebstoreInstaller;
23 namespace {
25 const char kInvalidManifestError[] = "Invalid manifest";
26 const char kExtensionTypeError[] = "Ephemeral extensions are not permitted";
27 const char kLaunchAbortedError[] = "Launch aborted";
29 Profile* ProfileForWebContents(content::WebContents* contents) {
30 if (!contents)
31 return NULL;
33 return Profile::FromBrowserContext(contents->GetBrowserContext());
36 gfx::NativeWindow NativeWindowForWebContents(content::WebContents* contents) {
37 if (!contents)
38 return NULL;
40 return contents->GetTopLevelNativeWindow();
43 } // namespace
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;
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;
74 void EphemeralAppLauncher::Start() {
75 ExtensionService* extension_service =
76 extensions::ExtensionSystem::Get(profile())->extension_service();
77 DCHECK(extension_service);
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;
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_);
98 // Keep this object alive until the enable flow is complete.
99 AddRef(); // Balanced in WebstoreStandaloneInstaller::CompleteInstall.
100 return;
103 // Fetch the app from the webstore.
104 StartObserving();
105 BeginInstall();
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))) {
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)) {
130 EphemeralAppLauncher::~EphemeralAppLauncher() {}
132 void EphemeralAppLauncher::StartObserving() {
133 extension_registry_observer_.Add(
134 extensions::ExtensionRegistry::Get(profile()));
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;
145 AppLaunchParams params(profile(), extension, NEW_FOREGROUND_TAB);
146 params.desktop_type =
147 chrome::GetHostDesktopTypeForNativeWindow(parent_window_);
148 OpenApplication(params);
151 bool EphemeralAppLauncher::CheckRequestorAlive() const {
152 return dummy_web_contents_.get() != NULL || web_contents() != NULL;
155 const GURL& EphemeralAppLauncher::GetRequestorURL() const {
156 return GURL::EmptyGURL();
159 bool EphemeralAppLauncher::ShouldShowPostInstallUI() const {
160 return false;
163 bool EphemeralAppLauncher::ShouldShowAppInstalledBubble() const {
164 return false;
167 WebContents* EphemeralAppLauncher::GetWebContents() const {
168 return web_contents() ? web_contents() : dummy_web_contents_.get();
171 scoped_ptr<ExtensionInstallPrompt::Prompt>
172 EphemeralAppLauncher::CreateInstallPrompt() const {
173 DCHECK(extension_.get() != NULL);
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>();
182 return make_scoped_ptr(new ExtensionInstallPrompt::Prompt(
183 ExtensionInstallPrompt::LAUNCH_PROMPT));
186 bool EphemeralAppLauncher::CheckInlineInstallPermitted(
187 const base::DictionaryValue& webstore_data,
188 std::string* error) const {
189 *error = "";
190 return true;
193 bool EphemeralAppLauncher::CheckRequestorPermitted(
194 const base::DictionaryValue& webstore_data,
195 std::string* error) const {
196 *error = "";
197 return true;
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;
217 if (!extension_->is_app()) {
218 *error = kExtensionTypeError;
219 return false;
222 return true;
225 scoped_ptr<ExtensionInstallPrompt>
226 EphemeralAppLauncher::CreateInstallUI() {
227 if (web_contents())
228 return make_scoped_ptr(new ExtensionInstallPrompt(web_contents()));
230 return make_scoped_ptr(
231 new ExtensionInstallPrompt(profile(), parent_window_, NULL));
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();
242 void EphemeralAppLauncher::CompleteInstall(const std::string& error) {
243 if (!error.empty())
244 WebstoreStandaloneInstaller::CompleteInstall(error);
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.
255 void EphemeralAppLauncher::WebContentsDestroyed() {
256 AbortInstall();
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());
268 void EphemeralAppLauncher::ExtensionEnableFlowFinished() {
269 ExtensionService* extension_service =
270 extensions::ExtensionSystem::Get(profile())->extension_service();
271 DCHECK(extension_service);
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);
282 void EphemeralAppLauncher::ExtensionEnableFlowAborted(bool user_initiated) {
283 WebstoreStandaloneInstaller::CompleteInstall(kLaunchAbortedError);