Home | History | Annotate | Download | only in extensions
      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