blob: e4664994853c3fdecc0f56ccef709f4bf9136610 [file] [log] [blame]
[email protected]e3c0bc22012-02-24 01:34:151// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]502e39612011-03-26 01:36:282// 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
[email protected]0d9a1da82013-03-14 21:52:077#include "base/bind.h"
[email protected]502e39612011-03-26 01:36:288#include "base/logging.h"
[email protected]b19fe572013-07-18 04:54:269#include "base/message_loop/message_loop.h"
rdevlin.cronin4f01c5f12015-05-07 17:52:0010#include "base/metrics/histogram_macros.h"
[email protected]226d79ad2014-03-14 21:34:5711#include "base/strings/utf_string_conversions.h"
rdevlin.croninac8ce8c2015-05-27 23:00:0212#include "chrome/browser/extensions/extension_service.h"
[email protected]7eb20e32014-04-30 08:50:5613#include "chrome/browser/extensions/extension_util.h"
[email protected]472522b2013-10-25 00:41:2814#include "chrome/browser/profiles/profile.h"
rdevlin.croninf3af70d52015-03-20 03:55:0415#include "chrome/browser/ui/browser_navigator.h"
[email protected]af39f002014-08-22 10:18:1816#include "chrome/grit/generated_resources.h"
rdevlin.cronin66209492015-06-10 20:44:0517#include "extensions/browser/extension_dialog_auto_confirm.h"
[email protected]e0ebb8d2014-05-21 20:26:2718#include "extensions/browser/extension_registry.h"
rdevlin.croninac8ce8c2015-05-27 23:00:0219#include "extensions/browser/extension_system.h"
[email protected]326e6f02014-06-20 04:53:3720#include "extensions/browser/image_loader.h"
[email protected]cda103d2014-04-04 16:22:3921#include "extensions/common/constants.h"
[email protected]e4452d32013-11-15 23:07:4122#include "extensions/common/extension.h"
[email protected]4b7908842014-04-07 23:50:2223#include "extensions/common/extension_icon_set.h"
[email protected]993da5e2013-03-23 21:25:1624#include "extensions/common/extension_resource.h"
rdevlin.croninf3af70d52015-03-20 03:55:0425#include "extensions/common/extension_urls.h"
[email protected]0db486f2014-04-09 19:32:2226#include "extensions/common/manifest_handlers/icons_handler.h"
rdevlin.cronindbb8fa52015-05-06 00:16:5627#include "extensions/common/manifest_url_handlers.h"
[email protected]226d79ad2014-03-14 21:34:5728#include "ui/base/l10n/l10n_util.h"
rdevlin.croninf3af70d52015-03-20 03:55:0429#include "ui/base/page_transition_types.h"
30#include "ui/base/window_open_disposition.h"
[email protected]bdd6eec2012-03-03 19:58:0631#include "ui/gfx/image/image.h"
[email protected]50b66262013-09-24 03:25:4832#include "ui/gfx/image/image_skia.h"
[email protected]502e39612011-03-26 01:36:2833
[email protected]d4050672014-06-04 09:18:4034namespace extensions {
35
[email protected]dd46a4ce2012-09-15 10:50:5036namespace {
37
rdevlin.croninac8ce8c2015-05-27 23:00:0238const char kExtensionRemovedError[] =
39 "Extension was removed before dialog closed.";
40
rdevlin.croninde23cac2015-07-15 23:51:3941const char kReferrerId[] = "chrome-remove-extension-dialog";
42
[email protected]dd46a4ce2012-09-15 10:50:5043// Returns bitmap for the default icon with size equal to the default icon's
44// pixel size under maximal supported scale factor.
45SkBitmap GetDefaultIconBitmapForMaxScaleFactor(bool is_app) {
[email protected]d4050672014-06-04 09:18:4046 const gfx::ImageSkia& image =
47 is_app ? util::GetDefaultAppIcon() : util::GetDefaultExtensionIcon();
[email protected]50b66262013-09-24 03:25:4848 return image.GetRepresentation(
49 gfx::ImageSkia::GetMaxSupportedScale()).sk_bitmap();
[email protected]dd46a4ce2012-09-15 10:50:5050}
51
52} // namespace
53
[email protected]6f03db062011-09-22 20:37:1454ExtensionUninstallDialog::ExtensionUninstallDialog(
[email protected]520414b12013-01-22 19:27:3655 Profile* profile,
[email protected]6f03db062011-09-22 20:37:1456 ExtensionUninstallDialog::Delegate* delegate)
[email protected]520414b12013-01-22 19:27:3657 : profile_(profile),
[email protected]6f03db062011-09-22 20:37:1458 delegate_(delegate),
rdevlin.croninac8ce8c2015-05-27 23:00:0259 uninstall_reason_(UNINSTALL_REASON_FOR_TESTING) {
[email protected]5f1ba412012-06-25 20:10:5260}
[email protected]502e39612011-03-26 01:36:2861
[email protected]5f1ba412012-06-25 20:10:5262ExtensionUninstallDialog::~ExtensionUninstallDialog() {
[email protected]5f1ba412012-06-25 20:10:5263}
[email protected]502e39612011-03-26 01:36:2864
rdevlin.croninac8ce8c2015-05-27 23:00:0265void ExtensionUninstallDialog::ConfirmUninstallByExtension(
66 const scoped_refptr<const Extension>& extension,
67 const scoped_refptr<const Extension>& triggering_extension,
68 UninstallReason reason) {
[email protected]226d79ad2014-03-14 21:34:5769 triggering_extension_ = triggering_extension;
rdevlin.croninac8ce8c2015-05-27 23:00:0270 ConfirmUninstall(extension, reason);
[email protected]226d79ad2014-03-14 21:34:5771}
72
rdevlin.croninac8ce8c2015-05-27 23:00:0273void ExtensionUninstallDialog::ConfirmUninstall(
74 const scoped_refptr<const Extension>& extension,
75 UninstallReason reason) {
76 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]502e39612011-03-26 01:36:2877 extension_ = extension;
rdevlin.croninac8ce8c2015-05-27 23:00:0278 uninstall_reason_ = reason;
[email protected]0d0ba182014-06-03 12:40:4379 // Bookmark apps may not have 128x128 icons so accept 64x64 icons.
[email protected]36a813162014-02-05 05:32:1980 const int icon_size = extension_->from_bookmark()
[email protected]0d0ba182014-06-03 12:40:4381 ? extension_misc::EXTENSION_ICON_SMALL * 2
82 : extension_misc::EXTENSION_ICON_LARGE;
[email protected]d4050672014-06-04 09:18:4083 ExtensionResource image = IconsInfo::GetIconResource(
rdevlin.cronin903676442015-05-15 18:34:1084 extension_.get(), icon_size, ExtensionIconSet::MATCH_BIGGER);
[email protected]eed85492013-01-14 20:37:4685
86 // Load the image asynchronously. The response will be sent to OnImageLoaded.
[email protected]d4050672014-06-04 09:18:4087 ImageLoader* loader = ImageLoader::Get(profile_);
[email protected]0d0ba182014-06-03 12:40:4388
[email protected]2a4939a2014-07-25 09:22:5289 SetIcon(gfx::Image());
[email protected]d4050672014-06-04 09:18:4090 std::vector<ImageLoader::ImageRepresentation> images_list;
91 images_list.push_back(ImageLoader::ImageRepresentation(
[email protected]0d0ba182014-06-03 12:40:4392 image,
[email protected]d4050672014-06-04 09:18:4093 ImageLoader::ImageRepresentation::NEVER_RESIZE,
[email protected]0d0ba182014-06-03 12:40:4394 gfx::Size(),
95 ui::SCALE_FACTOR_100P));
rdevlin.croninac8ce8c2015-05-27 23:00:0296 loader->LoadImagesAsync(extension_.get(), images_list,
[email protected]0d0ba182014-06-03 12:40:4397 base::Bind(&ExtensionUninstallDialog::OnImageLoaded,
rdevlin.croninac8ce8c2015-05-27 23:00:0298 AsWeakPtr(), extension_->id()));
[email protected]502e39612011-03-26 01:36:2899}
100
[email protected]bdd6eec2012-03-03 19:58:06101void ExtensionUninstallDialog::SetIcon(const gfx::Image& image) {
102 if (image.IsEmpty()) {
[email protected]dd46a4ce2012-09-15 10:50:50103 // 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.
[email protected]32e7a9b2013-01-23 23:00:19108 icon_ = gfx::ImageSkia::CreateFrom1xBitmap(
[email protected]1bc3ef02012-10-24 16:49:59109 GetDefaultIconBitmapForMaxScaleFactor(extension_->is_app()));
[email protected]bdd6eec2012-03-03 19:58:06110 } else {
[email protected]6280b5882012-06-05 21:56:41111 icon_ = *image.ToImageSkia();
[email protected]502e39612011-03-26 01:36:28112 }
113}
114
[email protected]e0ebb8d2014-05-21 20:26:27115void ExtensionUninstallDialog::OnImageLoaded(const std::string& extension_id,
116 const gfx::Image& image) {
[email protected]d4050672014-06-04 09:18:40117 const Extension* target_extension =
118 ExtensionRegistry::Get(profile_)
119 ->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING);
[email protected]e0ebb8d2014-05-21 20:26:27120 if (!target_extension) {
rdevlin.croninac8ce8c2015-05-27 23:00:02121 delegate_->OnExtensionUninstallDialogClosed(
122 false, base::ASCIIToUTF16(kExtensionRemovedError));
[email protected]e0ebb8d2014-05-21 20:26:27123 return;
124 }
125
[email protected]502e39612011-03-26 01:36:28126 SetIcon(image);
rdevlin.croninac8ce8c2015-05-27 23:00:02127
rdevlin.cronin66209492015-06-10 20:44:05128 switch (ScopedTestDialogAutoConfirm::GetAutoConfirmValue()) {
129 case ScopedTestDialogAutoConfirm::NONE:
rdevlin.croninac8ce8c2015-05-27 23:00:02130 Show();
131 break;
rdevlin.cronin66209492015-06-10 20:44:05132 case ScopedTestDialogAutoConfirm::ACCEPT:
rdevlin.croninac8ce8c2015-05-27 23:00:02133 OnDialogClosed(CLOSE_ACTION_UNINSTALL);
134 break;
rdevlin.cronin66209492015-06-10 20:44:05135 case ScopedTestDialogAutoConfirm::CANCEL:
rdevlin.croninac8ce8c2015-05-27 23:00:02136 OnDialogClosed(CLOSE_ACTION_CANCELED);
137 break;
138 }
[email protected]5f1ba412012-06-25 20:10:52139}
[email protected]226d79ad2014-03-14 21:34:57140
141std::string ExtensionUninstallDialog::GetHeadingText() {
142 if (triggering_extension_) {
143 return l10n_util::GetStringFUTF8(
144 IDS_EXTENSION_PROGRAMMATIC_UNINSTALL_PROMPT_HEADING,
145 base::UTF8ToUTF16(triggering_extension_->name()),
146 base::UTF8ToUTF16(extension_->name()));
147 }
148 return l10n_util::GetStringFUTF8(IDS_EXTENSION_UNINSTALL_PROMPT_HEADING,
149 base::UTF8ToUTF16(extension_->name()));
150}
[email protected]d4050672014-06-04 09:18:40151
rdevlin.croninf3af70d52015-03-20 03:55:04152bool ExtensionUninstallDialog::ShouldShowReportAbuseCheckbox() const {
rdevlin.cronin903676442015-05-15 18:34:10153 return ManifestURL::UpdatesFromGallery(extension_.get());
rdevlin.croninf3af70d52015-03-20 03:55:04154}
155
rdevlin.cronin4f01c5f12015-05-07 17:52:00156void ExtensionUninstallDialog::OnDialogClosed(CloseAction action) {
157 // We don't want to artificially weight any of the options, so only record if
158 // reporting abuse was available.
159 if (ShouldShowReportAbuseCheckbox()) {
160 UMA_HISTOGRAM_ENUMERATION("Extensions.UninstallDialogAction",
161 action,
162 CLOSE_ACTION_LAST);
163 }
rdevlin.croninac8ce8c2015-05-27 23:00:02164
165 bool success = false;
166 base::string16 error;
167 switch (action) {
168 case CLOSE_ACTION_UNINSTALL_AND_REPORT_ABUSE:
169 HandleReportAbuse();
170 // Fall through.
171 case CLOSE_ACTION_UNINSTALL: {
172 const Extension* current_extension =
173 ExtensionRegistry::Get(profile_)->GetExtensionById(
174 extension_->id(), ExtensionRegistry::EVERYTHING);
175 if (current_extension) {
176 success =
177 ExtensionSystem::Get(profile_)
178 ->extension_service()
179 ->UninstallExtension(extension_->id(), uninstall_reason_,
180 base::Bind(&base::DoNothing), &error);
181 } else {
182 error = base::ASCIIToUTF16(kExtensionRemovedError);
183 }
184 break;
185 }
186 case CLOSE_ACTION_CANCELED:
187 error = base::ASCIIToUTF16("User canceled uninstall dialog");
188 break;
189 case CLOSE_ACTION_LAST:
190 NOTREACHED();
191 }
192
193 delegate_->OnExtensionUninstallDialogClosed(success, error);
rdevlin.cronin4f01c5f12015-05-07 17:52:00194}
195
rdevlin.croninf3af70d52015-03-20 03:55:04196void ExtensionUninstallDialog::HandleReportAbuse() {
197 chrome::NavigateParams params(
198 profile_,
rdevlin.croninde23cac2015-07-15 23:51:39199 extension_urls::GetWebstoreReportAbuseUrl(extension_->id(), kReferrerId),
rdevlin.croninf3af70d52015-03-20 03:55:04200 ui::PAGE_TRANSITION_LINK);
201 params.disposition = NEW_FOREGROUND_TAB;
202 chrome::Navigate(&params);
203}
204
[email protected]d4050672014-06-04 09:18:40205} // namespace extensions