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/extension_uninstall_dialog.h" 6 7 #include "base/bind.h" 8 #include "base/logging.h" 9 #include "base/message_loop/message_loop.h" 10 #include "base/strings/utf_string_conversions.h" 11 #include "chrome/browser/chrome_notification_types.h" 12 #include "chrome/browser/extensions/extension_util.h" 13 #include "chrome/browser/profiles/profile.h" 14 #include "chrome/browser/ui/browser.h" 15 #include "content/public/browser/notification_service.h" 16 #include "content/public/browser/notification_source.h" 17 #include "extensions/browser/extension_registry.h" 18 #include "extensions/browser/image_loader.h" 19 #include "extensions/common/constants.h" 20 #include "extensions/common/extension.h" 21 #include "extensions/common/extension_icon_set.h" 22 #include "extensions/common/extension_resource.h" 23 #include "extensions/common/manifest_handlers/icons_handler.h" 24 #include "grit/generated_resources.h" 25 #include "grit/theme_resources.h" 26 #include "ui/base/l10n/l10n_util.h" 27 #include "ui/base/resource/resource_bundle.h" 28 #include "ui/gfx/image/image.h" 29 #include "ui/gfx/image/image_skia.h" 30 31 namespace extensions { 32 33 namespace { 34 35 // Returns bitmap for the default icon with size equal to the default icon's 36 // pixel size under maximal supported scale factor. 37 SkBitmap GetDefaultIconBitmapForMaxScaleFactor(bool is_app) { 38 const gfx::ImageSkia& image = 39 is_app ? util::GetDefaultAppIcon() : util::GetDefaultExtensionIcon(); 40 return image.GetRepresentation( 41 gfx::ImageSkia::GetMaxSupportedScale()).sk_bitmap(); 42 } 43 44 } // namespace 45 46 ExtensionUninstallDialog::ExtensionUninstallDialog( 47 Profile* profile, 48 Browser* browser, 49 ExtensionUninstallDialog::Delegate* delegate) 50 : profile_(profile), 51 browser_(browser), 52 delegate_(delegate), 53 extension_(NULL), 54 triggering_extension_(NULL), 55 state_(kImageIsLoading), 56 ui_loop_(base::MessageLoop::current()) { 57 if (browser) { 58 registrar_.Add(this, 59 chrome::NOTIFICATION_BROWSER_CLOSED, 60 content::Source<Browser>(browser)); 61 } 62 } 63 64 ExtensionUninstallDialog::~ExtensionUninstallDialog() { 65 } 66 67 void ExtensionUninstallDialog::ConfirmProgrammaticUninstall( 68 const Extension* extension, 69 const Extension* triggering_extension) { 70 triggering_extension_ = triggering_extension; 71 ConfirmUninstall(extension); 72 } 73 74 void ExtensionUninstallDialog::ConfirmUninstall(const Extension* extension) { 75 DCHECK(ui_loop_ == base::MessageLoop::current()); 76 extension_ = extension; 77 // Bookmark apps may not have 128x128 icons so accept 64x64 icons. 78 const int icon_size = extension_->from_bookmark() 79 ? extension_misc::EXTENSION_ICON_SMALL * 2 80 : extension_misc::EXTENSION_ICON_LARGE; 81 ExtensionResource image = IconsInfo::GetIconResource( 82 extension_, icon_size, ExtensionIconSet::MATCH_BIGGER); 83 84 // Load the image asynchronously. The response will be sent to OnImageLoaded. 85 state_ = kImageIsLoading; 86 ImageLoader* loader = ImageLoader::Get(profile_); 87 88 std::vector<ImageLoader::ImageRepresentation> images_list; 89 images_list.push_back(ImageLoader::ImageRepresentation( 90 image, 91 ImageLoader::ImageRepresentation::NEVER_RESIZE, 92 gfx::Size(), 93 ui::SCALE_FACTOR_100P)); 94 loader->LoadImagesAsync(extension_, 95 images_list, 96 base::Bind(&ExtensionUninstallDialog::OnImageLoaded, 97 AsWeakPtr(), 98 extension_->id())); 99 } 100 101 void ExtensionUninstallDialog::SetIcon(const gfx::Image& image) { 102 if (image.IsEmpty()) { 103 // Let's set default icon bitmap whose size is equal to the default icon's 104 // pixel size under maximal supported scale factor. If the bitmap is larger 105 // than the one we need, it will be scaled down by the ui code. 106 // TODO(tbarzic): We should use IconImage here and load the required bitmap 107 // lazily. 108 icon_ = gfx::ImageSkia::CreateFrom1xBitmap( 109 GetDefaultIconBitmapForMaxScaleFactor(extension_->is_app())); 110 } else { 111 icon_ = *image.ToImageSkia(); 112 } 113 } 114 115 void ExtensionUninstallDialog::OnImageLoaded(const std::string& extension_id, 116 const gfx::Image& image) { 117 const Extension* target_extension = 118 ExtensionRegistry::Get(profile_) 119 ->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING); 120 if (!target_extension) { 121 delegate_->ExtensionUninstallCanceled(); 122 return; 123 } 124 125 SetIcon(image); 126 127 // Show the dialog unless the browser has been closed while we were waiting 128 // for the image. 129 DCHECK(state_ == kImageIsLoading || state_ == kBrowserIsClosing); 130 if (state_ == kImageIsLoading) { 131 state_ = kDialogIsShowing; 132 Show(); 133 } 134 } 135 136 void ExtensionUninstallDialog::Observe( 137 int type, 138 const content::NotificationSource& source, 139 const content::NotificationDetails& details) { 140 DCHECK(type == chrome::NOTIFICATION_BROWSER_CLOSED); 141 142 browser_ = NULL; 143 // If the browser is closed while waiting for the image, we need to send a 144 // "cancel" event here, because there will not be another opportunity to 145 // notify the delegate of the cancellation as we won't open the dialog. 146 if (state_ == kImageIsLoading) { 147 state_ = kBrowserIsClosing; 148 delegate_->ExtensionUninstallCanceled(); 149 } 150 } 151 152 std::string ExtensionUninstallDialog::GetHeadingText() { 153 if (triggering_extension_) { 154 return l10n_util::GetStringFUTF8( 155 IDS_EXTENSION_PROGRAMMATIC_UNINSTALL_PROMPT_HEADING, 156 base::UTF8ToUTF16(triggering_extension_->name()), 157 base::UTF8ToUTF16(extension_->name())); 158 } 159 return l10n_util::GetStringFUTF8(IDS_EXTENSION_UNINSTALL_PROMPT_HEADING, 160 base::UTF8ToUTF16(extension_->name())); 161 } 162 163 } // namespace extensions 164