| 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 |