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