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