OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/apps/ephemeral_app_launcher.h" | 5 #include "chrome/browser/apps/ephemeral_app_launcher.h" |
6 | 6 |
| 7 #include "base/command_line.h" |
| 8 #include "base/strings/utf_string_conversions.h" |
| 9 #include "chrome/browser/extensions/extension_install_checker.h" |
7 #include "chrome/browser/extensions/extension_install_prompt.h" | 10 #include "chrome/browser/extensions/extension_install_prompt.h" |
8 #include "chrome/browser/extensions/extension_util.h" | 11 #include "chrome/browser/extensions/extension_util.h" |
9 #include "chrome/browser/profiles/profile.h" | 12 #include "chrome/browser/profiles/profile.h" |
10 #include "chrome/browser/ui/extensions/application_launch.h" | 13 #include "chrome/browser/ui/extensions/application_launch.h" |
11 #include "chrome/browser/ui/extensions/extension_enable_flow.h" | 14 #include "chrome/browser/ui/extensions/extension_enable_flow.h" |
| 15 #include "chrome/common/chrome_switches.h" |
12 #include "content/public/browser/web_contents.h" | 16 #include "content/public/browser/web_contents.h" |
| 17 #include "extensions/browser/extension_prefs.h" |
13 #include "extensions/browser/extension_registry.h" | 18 #include "extensions/browser/extension_registry.h" |
| 19 #include "extensions/browser/extension_system.h" |
| 20 #include "extensions/browser/management_policy.h" |
14 #include "extensions/common/permissions/permissions_data.h" | 21 #include "extensions/common/permissions/permissions_data.h" |
15 | 22 |
16 using content::WebContents; | 23 using content::WebContents; |
17 using extensions::Extension; | 24 using extensions::Extension; |
| 25 using extensions::ExtensionInstallChecker; |
| 26 using extensions::ExtensionPrefs; |
18 using extensions::ExtensionRegistry; | 27 using extensions::ExtensionRegistry; |
| 28 using extensions::ExtensionSystem; |
| 29 using extensions::ManagementPolicy; |
19 using extensions::WebstoreInstaller; | 30 using extensions::WebstoreInstaller; |
20 | 31 |
21 namespace { | 32 namespace { |
22 | 33 |
23 const char kInvalidManifestError[] = "Invalid manifest"; | 34 const char kInvalidManifestError[] = "Invalid manifest"; |
24 const char kExtensionTypeError[] = "Ephemeral extensions are not permitted"; | 35 const char kExtensionTypeError[] = "Cannot launch an extension"; |
25 const char kLaunchAbortedError[] = "Launch aborted"; | 36 const char kUserCancelledError[] = "Launch cancelled by the user"; |
| 37 const char kBlacklistedError[] = "App is blacklisted for malware"; |
| 38 const char kDependenciesError[] = "App has missing requirements"; |
| 39 const char kFeatureDisabledError[] = "Launching ephemeral apps is not enabled"; |
| 40 const char kMissingAppError[] = "App is not installed"; |
| 41 const char kAppDisabledError[] = "App is disabled"; |
26 | 42 |
27 Profile* ProfileForWebContents(content::WebContents* contents) { | 43 Profile* ProfileForWebContents(content::WebContents* contents) { |
28 if (!contents) | 44 if (!contents) |
29 return NULL; | 45 return NULL; |
30 | 46 |
31 return Profile::FromBrowserContext(contents->GetBrowserContext()); | 47 return Profile::FromBrowserContext(contents->GetBrowserContext()); |
32 } | 48 } |
33 | 49 |
34 gfx::NativeWindow NativeWindowForWebContents(content::WebContents* contents) { | 50 gfx::NativeWindow NativeWindowForWebContents(content::WebContents* contents) { |
35 if (!contents) | 51 if (!contents) |
36 return NULL; | 52 return NULL; |
37 | 53 |
38 return contents->GetTopLevelNativeWindow(); | 54 return contents->GetTopLevelNativeWindow(); |
39 } | 55 } |
40 | 56 |
| 57 // Check whether an extension can be launched. The extension does not need to |
| 58 // be currently installed. |
| 59 bool CheckCommonLaunchCriteria(Profile* profile, |
| 60 const extensions::Extension* extension, |
| 61 EphemeralAppLauncher::LaunchResult* reason, |
| 62 std::string* error) { |
| 63 // Only apps can be launched. |
| 64 if (!extension->is_app()) { |
| 65 *reason = EphemeralAppLauncher::LAUNCH_UNSUPPORTED_EXTENSION_TYPE; |
| 66 *error = kExtensionTypeError; |
| 67 return false; |
| 68 } |
| 69 |
| 70 // Do not launch apps blocked by management policies. |
| 71 ManagementPolicy* management_policy = |
| 72 ExtensionSystem::Get(profile)->management_policy(); |
| 73 base::string16 policy_error; |
| 74 if (!management_policy->UserMayLoad(extension, &policy_error)) { |
| 75 *reason = EphemeralAppLauncher::LAUNCH_BLOCKED_BY_POLICY; |
| 76 *error = base::UTF16ToUTF8(policy_error); |
| 77 return false; |
| 78 } |
| 79 |
| 80 return true; |
| 81 } |
| 82 |
41 } // namespace | 83 } // namespace |
42 | 84 |
43 // static | 85 // static |
44 scoped_refptr<EphemeralAppLauncher> | 86 bool EphemeralAppLauncher::IsFeatureEnabled() { |
45 EphemeralAppLauncher::CreateForLauncher( | 87 return CommandLine::ForCurrentProcess()->HasSwitch( |
| 88 switches::kEnableEphemeralApps); |
| 89 } |
| 90 |
| 91 // static |
| 92 scoped_refptr<EphemeralAppLauncher> EphemeralAppLauncher::CreateForLauncher( |
46 const std::string& webstore_item_id, | 93 const std::string& webstore_item_id, |
47 Profile* profile, | 94 Profile* profile, |
48 gfx::NativeWindow parent_window, | 95 gfx::NativeWindow parent_window, |
49 const Callback& callback) { | 96 const LaunchCallback& callback) { |
50 scoped_refptr<EphemeralAppLauncher> installer = | 97 scoped_refptr<EphemeralAppLauncher> installer = |
51 new EphemeralAppLauncher(webstore_item_id, | 98 new EphemeralAppLauncher(webstore_item_id, |
52 profile, | 99 profile, |
53 parent_window, | 100 parent_window, |
54 callback); | 101 callback); |
55 installer->set_install_source(WebstoreInstaller::INSTALL_SOURCE_APP_LAUNCHER); | 102 installer->set_install_source(WebstoreInstaller::INSTALL_SOURCE_APP_LAUNCHER); |
56 return installer; | 103 return installer; |
57 } | 104 } |
58 | 105 |
59 // static | 106 // static |
60 scoped_refptr<EphemeralAppLauncher> | 107 scoped_refptr<EphemeralAppLauncher> EphemeralAppLauncher::CreateForWebContents( |
61 EphemeralAppLauncher::CreateForLink( | |
62 const std::string& webstore_item_id, | 108 const std::string& webstore_item_id, |
63 content::WebContents* web_contents) { | 109 content::WebContents* web_contents, |
| 110 const LaunchCallback& callback) { |
64 scoped_refptr<EphemeralAppLauncher> installer = | 111 scoped_refptr<EphemeralAppLauncher> installer = |
65 new EphemeralAppLauncher(webstore_item_id, | 112 new EphemeralAppLauncher(webstore_item_id, web_contents, callback); |
66 web_contents, | |
67 Callback()); | |
68 installer->set_install_source(WebstoreInstaller::INSTALL_SOURCE_OTHER); | 113 installer->set_install_source(WebstoreInstaller::INSTALL_SOURCE_OTHER); |
69 return installer; | 114 return installer; |
70 } | 115 } |
71 | 116 |
72 void EphemeralAppLauncher::Start() { | 117 void EphemeralAppLauncher::Start() { |
| 118 if (!IsFeatureEnabled()) { |
| 119 InvokeCallback(LAUNCH_FEATURE_DISABLED, kFeatureDisabledError); |
| 120 return; |
| 121 } |
| 122 |
| 123 // Check whether the app already exists in extension system before downloading |
| 124 // from the webstore. |
73 const Extension* extension = | 125 const Extension* extension = |
74 ExtensionRegistry::Get(profile()) | 126 ExtensionRegistry::Get(profile()) |
75 ->GetExtensionById(id(), ExtensionRegistry::EVERYTHING); | 127 ->GetExtensionById(id(), ExtensionRegistry::EVERYTHING); |
76 if (extension) { | 128 if (extension) { |
| 129 LaunchResult result = LAUNCH_UNKNOWN_ERROR; |
| 130 std::string error; |
| 131 if (!CanLaunchInstalledApp(extension, &result, &error)) { |
| 132 InvokeCallback(result, error); |
| 133 return; |
| 134 } |
| 135 |
77 if (extensions::util::IsAppLaunchableWithoutEnabling(extension->id(), | 136 if (extensions::util::IsAppLaunchableWithoutEnabling(extension->id(), |
78 profile())) { | 137 profile())) { |
79 LaunchApp(extension); | 138 LaunchApp(extension); |
80 InvokeCallback(std::string()); | 139 InvokeCallback(LAUNCH_SUCCESS, std::string()); |
81 return; | 140 return; |
82 } | 141 } |
83 | 142 |
84 // The ephemeral app may have been updated and disabled as it requests | 143 EnableInstalledApp(extension); |
85 // more permissions. In this case we should always prompt before | |
86 // launching. | |
87 extension_enable_flow_.reset( | |
88 new ExtensionEnableFlow(profile(), extension->id(), this)); | |
89 if (web_contents()) | |
90 extension_enable_flow_->StartForWebContents(web_contents()); | |
91 else | |
92 extension_enable_flow_->StartForNativeWindow(parent_window_); | |
93 | |
94 // Keep this object alive until the enable flow is complete. | |
95 AddRef(); // Balanced in WebstoreStandaloneInstaller::CompleteInstall. | |
96 return; | 144 return; |
97 } | 145 } |
98 | 146 |
99 // Fetch the app from the webstore. | 147 // Install the app ephemerally and launch when complete. |
100 BeginInstall(); | 148 BeginInstall(); |
101 } | 149 } |
102 | 150 |
103 EphemeralAppLauncher::EphemeralAppLauncher(const std::string& webstore_item_id, | 151 EphemeralAppLauncher::EphemeralAppLauncher(const std::string& webstore_item_id, |
104 Profile* profile, | 152 Profile* profile, |
105 gfx::NativeWindow parent_window, | 153 gfx::NativeWindow parent_window, |
106 const Callback& callback) | 154 const LaunchCallback& callback) |
107 : WebstoreStandaloneInstaller(webstore_item_id, profile, callback), | 155 : WebstoreStandaloneInstaller(webstore_item_id, profile, Callback()), |
| 156 launch_callback_(callback), |
108 parent_window_(parent_window), | 157 parent_window_(parent_window), |
109 dummy_web_contents_( | 158 dummy_web_contents_( |
110 WebContents::Create(WebContents::CreateParams(profile))) { | 159 WebContents::Create(WebContents::CreateParams(profile))) { |
111 } | 160 } |
112 | 161 |
113 EphemeralAppLauncher::EphemeralAppLauncher(const std::string& webstore_item_id, | 162 EphemeralAppLauncher::EphemeralAppLauncher(const std::string& webstore_item_id, |
114 content::WebContents* web_contents, | 163 content::WebContents* web_contents, |
115 const Callback& callback) | 164 const LaunchCallback& callback) |
116 : WebstoreStandaloneInstaller(webstore_item_id, | 165 : WebstoreStandaloneInstaller(webstore_item_id, |
117 ProfileForWebContents(web_contents), | 166 ProfileForWebContents(web_contents), |
118 callback), | 167 Callback()), |
119 content::WebContentsObserver(web_contents), | 168 content::WebContentsObserver(web_contents), |
| 169 launch_callback_(callback), |
120 parent_window_(NativeWindowForWebContents(web_contents)) { | 170 parent_window_(NativeWindowForWebContents(web_contents)) { |
121 } | 171 } |
122 | 172 |
123 EphemeralAppLauncher::~EphemeralAppLauncher() {} | 173 EphemeralAppLauncher::~EphemeralAppLauncher() {} |
124 | 174 |
| 175 bool EphemeralAppLauncher::CanLaunchInstalledApp( |
| 176 const extensions::Extension* extension, |
| 177 LaunchResult* reason, |
| 178 std::string* error) { |
| 179 if (!CheckCommonLaunchCriteria(profile(), extension, reason, error)) |
| 180 return false; |
| 181 |
| 182 // Do not launch blacklisted apps. |
| 183 if (ExtensionPrefs::Get(profile())->IsExtensionBlacklisted(extension->id())) { |
| 184 *reason = LAUNCH_BLACKLISTED; |
| 185 *error = kBlacklistedError; |
| 186 return false; |
| 187 } |
| 188 |
| 189 // If the app has missing requirements, it cannot be launched. |
| 190 if (!extensions::util::IsAppLaunchable(extension->id(), profile())) { |
| 191 *reason = LAUNCH_MISSING_DEPENDENCIES; |
| 192 *error = kDependenciesError; |
| 193 return false; |
| 194 } |
| 195 |
| 196 return true; |
| 197 } |
| 198 |
| 199 void EphemeralAppLauncher::EnableInstalledApp(const Extension* extension) { |
| 200 extension_enable_flow_.reset( |
| 201 new ExtensionEnableFlow(profile(), extension->id(), this)); |
| 202 if (web_contents()) |
| 203 extension_enable_flow_->StartForWebContents(web_contents()); |
| 204 else |
| 205 extension_enable_flow_->StartForNativeWindow(parent_window_); |
| 206 |
| 207 // Keep this object alive until the enable flow is complete. Either |
| 208 // ExtensionEnableFlowFinished() or ExtensionEnableFlowAborted() will be |
| 209 // called. |
| 210 AddRef(); |
| 211 } |
| 212 |
| 213 void EphemeralAppLauncher::MaybeLaunchApp() { |
| 214 LaunchResult result = LAUNCH_UNKNOWN_ERROR; |
| 215 std::string error; |
| 216 |
| 217 ExtensionRegistry* registry = ExtensionRegistry::Get(profile()); |
| 218 const Extension* extension = |
| 219 registry->GetExtensionById(id(), ExtensionRegistry::EVERYTHING); |
| 220 if (extension) { |
| 221 // Although the installation was successful, the app may not be |
| 222 // launchable. |
| 223 if (registry->enabled_extensions().Contains(extension->id())) { |
| 224 result = LAUNCH_SUCCESS; |
| 225 LaunchApp(extension); |
| 226 } else { |
| 227 error = kAppDisabledError; |
| 228 // Determine why the app cannot be launched. |
| 229 CanLaunchInstalledApp(extension, &result, &error); |
| 230 } |
| 231 } else { |
| 232 // The extension must be present in the registry if installed. |
| 233 NOTREACHED(); |
| 234 error = kMissingAppError; |
| 235 } |
| 236 |
| 237 InvokeCallback(result, error); |
| 238 } |
| 239 |
125 void EphemeralAppLauncher::LaunchApp(const Extension* extension) const { | 240 void EphemeralAppLauncher::LaunchApp(const Extension* extension) const { |
126 DCHECK(extension); | 241 DCHECK(extension && extension->is_app() && |
127 if (!extension->is_app()) { | 242 ExtensionRegistry::Get(profile()) |
128 LOG(ERROR) << "Unable to launch extension " << extension->id() | 243 ->GetExtensionById(extension->id(), ExtensionRegistry::ENABLED)); |
129 << ". It is not an app."; | |
130 return; | |
131 } | |
132 | 244 |
133 AppLaunchParams params(profile(), extension, NEW_FOREGROUND_TAB); | 245 AppLaunchParams params(profile(), extension, NEW_FOREGROUND_TAB); |
134 params.desktop_type = | 246 params.desktop_type = |
135 chrome::GetHostDesktopTypeForNativeWindow(parent_window_); | 247 chrome::GetHostDesktopTypeForNativeWindow(parent_window_); |
136 OpenApplication(params); | 248 OpenApplication(params); |
137 } | 249 } |
138 | 250 |
| 251 void EphemeralAppLauncher::InvokeCallback(LaunchResult result, |
| 252 const std::string& error) { |
| 253 if (!launch_callback_.is_null()) { |
| 254 launch_callback_.Run(result, error); |
| 255 launch_callback_.Reset(); |
| 256 } |
| 257 } |
| 258 |
| 259 void EphemeralAppLauncher::AbortLaunch(LaunchResult result, |
| 260 const std::string& error) { |
| 261 InvokeCallback(result, error); |
| 262 WebstoreStandaloneInstaller::CompleteInstall(INSTALL_ABORTED, std::string()); |
| 263 } |
| 264 |
| 265 scoped_ptr<extensions::ExtensionInstallChecker> |
| 266 EphemeralAppLauncher::CreateInstallChecker() { |
| 267 return make_scoped_ptr(new ExtensionInstallChecker(profile())); |
| 268 } |
| 269 |
| 270 void EphemeralAppLauncher::CheckEphemeralInstallPermitted() { |
| 271 scoped_refptr<const Extension> extension = GetLocalizedExtensionForDisplay(); |
| 272 DCHECK(extension.get()); // Checked in OnManifestParsed(). |
| 273 |
| 274 install_checker_ = CreateInstallChecker(); |
| 275 DCHECK(install_checker_.get()); |
| 276 |
| 277 install_checker_->set_extension(extension); |
| 278 install_checker_->Start(ExtensionInstallChecker::CHECK_BLACKLIST | |
| 279 ExtensionInstallChecker::CHECK_REQUIREMENTS, |
| 280 true, |
| 281 base::Bind(&EphemeralAppLauncher::OnInstallChecked, |
| 282 base::Unretained(this))); |
| 283 } |
| 284 |
| 285 void EphemeralAppLauncher::OnInstallChecked(int check_failures) { |
| 286 if (!CheckRequestorAlive()) { |
| 287 AbortLaunch(LAUNCH_UNKNOWN_ERROR, std::string()); |
| 288 return; |
| 289 } |
| 290 |
| 291 if (install_checker_->blacklist_state() == extensions::BLACKLISTED_MALWARE) { |
| 292 AbortLaunch(LAUNCH_BLACKLISTED, kBlacklistedError); |
| 293 return; |
| 294 } |
| 295 |
| 296 if (!install_checker_->requirement_errors().empty()) { |
| 297 AbortLaunch(LAUNCH_MISSING_DEPENDENCIES, |
| 298 install_checker_->requirement_errors().front()); |
| 299 return; |
| 300 } |
| 301 |
| 302 // Proceed with the normal install flow. |
| 303 ProceedWithInstallPrompt(); |
| 304 } |
| 305 |
139 bool EphemeralAppLauncher::CheckRequestorAlive() const { | 306 bool EphemeralAppLauncher::CheckRequestorAlive() const { |
140 return dummy_web_contents_.get() != NULL || web_contents() != NULL; | 307 return dummy_web_contents_.get() != NULL || web_contents() != NULL; |
141 } | 308 } |
142 | 309 |
143 const GURL& EphemeralAppLauncher::GetRequestorURL() const { | 310 const GURL& EphemeralAppLauncher::GetRequestorURL() const { |
144 return GURL::EmptyGURL(); | 311 return GURL::EmptyGURL(); |
145 } | 312 } |
146 | 313 |
147 bool EphemeralAppLauncher::ShouldShowPostInstallUI() const { | 314 bool EphemeralAppLauncher::ShouldShowPostInstallUI() const { |
148 return false; | 315 return false; |
149 } | 316 } |
150 | 317 |
151 bool EphemeralAppLauncher::ShouldShowAppInstalledBubble() const { | 318 bool EphemeralAppLauncher::ShouldShowAppInstalledBubble() const { |
152 return false; | 319 return false; |
153 } | 320 } |
154 | 321 |
155 WebContents* EphemeralAppLauncher::GetWebContents() const { | 322 WebContents* EphemeralAppLauncher::GetWebContents() const { |
156 return web_contents() ? web_contents() : dummy_web_contents_.get(); | 323 return web_contents() ? web_contents() : dummy_web_contents_.get(); |
157 } | 324 } |
158 | 325 |
159 scoped_ptr<ExtensionInstallPrompt::Prompt> | 326 scoped_ptr<ExtensionInstallPrompt::Prompt> |
160 EphemeralAppLauncher::CreateInstallPrompt() const { | 327 EphemeralAppLauncher::CreateInstallPrompt() const { |
161 DCHECK(extension_.get() != NULL); | 328 const Extension* extension = localized_extension_for_display(); |
| 329 DCHECK(extension); // Checked in OnManifestParsed(). |
162 | 330 |
163 // Skip the prompt by returning null if the app does not need to display | 331 // Skip the prompt by returning null if the app does not need to display |
164 // permission warnings. | 332 // permission warnings. |
165 extensions::PermissionMessages permissions = | 333 extensions::PermissionMessages permissions = |
166 extension_->permissions_data()->GetPermissionMessages(); | 334 extension->permissions_data()->GetPermissionMessages(); |
167 if (permissions.empty()) | 335 if (permissions.empty()) |
168 return scoped_ptr<ExtensionInstallPrompt::Prompt>(); | 336 return scoped_ptr<ExtensionInstallPrompt::Prompt>(); |
169 | 337 |
170 return make_scoped_ptr(new ExtensionInstallPrompt::Prompt( | 338 return make_scoped_ptr(new ExtensionInstallPrompt::Prompt( |
171 ExtensionInstallPrompt::LAUNCH_PROMPT)); | 339 ExtensionInstallPrompt::LAUNCH_PROMPT)); |
172 } | 340 } |
173 | 341 |
174 bool EphemeralAppLauncher::CheckInlineInstallPermitted( | 342 bool EphemeralAppLauncher::CheckInlineInstallPermitted( |
175 const base::DictionaryValue& webstore_data, | 343 const base::DictionaryValue& webstore_data, |
176 std::string* error) const { | 344 std::string* error) const { |
177 *error = ""; | 345 *error = ""; |
178 return true; | 346 return true; |
179 } | 347 } |
180 | 348 |
181 bool EphemeralAppLauncher::CheckRequestorPermitted( | 349 bool EphemeralAppLauncher::CheckRequestorPermitted( |
182 const base::DictionaryValue& webstore_data, | 350 const base::DictionaryValue& webstore_data, |
183 std::string* error) const { | 351 std::string* error) const { |
184 *error = ""; | 352 *error = ""; |
185 return true; | 353 return true; |
186 } | 354 } |
187 | 355 |
188 bool EphemeralAppLauncher::CheckInstallValid( | 356 void EphemeralAppLauncher::OnManifestParsed() { |
189 const base::DictionaryValue& manifest, | 357 const Extension* extension = GetLocalizedExtensionForDisplay(); |
190 std::string* error) { | 358 if (!extension) { |
191 extension_ = Extension::Create( | 359 AbortLaunch(LAUNCH_INVALID_MANIFEST, kInvalidManifestError); |
192 base::FilePath(), | 360 return; |
193 extensions::Manifest::INTERNAL, | |
194 manifest, | |
195 Extension::REQUIRE_KEY | Extension::FROM_WEBSTORE, | |
196 id(), | |
197 error); | |
198 if (!extension_.get()) { | |
199 *error = kInvalidManifestError; | |
200 return false; | |
201 } | 361 } |
202 | 362 |
203 if (!extension_->is_app()) { | 363 LaunchResult result = LAUNCH_UNKNOWN_ERROR; |
204 *error = kExtensionTypeError; | 364 std::string error; |
205 return false; | 365 if (!CheckCommonLaunchCriteria(profile(), extension, &result, &error)) { |
| 366 AbortLaunch(result, error); |
| 367 return; |
206 } | 368 } |
207 | 369 |
208 return true; | 370 CheckEphemeralInstallPermitted(); |
209 } | 371 } |
210 | 372 |
211 scoped_ptr<ExtensionInstallPrompt> | 373 scoped_ptr<ExtensionInstallPrompt> EphemeralAppLauncher::CreateInstallUI() { |
212 EphemeralAppLauncher::CreateInstallUI() { | |
213 if (web_contents()) | 374 if (web_contents()) |
214 return make_scoped_ptr(new ExtensionInstallPrompt(web_contents())); | 375 return make_scoped_ptr(new ExtensionInstallPrompt(web_contents())); |
215 | 376 |
216 return make_scoped_ptr( | 377 return make_scoped_ptr( |
217 new ExtensionInstallPrompt(profile(), parent_window_, NULL)); | 378 new ExtensionInstallPrompt(profile(), parent_window_, NULL)); |
218 } | 379 } |
219 | 380 |
220 scoped_ptr<WebstoreInstaller::Approval> | 381 scoped_ptr<WebstoreInstaller::Approval> |
221 EphemeralAppLauncher::CreateApproval() const { | 382 EphemeralAppLauncher::CreateApproval() const { |
222 scoped_ptr<WebstoreInstaller::Approval> approval = | 383 scoped_ptr<WebstoreInstaller::Approval> approval = |
223 WebstoreStandaloneInstaller::CreateApproval(); | 384 WebstoreStandaloneInstaller::CreateApproval(); |
224 approval->is_ephemeral = true; | 385 approval->is_ephemeral = true; |
225 return approval.Pass(); | 386 return approval.Pass(); |
226 } | 387 } |
227 | 388 |
228 void EphemeralAppLauncher::CompleteInstall(const std::string& error) { | 389 void EphemeralAppLauncher::CompleteInstall(InstallResult result, |
229 if (error.empty()) { | 390 const std::string& error) { |
230 const Extension* extension = | 391 if (result == INSTALL_SUCCESS) { |
231 ExtensionRegistry::Get(profile()) | 392 MaybeLaunchApp(); |
232 ->GetExtensionById(id(), ExtensionRegistry::ENABLED); | 393 } else if (!launch_callback_.is_null()) { |
233 if (extension) | 394 // Convert the install error codes to launch error codes. |
234 LaunchApp(extension); | 395 LaunchResult launch_result = LAUNCH_UNKNOWN_ERROR; |
| 396 switch (result) { |
| 397 case INSTALL_USER_CANCELLED: |
| 398 launch_result = LAUNCH_USER_CANCELLED; |
| 399 break; |
| 400 case INSTALL_INVALID_ID: |
| 401 launch_result = LAUNCH_INVALID_ID; |
| 402 break; |
| 403 case INSTALL_INVALID_MANIFEST: |
| 404 launch_result = LAUNCH_INVALID_MANIFEST; |
| 405 break; |
| 406 case INSTALL_NOT_PERMITTED: |
| 407 case INSTALL_WEBSTORE_REQUEST_ERROR: |
| 408 case INSTALL_INVALID_WEBSTORE_RESPONSE: |
| 409 case INSTALL_ICON_ERROR: |
| 410 launch_result = LAUNCH_INSTALL_ERROR; |
| 411 break; |
| 412 case INSTALL_BLACKLISTED: |
| 413 launch_result = LAUNCH_BLACKLISTED; |
| 414 break; |
| 415 case INSTALL_MISSING_DEPENDENCIES: |
| 416 launch_result = LAUNCH_MISSING_DEPENDENCIES; |
| 417 break; |
| 418 default: |
| 419 break; |
| 420 } |
| 421 |
| 422 InvokeCallback(launch_result, error); |
235 } | 423 } |
236 | 424 |
237 WebstoreStandaloneInstaller::CompleteInstall(error); | 425 WebstoreStandaloneInstaller::CompleteInstall(result, error); |
238 } | 426 } |
239 | 427 |
240 void EphemeralAppLauncher::WebContentsDestroyed() { | 428 void EphemeralAppLauncher::WebContentsDestroyed() { |
| 429 launch_callback_.Reset(); |
241 AbortInstall(); | 430 AbortInstall(); |
242 } | 431 } |
243 | 432 |
244 void EphemeralAppLauncher::ExtensionEnableFlowFinished() { | 433 void EphemeralAppLauncher::ExtensionEnableFlowFinished() { |
245 CompleteInstall(std::string()); | 434 MaybeLaunchApp(); |
| 435 Release(); // Matches the AddRef in EnableInstalledApp(). |
246 } | 436 } |
247 | 437 |
248 void EphemeralAppLauncher::ExtensionEnableFlowAborted(bool user_initiated) { | 438 void EphemeralAppLauncher::ExtensionEnableFlowAborted(bool user_initiated) { |
249 CompleteInstall(kLaunchAbortedError); | 439 InvokeCallback(LAUNCH_USER_CANCELLED, kUserCancelledError); |
| 440 Release(); // Matches the AddRef in EnableInstalledApp(). |
250 } | 441 } |
OLD | NEW |