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 // Returns bitmap for the default icon with size equal to the default icon's
42 // pixel size under maximal supported scale factor.
43 SkBitmap
GetDefaultIconBitmapForMaxScaleFactor(bool is_app
) {
44 const gfx::ImageSkia
& image
=
45 is_app
? util::GetDefaultAppIcon() : util::GetDefaultExtensionIcon();
46 return image
.GetRepresentation(
47 gfx::ImageSkia::GetMaxSupportedScale()).sk_bitmap();
52 ExtensionUninstallDialog::ExtensionUninstallDialog(
54 ExtensionUninstallDialog::Delegate
* delegate
)
57 uninstall_reason_(UNINSTALL_REASON_FOR_TESTING
) {
60 ExtensionUninstallDialog::~ExtensionUninstallDialog() {
63 void ExtensionUninstallDialog::ConfirmUninstallByExtension(
64 const scoped_refptr
<const Extension
>& extension
,
65 const scoped_refptr
<const Extension
>& triggering_extension
,
66 UninstallReason reason
) {
67 triggering_extension_
= triggering_extension
;
68 ConfirmUninstall(extension
, reason
);
71 void ExtensionUninstallDialog::ConfirmUninstall(
72 const scoped_refptr
<const Extension
>& extension
,
73 UninstallReason reason
) {
74 DCHECK(thread_checker_
.CalledOnValidThread());
75 extension_
= extension
;
76 uninstall_reason_
= reason
;
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_
.get(), icon_size
, ExtensionIconSet::MATCH_BIGGER
);
84 // Load the image asynchronously. The response will be sent to OnImageLoaded.
85 ImageLoader
* loader
= ImageLoader::Get(profile_
);
87 SetIcon(gfx::Image());
88 std::vector
<ImageLoader::ImageRepresentation
> images_list
;
89 images_list
.push_back(ImageLoader::ImageRepresentation(
91 ImageLoader::ImageRepresentation::NEVER_RESIZE
,
93 ui::SCALE_FACTOR_100P
));
94 loader
->LoadImagesAsync(extension_
.get(), images_list
,
95 base::Bind(&ExtensionUninstallDialog::OnImageLoaded
,
96 AsWeakPtr(), extension_
->id()));
99 void ExtensionUninstallDialog::SetIcon(const gfx::Image
& image
) {
100 if (image
.IsEmpty()) {
101 // Let's set default icon bitmap whose size is equal to the default icon's
102 // pixel size under maximal supported scale factor. If the bitmap is larger
103 // than the one we need, it will be scaled down by the ui code.
104 // TODO(tbarzic): We should use IconImage here and load the required bitmap
106 icon_
= gfx::ImageSkia::CreateFrom1xBitmap(
107 GetDefaultIconBitmapForMaxScaleFactor(extension_
->is_app()));
109 icon_
= *image
.ToImageSkia();
113 void ExtensionUninstallDialog::OnImageLoaded(const std::string
& extension_id
,
114 const gfx::Image
& image
) {
115 const Extension
* target_extension
=
116 ExtensionRegistry::Get(profile_
)
117 ->GetExtensionById(extension_id
, ExtensionRegistry::EVERYTHING
);
118 if (!target_extension
) {
119 delegate_
->OnExtensionUninstallDialogClosed(
120 false, base::ASCIIToUTF16(kExtensionRemovedError
));
126 switch (ScopedTestDialogAutoConfirm::GetAutoConfirmValue()) {
127 case ScopedTestDialogAutoConfirm::NONE
:
130 case ScopedTestDialogAutoConfirm::ACCEPT
:
131 OnDialogClosed(CLOSE_ACTION_UNINSTALL
);
133 case ScopedTestDialogAutoConfirm::CANCEL
:
134 OnDialogClosed(CLOSE_ACTION_CANCELED
);
139 std::string
ExtensionUninstallDialog::GetHeadingText() {
140 if (triggering_extension_
) {
141 return l10n_util::GetStringFUTF8(
142 IDS_EXTENSION_PROGRAMMATIC_UNINSTALL_PROMPT_HEADING
,
143 base::UTF8ToUTF16(triggering_extension_
->name()),
144 base::UTF8ToUTF16(extension_
->name()));
146 return l10n_util::GetStringFUTF8(IDS_EXTENSION_UNINSTALL_PROMPT_HEADING
,
147 base::UTF8ToUTF16(extension_
->name()));
150 bool ExtensionUninstallDialog::ShouldShowReportAbuseCheckbox() const {
151 return ManifestURL::UpdatesFromGallery(extension_
.get());
154 void ExtensionUninstallDialog::OnDialogClosed(CloseAction action
) {
155 // We don't want to artificially weight any of the options, so only record if
156 // reporting abuse was available.
157 if (ShouldShowReportAbuseCheckbox()) {
158 UMA_HISTOGRAM_ENUMERATION("Extensions.UninstallDialogAction",
163 bool success
= false;
164 base::string16 error
;
166 case CLOSE_ACTION_UNINSTALL_AND_REPORT_ABUSE
:
169 case CLOSE_ACTION_UNINSTALL
: {
170 const Extension
* current_extension
=
171 ExtensionRegistry::Get(profile_
)->GetExtensionById(
172 extension_
->id(), ExtensionRegistry::EVERYTHING
);
173 if (current_extension
) {
175 ExtensionSystem::Get(profile_
)
176 ->extension_service()
177 ->UninstallExtension(extension_
->id(), uninstall_reason_
,
178 base::Bind(&base::DoNothing
), &error
);
180 error
= base::ASCIIToUTF16(kExtensionRemovedError
);
184 case CLOSE_ACTION_CANCELED
:
185 error
= base::ASCIIToUTF16("User canceled uninstall dialog");
187 case CLOSE_ACTION_LAST
:
191 delegate_
->OnExtensionUninstallDialogClosed(success
, error
);
194 void ExtensionUninstallDialog::HandleReportAbuse() {
195 chrome::NavigateParams
params(
197 extension_urls::GetWebstoreReportAbuseUrl(extension_
->id()),
198 ui::PAGE_TRANSITION_LINK
);
199 params
.disposition
= NEW_FOREGROUND_TAB
;
200 chrome::Navigate(¶ms
);
203 } // namespace extensions