OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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. | |
4 | |
5 #include "chrome/browser/extensions/external_install_ui.h" | |
6 | |
7 #include <string> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/lazy_instance.h" | |
11 #include "base/memory/ref_counted.h" | |
12 #include "base/memory/scoped_ptr.h" | |
13 #include "base/message_loop/message_loop.h" | |
14 #include "base/metrics/histogram.h" | |
15 #include "base/scoped_observer.h" | |
16 #include "base/strings/utf_string_conversions.h" | |
17 #include "chrome/app/chrome_command_ids.h" | |
18 #include "chrome/browser/chrome_notification_types.h" | |
19 #include "chrome/browser/extensions/extension_install_prompt.h" | |
20 #include "chrome/browser/extensions/extension_install_ui.h" | |
21 #include "chrome/browser/extensions/extension_service.h" | |
22 #include "chrome/browser/extensions/extension_uninstall_dialog.h" | |
23 #include "chrome/browser/extensions/webstore_data_fetcher.h" | |
24 #include "chrome/browser/extensions/webstore_data_fetcher_delegate.h" | |
25 #include "chrome/browser/profiles/profile.h" | |
26 #include "chrome/browser/ui/browser.h" | |
27 #include "chrome/browser/ui/browser_finder.h" | |
28 #include "chrome/browser/ui/global_error/global_error.h" | |
29 #include "chrome/browser/ui/global_error/global_error_service.h" | |
30 #include "chrome/browser/ui/global_error/global_error_service_factory.h" | |
31 #include "chrome/common/extensions/manifest_url_handler.h" | |
32 #include "content/public/browser/notification_details.h" | |
33 #include "content/public/browser/notification_observer.h" | |
34 #include "content/public/browser/notification_registrar.h" | |
35 #include "content/public/browser/notification_source.h" | |
36 #include "extensions/browser/extension_registry.h" | |
37 #include "extensions/browser/extension_registry_observer.h" | |
38 #include "grit/generated_resources.h" | |
39 #include "ui/base/l10n/l10n_util.h" | |
40 #include "ui/gfx/image/image.h" | |
41 #include "ui/gfx/image/image_skia_operations.h" | |
42 | |
43 namespace extensions { | |
44 | |
45 namespace { | |
46 | |
47 // Whether the external extension can use the streamlined bubble install flow. | |
48 bool UseBubbleInstall(const Extension* extension, bool is_new_profile) { | |
49 return ManifestURL::UpdatesFromGallery(extension) && !is_new_profile; | |
50 } | |
51 | |
52 } // namespace | |
53 | |
54 static const int kMenuCommandId = IDC_EXTERNAL_EXTENSION_ALERT; | |
55 | |
56 class ExternalInstallGlobalError; | |
57 | |
58 namespace extensions { | |
59 class ExtensionRegistry; | |
60 } | |
61 | |
62 // This class is refcounted to stay alive while we try and pull webstore data. | |
63 class ExternalInstallDialogDelegate | |
64 : public ExtensionInstallPrompt::Delegate, | |
65 public WebstoreDataFetcherDelegate, | |
66 public content::NotificationObserver, | |
67 public base::RefCountedThreadSafe<ExternalInstallDialogDelegate> { | |
68 public: | |
69 ExternalInstallDialogDelegate(Browser* browser, | |
70 ExtensionService* service, | |
71 const Extension* extension, | |
72 bool use_global_error); | |
73 | |
74 Browser* browser() { return browser_; } | |
75 | |
76 private: | |
77 friend class base::RefCountedThreadSafe<ExternalInstallDialogDelegate>; | |
78 friend class ExternalInstallGlobalError; | |
79 | |
80 virtual ~ExternalInstallDialogDelegate(); | |
81 | |
82 // ExtensionInstallPrompt::Delegate: | |
83 virtual void InstallUIProceed() OVERRIDE; | |
84 virtual void InstallUIAbort(bool user_initiated) OVERRIDE; | |
85 | |
86 // WebstoreDataFetcherDelegate: | |
87 virtual void OnWebstoreRequestFailure() OVERRIDE; | |
88 virtual void OnWebstoreResponseParseSuccess( | |
89 scoped_ptr<base::DictionaryValue> webstore_data) OVERRIDE; | |
90 virtual void OnWebstoreResponseParseFailure( | |
91 const std::string& error) OVERRIDE; | |
92 | |
93 // content::NotificationObserver: | |
94 virtual void Observe(int type, | |
95 const content::NotificationSource& source, | |
96 const content::NotificationDetails& details) OVERRIDE; | |
97 | |
98 // Show the install dialog to the user. | |
99 void ShowInstallUI(); | |
100 | |
101 // The UI for showing the install dialog when enabling. | |
102 scoped_ptr<ExtensionInstallPrompt> install_ui_; | |
103 scoped_ptr<ExtensionInstallPrompt::Prompt> prompt_; | |
104 | |
105 Browser* browser_; | |
106 base::WeakPtr<ExtensionService> service_weak_; | |
107 scoped_ptr<WebstoreDataFetcher> webstore_data_fetcher_; | |
108 content::NotificationRegistrar registrar_; | |
109 std::string extension_id_; | |
110 bool use_global_error_; | |
111 | |
112 DISALLOW_COPY_AND_ASSIGN(ExternalInstallDialogDelegate); | |
113 }; | |
114 | |
115 // Only shows a menu item, no bubble. Clicking the menu item shows | |
116 // an external install dialog. | |
117 class ExternalInstallMenuAlert : public GlobalErrorWithStandardBubble, | |
118 public content::NotificationObserver, | |
119 public ExtensionRegistryObserver { | |
120 public: | |
121 ExternalInstallMenuAlert(ExtensionService* service, | |
122 const Extension* extension); | |
123 virtual ~ExternalInstallMenuAlert(); | |
124 | |
125 // GlobalError implementation. | |
126 virtual Severity GetSeverity() OVERRIDE; | |
127 virtual bool HasMenuItem() OVERRIDE; | |
128 virtual int MenuItemCommandID() OVERRIDE; | |
129 virtual base::string16 MenuItemLabel() OVERRIDE; | |
130 virtual void ExecuteMenuItem(Browser* browser) OVERRIDE; | |
131 virtual bool HasBubbleView() OVERRIDE; | |
132 virtual base::string16 GetBubbleViewTitle() OVERRIDE; | |
133 virtual std::vector<base::string16> GetBubbleViewMessages() OVERRIDE; | |
134 virtual base::string16 GetBubbleViewAcceptButtonLabel() OVERRIDE; | |
135 virtual base::string16 GetBubbleViewCancelButtonLabel() OVERRIDE; | |
136 virtual void OnBubbleViewDidClose(Browser* browser) OVERRIDE; | |
137 virtual void BubbleViewAcceptButtonPressed(Browser* browser) OVERRIDE; | |
138 virtual void BubbleViewCancelButtonPressed(Browser* browser) OVERRIDE; | |
139 | |
140 protected: | |
141 ExtensionService* service_; | |
142 const Extension* extension_; | |
143 | |
144 private: | |
145 // Delete this instance after cleaning jobs. | |
146 void Clean(); | |
147 | |
148 // content::NotificationObserver implementation. | |
149 virtual void Observe(int type, | |
150 const content::NotificationSource& source, | |
151 const content::NotificationDetails& details) OVERRIDE; | |
152 | |
153 // ExtensionRegistryObserver implementation. | |
154 virtual void OnExtensionLoaded(content::BrowserContext* browser_context, | |
155 const Extension* extension) OVERRIDE; | |
156 | |
157 content::NotificationRegistrar registrar_; | |
158 | |
159 // Listen to extension load notifications. | |
160 ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver> | |
161 extension_registry_observer_; | |
162 | |
163 DISALLOW_COPY_AND_ASSIGN(ExternalInstallMenuAlert); | |
164 }; | |
165 | |
166 // Shows a menu item and a global error bubble, replacing the install dialog. | |
167 class ExternalInstallGlobalError : public ExternalInstallMenuAlert { | |
168 public: | |
169 ExternalInstallGlobalError(ExtensionService* service, | |
170 const Extension* extension, | |
171 ExternalInstallDialogDelegate* delegate, | |
172 const ExtensionInstallPrompt::Prompt& prompt); | |
173 virtual ~ExternalInstallGlobalError(); | |
174 | |
175 virtual void ExecuteMenuItem(Browser* browser) OVERRIDE; | |
176 virtual bool HasBubbleView() OVERRIDE; | |
177 virtual gfx::Image GetBubbleViewIcon() OVERRIDE; | |
178 virtual base::string16 GetBubbleViewTitle() OVERRIDE; | |
179 virtual std::vector<base::string16> GetBubbleViewMessages() OVERRIDE; | |
180 virtual base::string16 GetBubbleViewAcceptButtonLabel() OVERRIDE; | |
181 virtual base::string16 GetBubbleViewCancelButtonLabel() OVERRIDE; | |
182 virtual void OnBubbleViewDidClose(Browser* browser) OVERRIDE; | |
183 virtual void BubbleViewAcceptButtonPressed(Browser* browser) OVERRIDE; | |
184 virtual void BubbleViewCancelButtonPressed(Browser* browser) OVERRIDE; | |
185 | |
186 protected: | |
187 // Ref-counted, but needs to be disposed of if we are dismissed without | |
188 // having been clicked (perhaps because the user enabled the extension | |
189 // manually). | |
190 ExternalInstallDialogDelegate* delegate_; | |
191 const ExtensionInstallPrompt::Prompt* prompt_; | |
192 | |
193 private: | |
194 DISALLOW_COPY_AND_ASSIGN(ExternalInstallGlobalError); | |
195 }; | |
196 | |
197 static void CreateExternalInstallGlobalError( | |
198 base::WeakPtr<ExtensionService> service, | |
199 const std::string& extension_id, | |
200 const ExtensionInstallPrompt::ShowParams& show_params, | |
201 ExtensionInstallPrompt::Delegate* prompt_delegate, | |
202 const ExtensionInstallPrompt::Prompt& prompt) { | |
203 if (!service.get()) | |
204 return; | |
205 const Extension* extension = service->GetInstalledExtension(extension_id); | |
206 if (!extension) | |
207 return; | |
208 GlobalErrorService* error_service = | |
209 GlobalErrorServiceFactory::GetForProfile(service->profile()); | |
210 if (error_service->GetGlobalErrorByMenuItemCommandID(kMenuCommandId)) | |
211 return; | |
212 | |
213 ExternalInstallDialogDelegate* delegate = | |
214 static_cast<ExternalInstallDialogDelegate*>(prompt_delegate); | |
215 ExternalInstallGlobalError* error_bubble = new ExternalInstallGlobalError( | |
216 service.get(), extension, delegate, prompt); | |
217 error_service->AddGlobalError(error_bubble); | |
218 // Show bubble immediately if possible. | |
219 if (delegate->browser()) | |
220 error_bubble->ShowBubbleView(delegate->browser()); | |
221 } | |
222 | |
223 static void ShowExternalInstallDialog( | |
224 ExtensionService* service, | |
225 Browser* browser, | |
226 const Extension* extension) { | |
227 // This object manages its own lifetime. | |
228 new ExternalInstallDialogDelegate(browser, service, extension, false); | |
229 } | |
230 | |
231 // ExternalInstallDialogDelegate -------------------------------------------- | |
232 | |
233 ExternalInstallDialogDelegate::ExternalInstallDialogDelegate( | |
234 Browser* browser, | |
235 ExtensionService* service, | |
236 const Extension* extension, | |
237 bool use_global_error) | |
238 : browser_(browser), | |
239 service_weak_(service->AsWeakPtr()), | |
240 extension_id_(extension->id()), | |
241 use_global_error_(use_global_error) { | |
242 AddRef(); // Balanced in Proceed or Abort. | |
243 | |
244 prompt_.reset(new ExtensionInstallPrompt::Prompt( | |
245 ExtensionInstallPrompt::EXTERNAL_INSTALL_PROMPT)); | |
246 | |
247 // If we don't have a browser, we can't go to the webstore to fetch data. | |
248 // This should only happen in tests. | |
249 if (!browser) { | |
250 ShowInstallUI(); | |
251 return; | |
252 } | |
253 | |
254 // Make sure to be notified if the owning profile is destroyed. | |
255 registrar_.Add(this, | |
256 chrome::NOTIFICATION_PROFILE_DESTROYED, | |
257 content::Source<Profile>(browser->profile())); | |
258 | |
259 webstore_data_fetcher_.reset(new WebstoreDataFetcher( | |
260 this, | |
261 browser->profile()->GetRequestContext(), | |
262 GURL::EmptyGURL(), | |
263 extension->id())); | |
264 webstore_data_fetcher_->Start(); | |
265 } | |
266 | |
267 void ExternalInstallDialogDelegate::OnWebstoreRequestFailure() { | |
268 ShowInstallUI(); | |
269 } | |
270 | |
271 void ExternalInstallDialogDelegate::OnWebstoreResponseParseSuccess( | |
272 scoped_ptr<base::DictionaryValue> webstore_data) { | |
273 std::string localized_user_count; | |
274 double average_rating; | |
275 int rating_count; | |
276 if (!webstore_data->GetString(kUsersKey, &localized_user_count) || | |
277 !webstore_data->GetDouble(kAverageRatingKey, &average_rating) || | |
278 !webstore_data->GetInteger(kRatingCountKey, &rating_count)) { | |
279 // If we don't get a valid webstore response, short circuit, and continue | |
280 // to show a prompt without webstore data. | |
281 ShowInstallUI(); | |
282 return; | |
283 } | |
284 | |
285 bool show_user_count = true; | |
286 webstore_data->GetBoolean(kShowUserCountKey, &show_user_count); | |
287 | |
288 prompt_->SetWebstoreData(localized_user_count, | |
289 show_user_count, | |
290 average_rating, | |
291 rating_count); | |
292 | |
293 ShowInstallUI(); | |
294 } | |
295 | |
296 void ExternalInstallDialogDelegate::OnWebstoreResponseParseFailure( | |
297 const std::string& error) { | |
298 ShowInstallUI(); | |
299 } | |
300 | |
301 void ExternalInstallDialogDelegate::Observe( | |
302 int type, | |
303 const content::NotificationSource& source, | |
304 const content::NotificationDetails& details) { | |
305 DCHECK_EQ(type, chrome::NOTIFICATION_PROFILE_DESTROYED); | |
306 // If the owning profile is destroyed, we need to abort so that we don't leak. | |
307 InstallUIAbort(false); // Not user initiated. | |
308 } | |
309 | |
310 void ExternalInstallDialogDelegate::ShowInstallUI() { | |
311 const Extension* extension = NULL; | |
312 if (!service_weak_.get() || | |
313 !(extension = service_weak_->GetInstalledExtension(extension_id_))) { | |
314 return; | |
315 } | |
316 install_ui_.reset( | |
317 ExtensionInstallUI::CreateInstallPromptWithBrowser(browser_)); | |
318 | |
319 const ExtensionInstallPrompt::ShowDialogCallback callback = | |
320 use_global_error_ ? | |
321 base::Bind(&CreateExternalInstallGlobalError, | |
322 service_weak_, | |
323 extension_id_) : | |
324 ExtensionInstallPrompt::GetDefaultShowDialogCallback(); | |
325 | |
326 install_ui_->ConfirmExternalInstall(this, extension, callback, *prompt_); | |
327 } | |
328 | |
329 ExternalInstallDialogDelegate::~ExternalInstallDialogDelegate() { | |
330 } | |
331 | |
332 void ExternalInstallDialogDelegate::InstallUIProceed() { | |
333 const Extension* extension = NULL; | |
334 if (service_weak_.get() && | |
335 (extension = service_weak_->GetInstalledExtension(extension_id_))) { | |
336 service_weak_->GrantPermissionsAndEnableExtension(extension); | |
337 } | |
338 Release(); | |
339 } | |
340 | |
341 void ExternalInstallDialogDelegate::InstallUIAbort(bool user_initiated) { | |
342 const Extension* extension = NULL; | |
343 | |
344 // Uninstall the extension if the abort was user initiated (and not, e.g., the | |
345 // result of the window closing). | |
346 // Otherwise, the extension will remain installed, but unacknowledged, so it | |
347 // will be prompted again. | |
348 if (user_initiated && | |
349 service_weak_.get() && | |
350 (extension = service_weak_->GetInstalledExtension(extension_id_))) { | |
351 service_weak_->UninstallExtension(extension_id_, false, NULL); | |
352 } | |
353 Release(); | |
354 } | |
355 | |
356 // ExternalInstallMenuAlert ------------------------------------------------- | |
357 | |
358 ExternalInstallMenuAlert::ExternalInstallMenuAlert(ExtensionService* service, | |
359 const Extension* extension) | |
360 : service_(service), | |
361 extension_(extension), | |
362 extension_registry_observer_(this) { | |
363 extension_registry_observer_.Add(ExtensionRegistry::Get(service->profile())); | |
364 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_REMOVED, | |
365 content::Source<Profile>(service->profile())); | |
366 } | |
367 | |
368 ExternalInstallMenuAlert::~ExternalInstallMenuAlert() { | |
369 } | |
370 | |
371 GlobalError::Severity ExternalInstallMenuAlert::GetSeverity() { | |
372 return SEVERITY_LOW; | |
373 } | |
374 | |
375 bool ExternalInstallMenuAlert::HasMenuItem() { | |
376 return true; | |
377 } | |
378 | |
379 int ExternalInstallMenuAlert::MenuItemCommandID() { | |
380 return kMenuCommandId; | |
381 } | |
382 | |
383 base::string16 ExternalInstallMenuAlert::MenuItemLabel() { | |
384 int id = -1; | |
385 if (extension_->is_app()) | |
386 id = IDS_EXTENSION_EXTERNAL_INSTALL_ALERT_APP; | |
387 else if (extension_->is_theme()) | |
388 id = IDS_EXTENSION_EXTERNAL_INSTALL_ALERT_THEME; | |
389 else | |
390 id = IDS_EXTENSION_EXTERNAL_INSTALL_ALERT_EXTENSION; | |
391 return l10n_util::GetStringFUTF16(id, base::UTF8ToUTF16(extension_->name())); | |
392 } | |
393 | |
394 void ExternalInstallMenuAlert::ExecuteMenuItem(Browser* browser) { | |
395 ShowExternalInstallDialog(service_, browser, extension_); | |
396 } | |
397 | |
398 bool ExternalInstallMenuAlert::HasBubbleView() { | |
399 return false; | |
400 } | |
401 base::string16 ExternalInstallMenuAlert::GetBubbleViewTitle() { | |
402 return base::string16(); | |
403 } | |
404 | |
405 std::vector<base::string16> ExternalInstallMenuAlert::GetBubbleViewMessages() { | |
406 return std::vector<base::string16>(); | |
407 } | |
408 | |
409 base::string16 ExternalInstallMenuAlert::GetBubbleViewAcceptButtonLabel() { | |
410 return base::string16(); | |
411 } | |
412 | |
413 base::string16 ExternalInstallMenuAlert::GetBubbleViewCancelButtonLabel() { | |
414 return base::string16(); | |
415 } | |
416 | |
417 void ExternalInstallMenuAlert::OnBubbleViewDidClose(Browser* browser) { | |
418 NOTREACHED(); | |
419 } | |
420 | |
421 void ExternalInstallMenuAlert::BubbleViewAcceptButtonPressed( | |
422 Browser* browser) { | |
423 NOTREACHED(); | |
424 } | |
425 | |
426 void ExternalInstallMenuAlert::BubbleViewCancelButtonPressed( | |
427 Browser* browser) { | |
428 NOTREACHED(); | |
429 } | |
430 | |
431 void ExternalInstallMenuAlert::OnExtensionLoaded( | |
432 content::BrowserContext* browser_context, | |
433 const Extension* extension) { | |
434 if (extension == extension_) | |
435 Clean(); | |
436 } | |
437 | |
438 void ExternalInstallMenuAlert::Observe( | |
439 int type, | |
440 const content::NotificationSource& source, | |
441 const content::NotificationDetails& details) { | |
442 // The error is invalidated if the extension has been loaded or removed. | |
443 DCHECK_EQ(type, chrome::NOTIFICATION_EXTENSION_REMOVED); | |
444 const Extension* extension = content::Details<const Extension>(details).ptr(); | |
445 if (extension == extension_) | |
446 Clean(); | |
447 } | |
448 | |
449 void ExternalInstallMenuAlert::Clean() { | |
450 GlobalErrorService* error_service = | |
451 GlobalErrorServiceFactory::GetForProfile(service_->profile()); | |
452 error_service->RemoveGlobalError(this); | |
453 service_->AcknowledgeExternalExtension(extension_->id()); | |
454 delete this; | |
455 } | |
456 | |
457 // ExternalInstallGlobalError ----------------------------------------------- | |
458 | |
459 ExternalInstallGlobalError::ExternalInstallGlobalError( | |
460 ExtensionService* service, | |
461 const Extension* extension, | |
462 ExternalInstallDialogDelegate* delegate, | |
463 const ExtensionInstallPrompt::Prompt& prompt) | |
464 : ExternalInstallMenuAlert(service, extension), | |
465 delegate_(delegate), | |
466 prompt_(&prompt) { | |
467 } | |
468 | |
469 ExternalInstallGlobalError::~ExternalInstallGlobalError() { | |
470 if (delegate_) | |
471 delegate_->Release(); | |
472 } | |
473 | |
474 void ExternalInstallGlobalError::ExecuteMenuItem(Browser* browser) { | |
475 ShowBubbleView(browser); | |
476 } | |
477 | |
478 bool ExternalInstallGlobalError::HasBubbleView() { | |
479 return true; | |
480 } | |
481 | |
482 gfx::Image ExternalInstallGlobalError::GetBubbleViewIcon() { | |
483 if (prompt_->icon().IsEmpty()) | |
484 return GlobalErrorWithStandardBubble::GetBubbleViewIcon(); | |
485 // Scale icon to a reasonable size. | |
486 return gfx::Image(gfx::ImageSkiaOperations::CreateResizedImage( | |
487 *prompt_->icon().ToImageSkia(), | |
488 skia::ImageOperations::RESIZE_BEST, | |
489 gfx::Size(extension_misc::EXTENSION_ICON_SMALL, | |
490 extension_misc::EXTENSION_ICON_SMALL))); | |
491 } | |
492 | |
493 base::string16 ExternalInstallGlobalError::GetBubbleViewTitle() { | |
494 return prompt_->GetDialogTitle(); | |
495 } | |
496 | |
497 std::vector<base::string16> | |
498 ExternalInstallGlobalError::GetBubbleViewMessages() { | |
499 std::vector<base::string16> messages; | |
500 messages.push_back(prompt_->GetHeading()); | |
501 if (prompt_->GetPermissionCount()) { | |
502 messages.push_back(prompt_->GetPermissionsHeading()); | |
503 for (size_t i = 0; i < prompt_->GetPermissionCount(); ++i) { | |
504 messages.push_back(l10n_util::GetStringFUTF16( | |
505 IDS_EXTENSION_PERMISSION_LINE, | |
506 prompt_->GetPermission(i))); | |
507 } | |
508 } | |
509 // TODO(yoz): OAuth issue advice? | |
510 return messages; | |
511 } | |
512 | |
513 base::string16 ExternalInstallGlobalError::GetBubbleViewAcceptButtonLabel() { | |
514 return prompt_->GetAcceptButtonLabel(); | |
515 } | |
516 | |
517 base::string16 ExternalInstallGlobalError::GetBubbleViewCancelButtonLabel() { | |
518 return prompt_->GetAbortButtonLabel(); | |
519 } | |
520 | |
521 void ExternalInstallGlobalError::OnBubbleViewDidClose(Browser* browser) { | |
522 } | |
523 | |
524 void ExternalInstallGlobalError::BubbleViewAcceptButtonPressed( | |
525 Browser* browser) { | |
526 ExternalInstallDialogDelegate* delegate = delegate_; | |
527 delegate_ = NULL; | |
528 delegate->InstallUIProceed(); | |
529 } | |
530 | |
531 void ExternalInstallGlobalError::BubbleViewCancelButtonPressed( | |
532 Browser* browser) { | |
533 ExternalInstallDialogDelegate* delegate = delegate_; | |
534 delegate_ = NULL; | |
535 delegate->InstallUIAbort(true); | |
536 } | |
537 | |
538 // Public interface --------------------------------------------------------- | |
539 | |
540 void AddExternalInstallError(ExtensionService* service, | |
541 const Extension* extension, | |
542 bool is_new_profile) { | |
543 GlobalErrorService* error_service = | |
544 GlobalErrorServiceFactory::GetForProfile(service->profile()); | |
545 if (error_service->GetGlobalErrorByMenuItemCommandID(kMenuCommandId)) | |
546 return; | |
547 | |
548 if (UseBubbleInstall(extension, is_new_profile)) { | |
549 Browser* browser = NULL; | |
550 #if !defined(OS_ANDROID) | |
551 browser = chrome::FindTabbedBrowser(service->profile(), | |
552 true, | |
553 chrome::GetActiveDesktop()); | |
554 #endif | |
555 new ExternalInstallDialogDelegate(browser, service, extension, true); | |
556 } else { | |
557 error_service->AddGlobalError( | |
558 new ExternalInstallMenuAlert(service, extension)); | |
559 } | |
560 } | |
561 | |
562 void RemoveExternalInstallError(ExtensionService* service) { | |
563 GlobalErrorService* error_service = | |
564 GlobalErrorServiceFactory::GetForProfile(service->profile()); | |
565 GlobalError* error = error_service->GetGlobalErrorByMenuItemCommandID( | |
566 kMenuCommandId); | |
567 if (error) { | |
568 error_service->RemoveGlobalError(error); | |
569 delete error; | |
570 } | |
571 } | |
572 | |
573 bool HasExternalInstallError(ExtensionService* service) { | |
574 GlobalErrorService* error_service = | |
575 GlobalErrorServiceFactory::GetForProfile(service->profile()); | |
576 GlobalError* error = error_service->GetGlobalErrorByMenuItemCommandID( | |
577 kMenuCommandId); | |
578 return !!error; | |
579 } | |
580 | |
581 bool HasExternalInstallBubble(ExtensionService* service) { | |
582 GlobalErrorService* error_service = | |
583 GlobalErrorServiceFactory::GetForProfile(service->profile()); | |
584 GlobalError* error = error_service->GetGlobalErrorByMenuItemCommandID( | |
585 kMenuCommandId); | |
586 return error && error->HasBubbleView(); | |
587 } | |
588 | |
589 } // namespace extensions | |
OLD | NEW |