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 "chrome/browser/chrome_notification_types.h" 11 #include "chrome/browser/extensions/image_loader.h" 12 #include "chrome/browser/ui/browser.h" 13 #include "chrome/common/extensions/extension.h" 14 #include "chrome/common/extensions/extension_constants.h" 15 #include "chrome/common/extensions/extension_icon_set.h" 16 #include "chrome/common/extensions/manifest_handlers/icons_handler.h" 17 #include "content/public/browser/notification_service.h" 18 #include "content/public/browser/notification_source.h" 19 #include "extensions/common/extension_resource.h" 20 #include "grit/generated_resources.h" 21 #include "grit/theme_resources.h" 22 #include "ui/base/resource/resource_bundle.h" 23 #include "ui/gfx/image/image.h" 24 25 namespace { 26 27 // Returns pixel size under maximal scale factor for the icon whose device 28 // independent size is |size_in_dip| 29 int GetSizeForMaxScaleFactor(int size_in_dip) { 30 ui::ScaleFactor max_scale_factor = ui::GetMaxScaleFactor(); 31 float max_scale_factor_scale = ui::GetScaleFactorScale(max_scale_factor); 32 33 return static_cast<int>(size_in_dip * max_scale_factor_scale); 34 } 35 36 // Returns bitmap for the default icon with size equal to the default icon's 37 // pixel size under maximal supported scale factor. 38 SkBitmap GetDefaultIconBitmapForMaxScaleFactor(bool is_app) { 39 const gfx::ImageSkia& image = is_app ? 40 extensions::IconsInfo::GetDefaultAppIcon() : 41 extensions::IconsInfo::GetDefaultExtensionIcon(); 42 return image.GetRepresentation(ui::GetMaxScaleFactor()).sk_bitmap(); 43 } 44 45 } // namespace 46 47 // Size of extension icon in top left of dialog. 48 static const int kIconSize = 69; 49 50 ExtensionUninstallDialog::ExtensionUninstallDialog( 51 Profile* profile, 52 Browser* browser, 53 ExtensionUninstallDialog::Delegate* delegate) 54 : profile_(profile), 55 browser_(browser), 56 delegate_(delegate), 57 extension_(NULL), 58 state_(kImageIsLoading), 59 ui_loop_(base::MessageLoop::current()) { 60 if (browser) { 61 registrar_.Add(this, 62 chrome::NOTIFICATION_BROWSER_CLOSED, 63 content::Source<Browser>(browser)); 64 } 65 } 66 67 ExtensionUninstallDialog::~ExtensionUninstallDialog() { 68 } 69 70 void ExtensionUninstallDialog::ConfirmUninstall( 71 const extensions::Extension* extension) { 72 DCHECK(ui_loop_ == base::MessageLoop::current()); 73 extension_ = extension; 74 extensions::ExtensionResource image = extensions::IconsInfo::GetIconResource( 75 extension_, 76 extension_misc::EXTENSION_ICON_LARGE, 77 ExtensionIconSet::MATCH_BIGGER); 78 // Load the icon whose pixel size is large enough to be displayed under 79 // maximal supported scale factor. UI code will scale the icon down if needed. 80 int pixel_size = GetSizeForMaxScaleFactor(kIconSize); 81 82 // Load the image asynchronously. The response will be sent to OnImageLoaded. 83 state_ = kImageIsLoading; 84 extensions::ImageLoader* loader = 85 extensions::ImageLoader::Get(profile_); 86 loader->LoadImageAsync(extension_, image, 87 gfx::Size(pixel_size, pixel_size), 88 base::Bind(&ExtensionUninstallDialog::OnImageLoaded, 89 AsWeakPtr())); 90 } 91 92 void ExtensionUninstallDialog::SetIcon(const gfx::Image& image) { 93 if (image.IsEmpty()) { 94 // Let's set default icon bitmap whose size is equal to the default icon's 95 // pixel size under maximal supported scale factor. If the bitmap is larger 96 // than the one we need, it will be scaled down by the ui code. 97 // TODO(tbarzic): We should use IconImage here and load the required bitmap 98 // lazily. 99 icon_ = gfx::ImageSkia::CreateFrom1xBitmap( 100 GetDefaultIconBitmapForMaxScaleFactor(extension_->is_app())); 101 } else { 102 icon_ = *image.ToImageSkia(); 103 } 104 } 105 106 void ExtensionUninstallDialog::OnImageLoaded(const gfx::Image& image) { 107 SetIcon(image); 108 109 // Show the dialog unless the browser has been closed while we were waiting 110 // for the image. 111 DCHECK(state_ == kImageIsLoading || state_ == kBrowserIsClosing); 112 if (state_ == kImageIsLoading) { 113 state_ = kDialogIsShowing; 114 Show(); 115 } 116 } 117 118 void ExtensionUninstallDialog::Observe( 119 int type, 120 const content::NotificationSource& source, 121 const content::NotificationDetails& details) { 122 DCHECK(type == chrome::NOTIFICATION_BROWSER_CLOSED); 123 124 browser_ = NULL; 125 // If the browser is closed while waiting for the image, we need to send a 126 // "cancel" event here, because there will not be another opportunity to 127 // notify the delegate of the cancellation as we won't open the dialog. 128 if (state_ == kImageIsLoading) { 129 state_ = kBrowserIsClosing; 130 delegate_->ExtensionUninstallCanceled(); 131 } 132 } 133