| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/extensions/extension_install_ui.h" |
| |
| #include <map> |
| |
| #include "base/command_line.h" |
| #include "base/file_util.h" |
| #include "base/string_number_conversions.h" |
| #include "base/string_util.h" |
| #include "base/stringprintf.h" |
| #include "base/utf_string_conversions.h" |
| #include "chrome/browser/extensions/extension_install_dialog.h" |
| #include "chrome/browser/extensions/theme_installed_infobar_delegate.h" |
| #include "chrome/browser/infobars/infobar_tab_helper.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/simple_message_box.h" |
| #include "chrome/browser/tabs/tab_strip_model.h" |
| #include "chrome/browser/themes/theme_service.h" |
| #include "chrome/browser/themes/theme_service_factory.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/browser_dialogs.h" |
| #include "chrome/browser/ui/browser_list.h" |
| #include "chrome/browser/ui/browser_navigator.h" |
| #include "chrome/browser/ui/browser_window.h" |
| #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
| #include "chrome/common/chrome_notification_types.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "chrome/common/extensions/extension.h" |
| #include "chrome/common/extensions/extension_icon_set.h" |
| #include "chrome/common/extensions/extension_resource.h" |
| #include "chrome/common/extensions/url_pattern.h" |
| #include "chrome/common/url_constants.h" |
| #include "content/common/notification_service.h" |
| #include "grit/chromium_strings.h" |
| #include "grit/generated_resources.h" |
| #include "grit/theme_resources.h" |
| #include "ui/base/l10n/l10n_util.h" |
| |
| // static |
| const int ExtensionInstallUI::kTitleIds[NUM_PROMPT_TYPES] = { |
| IDS_EXTENSION_INSTALL_PROMPT_TITLE, |
| IDS_EXTENSION_INSTALL_PROMPT_TITLE, |
| IDS_EXTENSION_RE_ENABLE_PROMPT_TITLE, |
| IDS_EXTENSION_PERMISSIONS_PROMPT_TITLE |
| }; |
| // static |
| const int ExtensionInstallUI::kHeadingIds[NUM_PROMPT_TYPES] = { |
| IDS_EXTENSION_INSTALL_PROMPT_HEADING, |
| IDS_EXTENSION_INSTALL_PROMPT_HEADING, |
| IDS_EXTENSION_RE_ENABLE_PROMPT_HEADING, |
| IDS_EXTENSION_PERMISSIONS_PROMPT_HEADING |
| }; |
| // static |
| const int ExtensionInstallUI::kButtonIds[NUM_PROMPT_TYPES] = { |
| IDS_EXTENSION_PROMPT_INSTALL_BUTTON, |
| IDS_EXTENSION_PROMPT_INSTALL_BUTTON, |
| IDS_EXTENSION_PROMPT_RE_ENABLE_BUTTON, |
| IDS_EXTENSION_PROMPT_PERMISSIONS_BUTTON |
| }; |
| // static |
| const int ExtensionInstallUI::kAbortButtonIds[NUM_PROMPT_TYPES] = { |
| 0, |
| 0, |
| 0, |
| IDS_EXTENSION_PROMPT_PERMISSIONS_ABORT_BUTTON |
| }; |
| // static |
| const int ExtensionInstallUI::kWarningIds[NUM_PROMPT_TYPES] = { |
| IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO, |
| IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO, |
| IDS_EXTENSION_PROMPT_WILL_NOW_HAVE_ACCESS_TO, |
| IDS_EXTENSION_PROMPT_WANTS_ACCESS_TO, |
| }; |
| |
| namespace { |
| |
| // Size of extension icon in top left of dialog. |
| const int kIconSize = 69; |
| |
| } // namespace |
| |
| ExtensionInstallUI::Prompt::Prompt(PromptType type) : type(type) { |
| } |
| |
| ExtensionInstallUI::Prompt::~Prompt() { |
| } |
| |
| ExtensionInstallUI::ExtensionInstallUI(Profile* profile) |
| : profile_(profile), |
| ui_loop_(MessageLoop::current()), |
| previous_using_native_theme_(false), |
| extension_(NULL), |
| delegate_(NULL), |
| prompt_type_(NUM_PROMPT_TYPES), |
| ALLOW_THIS_IN_INITIALIZER_LIST(tracker_(this)), |
| use_app_installed_bubble_(false) { |
| // Remember the current theme in case the user presses undo. |
| if (profile_) { |
| const Extension* previous_theme = |
| ThemeServiceFactory::GetThemeForProfile(profile_); |
| if (previous_theme) |
| previous_theme_id_ = previous_theme->id(); |
| previous_using_native_theme_ = |
| ThemeServiceFactory::GetForProfile(profile_)->UsingNativeTheme(); |
| } |
| } |
| |
| ExtensionInstallUI::~ExtensionInstallUI() { |
| } |
| |
| void ExtensionInstallUI::ConfirmInstall(Delegate* delegate, |
| const Extension* extension) { |
| DCHECK(ui_loop_ == MessageLoop::current()); |
| extension_ = extension; |
| permissions_ = extension->GetActivePermissions(); |
| delegate_ = delegate; |
| |
| // We special-case themes to not show any confirm UI. Instead they are |
| // immediately installed, and then we show an infobar (see OnInstallSuccess) |
| // to allow the user to revert if they don't like it. |
| if (extension->is_theme()) { |
| delegate->InstallUIProceed(); |
| return; |
| } |
| |
| ShowConfirmation(INSTALL_PROMPT); |
| } |
| |
| void ExtensionInstallUI::ConfirmReEnable(Delegate* delegate, |
| const Extension* extension) { |
| DCHECK(ui_loop_ == MessageLoop::current()); |
| extension_ = extension; |
| permissions_ = extension->GetActivePermissions(); |
| delegate_ = delegate; |
| |
| ShowConfirmation(RE_ENABLE_PROMPT); |
| } |
| |
| void ExtensionInstallUI::ConfirmPermissions( |
| Delegate* delegate, |
| const Extension* extension, |
| const ExtensionPermissionSet* permissions) { |
| DCHECK(ui_loop_ == MessageLoop::current()); |
| extension_ = extension; |
| permissions_ = permissions; |
| delegate_ = delegate; |
| |
| ShowConfirmation(PERMISSIONS_PROMPT); |
| } |
| |
| void ExtensionInstallUI::OnInstallSuccess(const Extension* extension, |
| SkBitmap* icon) { |
| extension_ = extension; |
| SetIcon(icon); |
| |
| if (extension->is_theme()) { |
| ShowThemeInfoBar(previous_theme_id_, previous_using_native_theme_, |
| extension, profile_); |
| return; |
| } |
| |
| // Extensions aren't enabled by default in incognito so we confirm |
| // the install in a normal window. |
| Profile* profile = profile_->GetOriginalProfile(); |
| Browser* browser = Browser::GetOrCreateTabbedBrowser(profile); |
| if (browser->tab_count() == 0) |
| browser->AddBlankTab(true); |
| browser->window()->Show(); |
| |
| bool use_bubble_for_apps = false; |
| |
| #if defined(TOOLKIT_VIEWS) |
| CommandLine* cmdline = CommandLine::ForCurrentProcess(); |
| use_bubble_for_apps = (use_app_installed_bubble_ || |
| cmdline->HasSwitch(switches::kAppsNewInstallBubble)); |
| #endif |
| |
| if (extension->is_app() && !use_bubble_for_apps) { |
| ExtensionInstallUI::OpenAppInstalledNTP(browser, extension->id()); |
| return; |
| } |
| |
| browser::ShowExtensionInstalledBubble(extension, browser, icon_, profile); |
| } |
| |
| namespace { |
| |
| bool disable_failure_ui_for_tests = false; |
| |
| } // namespace |
| |
| void ExtensionInstallUI::OnInstallFailure(const std::string& error) { |
| DCHECK(ui_loop_ == MessageLoop::current()); |
| |
| Browser* browser = BrowserList::GetLastActiveWithProfile(profile_); |
| if (disable_failure_ui_for_tests) |
| return; |
| browser::ShowErrorBox( |
| browser ? browser->window()->GetNativeHandle() : NULL, |
| l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALL_FAILURE_TITLE), |
| UTF8ToUTF16(error)); |
| } |
| |
| void ExtensionInstallUI::SetIcon(SkBitmap* image) { |
| if (image) |
| icon_ = *image; |
| else |
| icon_ = SkBitmap(); |
| if (icon_.empty()) |
| icon_ = Extension::GetDefaultIcon(extension_->is_app()); |
| } |
| |
| void ExtensionInstallUI::OnImageLoaded( |
| SkBitmap* image, const ExtensionResource& resource, int index) { |
| SetIcon(image); |
| |
| switch (prompt_type_) { |
| case PERMISSIONS_PROMPT: |
| case RE_ENABLE_PROMPT: |
| case INSTALL_PROMPT: { |
| NotificationService* service = NotificationService::current(); |
| service->Notify(chrome::NOTIFICATION_EXTENSION_WILL_SHOW_CONFIRM_DIALOG, |
| Source<ExtensionInstallUI>(this), |
| NotificationService::NoDetails()); |
| |
| Prompt prompt(prompt_type_); |
| prompt.permissions = permissions_->GetWarningMessages(); |
| ShowExtensionInstallDialog( |
| profile_, delegate_, extension_, &icon_, prompt); |
| break; |
| } |
| default: |
| NOTREACHED() << "Unknown message"; |
| break; |
| } |
| } |
| |
| // static |
| void ExtensionInstallUI::OpenAppInstalledNTP(Browser* browser, |
| const std::string& app_id) { |
| browser::NavigateParams params = |
| browser->GetSingletonTabNavigateParams(GURL(chrome::kChromeUINewTabURL)); |
| browser::Navigate(¶ms); |
| |
| NotificationService::current()->Notify( |
| chrome::NOTIFICATION_APP_INSTALLED_TO_NTP, |
| Source<TabContents>(params.target_contents->tab_contents()), |
| Details<const std::string>(&app_id)); |
| } |
| |
| // static |
| void ExtensionInstallUI::DisableFailureUIForTests() { |
| disable_failure_ui_for_tests = true; |
| } |
| |
| void ExtensionInstallUI::ShowThemeInfoBar(const std::string& previous_theme_id, |
| bool previous_using_native_theme, |
| const Extension* new_theme, |
| Profile* profile) { |
| if (!new_theme->is_theme()) |
| return; |
| |
| // Get last active tabbed browser of profile. |
| Browser* browser = BrowserList::FindTabbedBrowser(profile, true); |
| if (!browser) |
| return; |
| |
| TabContentsWrapper* tab_contents = browser->GetSelectedTabContentsWrapper(); |
| if (!tab_contents) |
| return; |
| InfoBarTabHelper* infobar_helper = tab_contents->infobar_tab_helper(); |
| |
| // First find any previous theme preview infobars. |
| InfoBarDelegate* old_delegate = NULL; |
| for (size_t i = 0; i < infobar_helper->infobar_count(); ++i) { |
| InfoBarDelegate* delegate = infobar_helper->GetInfoBarDelegateAt(i); |
| ThemeInstalledInfoBarDelegate* theme_infobar = |
| delegate->AsThemePreviewInfobarDelegate(); |
| if (theme_infobar) { |
| // If the user installed the same theme twice, ignore the second install |
| // and keep the first install info bar, so that they can easily undo to |
| // get back the previous theme. |
| if (theme_infobar->MatchesTheme(new_theme)) |
| return; |
| old_delegate = delegate; |
| break; |
| } |
| } |
| |
| // Then either replace that old one or add a new one. |
| InfoBarDelegate* new_delegate = GetNewThemeInstalledInfoBarDelegate( |
| tab_contents->tab_contents(), new_theme, previous_theme_id, |
| previous_using_native_theme); |
| |
| if (old_delegate) |
| infobar_helper->ReplaceInfoBar(old_delegate, new_delegate); |
| else |
| infobar_helper->AddInfoBar(new_delegate); |
| } |
| |
| void ExtensionInstallUI::ShowConfirmation(PromptType prompt_type) { |
| // Load the image asynchronously. For the response, check OnImageLoaded. |
| prompt_type_ = prompt_type; |
| ExtensionResource image = |
| extension_->GetIconResource(Extension::EXTENSION_ICON_LARGE, |
| ExtensionIconSet::MATCH_EXACTLY); |
| tracker_.LoadImage(extension_, image, |
| gfx::Size(kIconSize, kIconSize), |
| ImageLoadingTracker::DONT_CACHE); |
| } |
| |
| InfoBarDelegate* ExtensionInstallUI::GetNewThemeInstalledInfoBarDelegate( |
| TabContents* tab_contents, |
| const Extension* new_theme, |
| const std::string& previous_theme_id, |
| bool previous_using_native_theme) { |
| return new ThemeInstalledInfoBarDelegate(tab_contents, new_theme, |
| previous_theme_id, |
| previous_using_native_theme); |
| } |