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.
5 #include "chrome/browser/extensions/extension_uninstall_dialog.h"
8 #include "base/logging.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/metrics/histogram_macros.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "chrome/browser/extensions/extension_service.h"
13 #include "chrome/browser/extensions/extension_util.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/ui/browser_navigator.h"
16 #include "chrome/grit/generated_resources.h"
17 #include "extensions/browser/extension_dialog_auto_confirm.h"
18 #include "extensions/browser/extension_registry.h"
19 #include "extensions/browser/extension_system.h"
20 #include "extensions/browser/image_loader.h"
21 #include "extensions/common/constants.h"
22 #include "extensions/common/extension.h"
23 #include "extensions/common/extension_icon_set.h"
24 #include "extensions/common/extension_resource.h"
25 #include "extensions/common/extension_urls.h"
26 #include "extensions/common/manifest_handlers/icons_handler.h"
27 #include "extensions/common/manifest_url_handlers.h"
28 #include "ui/base/l10n/l10n_util.h"
29 #include "ui/base/page_transition_types.h"
30 #include "ui/base/window_open_disposition.h"
31 #include "ui/gfx/image/image.h"
32 #include "ui/gfx/image/image_skia.h"
34 namespace extensions
{
38 const char kExtensionRemovedError
[] =
39 "Extension was removed before dialog closed.";
41 const char kReferrerId
[] = "chrome-remove-extension-dialog";
43 // Returns bitmap for the default icon with size equal to the default icon's
44 // pixel size under maximal supported scale factor.
45 SkBitmap
GetDefaultIconBitmapForMaxScaleFactor(bool is_app
) {
46 const gfx::ImageSkia
& image
=
47 is_app
? util::GetDefaultAppIcon() : util::GetDefaultExtensionIcon();
48 return image
.GetRepresentation(
49 gfx::ImageSkia::GetMaxSupportedScale()).sk_bitmap();
54 ExtensionUninstallDialog::ExtensionUninstallDialog(
56 ExtensionUninstallDialog::Delegate
* delegate
)
59 uninstall_reason_(UNINSTALL_REASON_FOR_TESTING
) {
62 ExtensionUninstallDialog::~ExtensionUninstallDialog() {
65 void ExtensionUninstallDialog::ConfirmUninstallByExtension(
66 const scoped_refptr
<const Extension
>& extension
,
67 const scoped_refptr
<const Extension
>& triggering_extension
,
68 UninstallReason reason
,
69 UninstallSource source
) {
70 triggering_extension_
= triggering_extension
;
71 ConfirmUninstall(extension
, reason
, source
);
74 void ExtensionUninstallDialog::ConfirmUninstall(
75 const scoped_refptr
<const Extension
>& extension
,
76 UninstallReason reason
,
77 UninstallSource source
) {
78 DCHECK(thread_checker_
.CalledOnValidThread());
80 UMA_HISTOGRAM_ENUMERATION("Extensions.UninstallSource", source
,
81 NUM_UNINSTALL_SOURCES
);
83 extension_
= extension
;
84 uninstall_reason_
= reason
;
85 // Bookmark apps may not have 128x128 icons so accept 64x64 icons.
86 const int icon_size
= extension_
->from_bookmark()
87 ? extension_misc::EXTENSION_ICON_SMALL
* 2
88 : extension_misc::EXTENSION_ICON_LARGE
;
89 ExtensionResource image
= IconsInfo::GetIconResource(
90 extension_
.get(), icon_size
, ExtensionIconSet::MATCH_BIGGER
);
92 // Load the image asynchronously. The response will be sent to OnImageLoaded.
93 ImageLoader
* loader
= ImageLoader::Get(profile_
);
95 SetIcon(gfx::Image());
96 std::vector
<ImageLoader::ImageRepresentation
> images_list
;
97 images_list
.push_back(ImageLoader::ImageRepresentation(
99 ImageLoader::ImageRepresentation::NEVER_RESIZE
,
101 ui::SCALE_FACTOR_100P
));
102 loader
->LoadImagesAsync(extension_
.get(), images_list
,
103 base::Bind(&ExtensionUninstallDialog::OnImageLoaded
,
104 AsWeakPtr(), extension_
->id()));
107 void ExtensionUninstallDialog::SetIcon(const gfx::Image
& image
) {
108 if (image
.IsEmpty()) {
109 // Let's set default icon bitmap whose size is equal to the default icon's
110 // pixel size under maximal supported scale factor. If the bitmap is larger
111 // than the one we need, it will be scaled down by the ui code.
112 // TODO(tbarzic): We should use IconImage here and load the required bitmap
114 icon_
= gfx::ImageSkia::CreateFrom1xBitmap(
115 GetDefaultIconBitmapForMaxScaleFactor(extension_
->is_app()));
117 icon_
= *image
.ToImageSkia();
121 void ExtensionUninstallDialog::OnImageLoaded(const std::string
& extension_id
,
122 const gfx::Image
& image
) {
123 const Extension
* target_extension
=
124 ExtensionRegistry::Get(profile_
)
125 ->GetExtensionById(extension_id
, ExtensionRegistry::EVERYTHING
);
126 if (!target_extension
) {
127 delegate_
->OnExtensionUninstallDialogClosed(
128 false, base::ASCIIToUTF16(kExtensionRemovedError
));
134 switch (ScopedTestDialogAutoConfirm::GetAutoConfirmValue()) {
135 case ScopedTestDialogAutoConfirm::NONE
:
138 case ScopedTestDialogAutoConfirm::ACCEPT
:
139 OnDialogClosed(CLOSE_ACTION_UNINSTALL
);
141 case ScopedTestDialogAutoConfirm::CANCEL
:
142 OnDialogClosed(CLOSE_ACTION_CANCELED
);
147 std::string
ExtensionUninstallDialog::GetHeadingText() {
148 if (triggering_extension_
) {
149 return l10n_util::GetStringFUTF8(
150 IDS_EXTENSION_PROGRAMMATIC_UNINSTALL_PROMPT_HEADING
,
151 base::UTF8ToUTF16(triggering_extension_
->name()),
152 base::UTF8ToUTF16(extension_
->name()));
154 return l10n_util::GetStringFUTF8(IDS_EXTENSION_UNINSTALL_PROMPT_HEADING
,
155 base::UTF8ToUTF16(extension_
->name()));
158 bool ExtensionUninstallDialog::ShouldShowReportAbuseCheckbox() const {
159 return ManifestURL::UpdatesFromGallery(extension_
.get());
162 void ExtensionUninstallDialog::OnDialogClosed(CloseAction action
) {
163 // We don't want to artificially weight any of the options, so only record if
164 // reporting abuse was available.
165 if (ShouldShowReportAbuseCheckbox()) {
166 UMA_HISTOGRAM_ENUMERATION("Extensions.UninstallDialogAction",
171 bool success
= false;
172 base::string16 error
;
174 case CLOSE_ACTION_UNINSTALL_AND_REPORT_ABUSE
:
177 case CLOSE_ACTION_UNINSTALL
: {
178 const Extension
* current_extension
=
179 ExtensionRegistry::Get(profile_
)->GetExtensionById(
180 extension_
->id(), ExtensionRegistry::EVERYTHING
);
181 if (current_extension
) {
183 ExtensionSystem::Get(profile_
)
184 ->extension_service()
185 ->UninstallExtension(extension_
->id(), uninstall_reason_
,
186 base::Bind(&base::DoNothing
), &error
);
188 error
= base::ASCIIToUTF16(kExtensionRemovedError
);
192 case CLOSE_ACTION_CANCELED
:
193 error
= base::ASCIIToUTF16("User canceled uninstall dialog");
195 case CLOSE_ACTION_LAST
:
199 delegate_
->OnExtensionUninstallDialogClosed(success
, error
);
202 void ExtensionUninstallDialog::HandleReportAbuse() {
203 chrome::NavigateParams
params(
205 extension_urls::GetWebstoreReportAbuseUrl(extension_
->id(), kReferrerId
),
206 ui::PAGE_TRANSITION_LINK
);
207 params
.disposition
= NEW_FOREGROUND_TAB
;
208 chrome::Navigate(¶ms
);
211 } // namespace extensions