extension_install_ui.cc revision 72a454cd3513ac24fbdd0e0cb9ad70b86a99b801
1// Copyright (c) 2011 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/extension_install_ui.h" 6 7#include <map> 8 9#include "base/command_line.h" 10#include "base/file_util.h" 11#include "base/string_number_conversions.h" 12#include "base/string_util.h" 13#include "base/utf_string_conversions.h" 14#include "chrome/browser/browser_list.h" 15#include "chrome/browser/browser_window.h" 16#include "chrome/browser/extensions/theme_installed_infobar_delegate.h" 17#include "chrome/browser/platform_util.h" 18#include "chrome/browser/profiles/profile.h" 19#include "chrome/browser/tab_contents/tab_contents.h" 20#include "chrome/browser/tabs/tab_strip_model.h" 21#include "chrome/browser/ui/browser_dialogs.h" 22#include "chrome/common/extensions/extension.h" 23#include "chrome/common/extensions/extension_icon_set.h" 24#include "chrome/common/extensions/extension_resource.h" 25#include "chrome/common/extensions/url_pattern.h" 26#include "chrome/common/notification_service.h" 27#include "chrome/common/url_constants.h" 28#include "grit/chromium_strings.h" 29#include "grit/generated_resources.h" 30#include "grit/theme_resources.h" 31#include "ui/base/l10n/l10n_util.h" 32#include "ui/base/resource/resource_bundle.h" 33 34#if defined(TOOLKIT_GTK) 35#include "chrome/browser/extensions/gtk_theme_installed_infobar_delegate.h" 36#include "chrome/browser/ui/gtk/gtk_theme_provider.h" 37#endif 38 39// static 40const int ExtensionInstallUI::kTitleIds[NUM_PROMPT_TYPES] = { 41 IDS_EXTENSION_INSTALL_PROMPT_TITLE, 42 IDS_EXTENSION_UNINSTALL_PROMPT_TITLE 43}; 44// static 45const int ExtensionInstallUI::kHeadingIds[NUM_PROMPT_TYPES] = { 46 IDS_EXTENSION_INSTALL_PROMPT_HEADING, 47 IDS_EXTENSION_UNINSTALL_PROMPT_HEADING 48}; 49// static 50const int ExtensionInstallUI::kButtonIds[NUM_PROMPT_TYPES] = { 51 IDS_EXTENSION_PROMPT_INSTALL_BUTTON, 52 IDS_EXTENSION_PROMPT_UNINSTALL_BUTTON 53}; 54 55namespace { 56 57// Size of extension icon in top left of dialog. 58const int kIconSize = 69; 59 60} // namespace 61 62ExtensionInstallUI::ExtensionInstallUI(Profile* profile) 63 : profile_(profile), 64 ui_loop_(MessageLoop::current()), 65 previous_use_system_theme_(false), 66 extension_(NULL), 67 delegate_(NULL), 68 prompt_type_(NUM_PROMPT_TYPES), 69 ALLOW_THIS_IN_INITIALIZER_LIST(tracker_(this)) { 70 // Remember the current theme in case the user presses undo. 71 if (profile_) { 72 const Extension* previous_theme = profile_->GetTheme(); 73 if (previous_theme) 74 previous_theme_id_ = previous_theme->id(); 75#if defined(TOOLKIT_GTK) 76 // On Linux, we also need to take the user's system settings into account 77 // to undo theme installation. 78 previous_use_system_theme_ = 79 GtkThemeProvider::GetFrom(profile_)->UseGtkTheme(); 80#else 81 DCHECK(!previous_use_system_theme_); 82#endif 83 } 84} 85 86ExtensionInstallUI::~ExtensionInstallUI() { 87} 88 89void ExtensionInstallUI::ConfirmInstall(Delegate* delegate, 90 const Extension* extension) { 91 DCHECK(ui_loop_ == MessageLoop::current()); 92 extension_ = extension; 93 delegate_ = delegate; 94 95 // We special-case themes to not show any confirm UI. Instead they are 96 // immediately installed, and then we show an infobar (see OnInstallSuccess) 97 // to allow the user to revert if they don't like it. 98 if (extension->is_theme()) { 99 delegate->InstallUIProceed(); 100 return; 101 } 102 103 ShowConfirmation(INSTALL_PROMPT); 104} 105 106void ExtensionInstallUI::ConfirmUninstall(Delegate* delegate, 107 const Extension* extension) { 108 DCHECK(ui_loop_ == MessageLoop::current()); 109 extension_ = extension; 110 delegate_ = delegate; 111 112 ShowConfirmation(UNINSTALL_PROMPT); 113} 114 115void ExtensionInstallUI::OnInstallSuccess(const Extension* extension, 116 SkBitmap* icon) { 117 extension_ = extension; 118 SetIcon(icon); 119 120 if (extension->is_theme()) { 121 ShowThemeInfoBar(previous_theme_id_, previous_use_system_theme_, 122 extension, profile_); 123 return; 124 } 125 126 // Extensions aren't enabled by default in incognito so we confirm 127 // the install in a normal window. 128 Profile* profile = profile_->GetOriginalProfile(); 129 Browser* browser = Browser::GetOrCreateTabbedBrowser(profile); 130 if (browser->tab_count() == 0) 131 browser->AddBlankTab(true); 132 browser->window()->Show(); 133 134 if (extension->GetFullLaunchURL().is_valid()) { 135 std::string hash_params = "app-id="; 136 hash_params += extension->id(); 137 138 std::string url(chrome::kChromeUINewTabURL); 139 url += "/#"; 140 url += hash_params; 141 browser->AddSelectedTabWithURL(GURL(url), PageTransition::TYPED); 142 143 return; 144 } 145 146 browser::ShowExtensionInstalledBubble(extension, browser, icon_, profile); 147} 148 149void ExtensionInstallUI::OnInstallFailure(const std::string& error) { 150 DCHECK(ui_loop_ == MessageLoop::current()); 151 152 Browser* browser = BrowserList::GetLastActiveWithProfile(profile_); 153 platform_util::SimpleErrorBox( 154 browser ? browser->window()->GetNativeHandle() : NULL, 155 l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALL_FAILURE_TITLE), 156 UTF8ToUTF16(error)); 157} 158 159void ExtensionInstallUI::SetIcon(SkBitmap* image) { 160 if (image) 161 icon_ = *image; 162 else 163 icon_ = SkBitmap(); 164 if (icon_.empty()) { 165 if (extension_->is_app()) { 166 icon_ = *ResourceBundle::GetSharedInstance().GetBitmapNamed( 167 IDR_APP_DEFAULT_ICON); 168 } else { 169 icon_ = *ResourceBundle::GetSharedInstance().GetBitmapNamed( 170 IDR_EXTENSION_DEFAULT_ICON); 171 } 172 } 173} 174 175void ExtensionInstallUI::OnImageLoaded( 176 SkBitmap* image, ExtensionResource resource, int index) { 177 SetIcon(image); 178 179 switch (prompt_type_) { 180 case INSTALL_PROMPT: { 181 // TODO(jcivelli): http://crbug.com/44771 We should not show an install 182 // dialog when installing an app from the gallery. 183 NotificationService* service = NotificationService::current(); 184 service->Notify(NotificationType::EXTENSION_WILL_SHOW_CONFIRM_DIALOG, 185 Source<ExtensionInstallUI>(this), 186 NotificationService::NoDetails()); 187 188 std::vector<string16> warnings = extension_->GetPermissionMessages(); 189 ShowExtensionInstallUIPrompt2Impl(profile_, delegate_, extension_, &icon_, 190 warnings); 191 break; 192 } 193 case UNINSTALL_PROMPT: { 194 ShowExtensionInstallUIPromptImpl(profile_, delegate_, extension_, &icon_, 195 UNINSTALL_PROMPT); 196 break; 197 } 198 default: 199 NOTREACHED() << "Unknown message"; 200 break; 201 } 202} 203 204void ExtensionInstallUI::ShowThemeInfoBar(const std::string& previous_theme_id, 205 bool previous_use_system_theme, 206 const Extension* new_theme, 207 Profile* profile) { 208 if (!new_theme->is_theme()) 209 return; 210 211 // Get last active normal browser of profile. 212 Browser* browser = BrowserList::FindBrowserWithType(profile, 213 Browser::TYPE_NORMAL, 214 true); 215 if (!browser) 216 return; 217 218 TabContents* tab_contents = browser->GetSelectedTabContents(); 219 if (!tab_contents) 220 return; 221 222 // First find any previous theme preview infobars. 223 InfoBarDelegate* old_delegate = NULL; 224 for (size_t i = 0; i < tab_contents->infobar_count(); ++i) { 225 InfoBarDelegate* delegate = tab_contents->GetInfoBarDelegateAt(i); 226 ThemeInstalledInfoBarDelegate* theme_infobar = 227 delegate->AsThemePreviewInfobarDelegate(); 228 if (theme_infobar) { 229 // If the user installed the same theme twice, ignore the second install 230 // and keep the first install info bar, so that they can easily undo to 231 // get back the previous theme. 232 if (theme_infobar->MatchesTheme(new_theme)) 233 return; 234 old_delegate = delegate; 235 break; 236 } 237 } 238 239 // Then either replace that old one or add a new one. 240 InfoBarDelegate* new_delegate = GetNewThemeInstalledInfoBarDelegate( 241 tab_contents, new_theme, previous_theme_id, previous_use_system_theme); 242 243 if (old_delegate) 244 tab_contents->ReplaceInfoBar(old_delegate, new_delegate); 245 else 246 tab_contents->AddInfoBar(new_delegate); 247} 248 249void ExtensionInstallUI::ShowConfirmation(PromptType prompt_type) { 250 // Load the image asynchronously. For the response, check OnImageLoaded. 251 prompt_type_ = prompt_type; 252 ExtensionResource image = 253 extension_->GetIconResource(Extension::EXTENSION_ICON_LARGE, 254 ExtensionIconSet::MATCH_EXACTLY); 255 tracker_.LoadImage(extension_, image, 256 gfx::Size(kIconSize, kIconSize), 257 ImageLoadingTracker::DONT_CACHE); 258} 259 260InfoBarDelegate* ExtensionInstallUI::GetNewThemeInstalledInfoBarDelegate( 261 TabContents* tab_contents, 262 const Extension* new_theme, 263 const std::string& previous_theme_id, 264 bool previous_use_system_theme) { 265#if defined(TOOLKIT_GTK) 266 return new GtkThemeInstalledInfoBarDelegate(tab_contents, new_theme, 267 previous_theme_id, previous_use_system_theme); 268#else 269 return new ThemeInstalledInfoBarDelegate(tab_contents, new_theme, 270 previous_theme_id); 271#endif 272} 273