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