blob: da9f0a061441515eb1f4ee38eafd1bab2c1abb14 [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,
rdevlin.cronine18eb8cd2015-07-16 16:31:2868 UninstallReason reason,
69 UninstallSource source) {
[email protected]226d79ad2014-03-14 21:34:5770 triggering_extension_ = triggering_extension;
rdevlin.cronine18eb8cd2015-07-16 16:31:2871 ConfirmUninstall(extension, reason, source);
[email protected]226d79ad2014-03-14 21:34:5772}
73
rdevlin.croninac8ce8c2015-05-27 23:00:0274void ExtensionUninstallDialog::ConfirmUninstall(
75 const scoped_refptr<const Extension>& extension,
rdevlin.cronine18eb8cd2015-07-16 16:31:2876 UninstallReason reason,
77 UninstallSource source) {
rdevlin.croninac8ce8c2015-05-27 23:00:0278 DCHECK(thread_checker_.CalledOnValidThread());
rdevlin.cronine18eb8cd2015-07-16 16:31:2879
80 UMA_HISTOGRAM_ENUMERATION("Extensions.UninstallSource", source,
81 NUM_UNINSTALL_SOURCES);
82
[email protected]502e39612011-03-26 01:36:2883 extension_ = extension;
rdevlin.croninac8ce8c2015-05-27 23:00:0284 uninstall_reason_ = reason;
[email protected]0d0ba182014-06-03 12:40:4385 // Bookmark apps may not have 128x128 icons so accept 64x64 icons.
[email protected]36a813162014-02-05 05:32:1986 const int icon_size = extension_->from_bookmark()
[email protected]0d0ba182014-06-03 12:40:4387 ? extension_misc::EXTENSION_ICON_SMALL * 2
88 : extension_misc::EXTENSION_ICON_LARGE;
[email protected]d4050672014-06-04 09:18:4089 ExtensionResource image = IconsInfo::GetIconResource(
rdevlin.cronin903676442015-05-15 18:34:1090 extension_.get(), icon_size, ExtensionIconSet::MATCH_BIGGER);
[email protected]eed85492013-01-14 20:37:4691
92 // Load the image asynchronously. The response will be sent to OnImageLoaded.
[email protected]d4050672014-06-04 09:18:4093 ImageLoader* loader = ImageLoader::Get(profile_);
[email protected]0d0ba182014-06-03 12:40:4394
[email protected]2a4939a2014-07-25 09:22:5295 SetIcon(gfx::Image());
[email protected]d4050672014-06-04 09:18:4096 std::vector<ImageLoader::ImageRepresentation> images_list;
97 images_list.push_back(ImageLoader::ImageRepresentation(
[email protected]0d0ba182014-06-03 12:40:4398 image,
[email protected]d4050672014-06-04 09:18:4099 ImageLoader::ImageRepresentation::NEVER_RESIZE,
[email protected]0d0ba182014-06-03 12:40:43100 gfx::Size(),
101 ui::SCALE_FACTOR_100P));
rdevlin.croninac8ce8c2015-05-27 23:00:02102 loader->LoadImagesAsync(extension_.get(), images_list,
[email protected]0d0ba182014-06-03 12:40:43103 base::Bind(&ExtensionUninstallDialog::OnImageLoaded,
rdevlin.croninac8ce8c2015-05-27 23:00:02104 AsWeakPtr(), extension_->id()));
[email protected]502e39612011-03-26 01:36:28105}
106
[email protected]bdd6eec2012-03-03 19:58:06107void ExtensionUninstallDialog::SetIcon(const gfx::Image& image) {
108 if (image.IsEmpty()) {
[email protected]dd46a4ce2012-09-15 10:50:50109 // 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
113 // lazily.
[email protected]32e7a9b2013-01-23 23:00:19114 icon_ = gfx::ImageSkia::CreateFrom1xBitmap(
[email protected]1bc3ef02012-10-24 16:49:59115 GetDefaultIconBitmapForMaxScaleFactor(extension_->is_app()));
[email protected]bdd6eec2012-03-03 19:58:06116 } else {
[email protected]6280b5882012-06-05 21:56:41117 icon_ = *image.ToImageSkia();
[email protected]502e39612011-03-26 01:36:28118 }
119}
120
[email protected]e0ebb8d2014-05-21 20:26:27121void ExtensionUninstallDialog::OnImageLoaded(const std::string& extension_id,
122 const gfx::Image& image) {
[email protected]d4050672014-06-04 09:18:40123 const Extension* target_extension =
124 ExtensionRegistry::Get(profile_)
125 ->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING);
[email protected]e0ebb8d2014-05-21 20:26:27126 if (!target_extension) {
rdevlin.croninac8ce8c2015-05-27 23:00:02127 delegate_->OnExtensionUninstallDialogClosed(
128 false, base::ASCIIToUTF16(kExtensionRemovedError));
[email protected]e0ebb8d2014-05-21 20:26:27129 return;
130 }
131
[email protected]502e39612011-03-26 01:36:28132 SetIcon(image);
rdevlin.croninac8ce8c2015-05-27 23:00:02133
rdevlin.cronin66209492015-06-10 20:44:05134 switch (ScopedTestDialogAutoConfirm::GetAutoConfirmValue()) {
135 case ScopedTestDialogAutoConfirm::NONE:
rdevlin.croninac8ce8c2015-05-27 23:00:02136 Show();
137 break;
rdevlin.cronin66209492015-06-10 20:44:05138 case ScopedTestDialogAutoConfirm::ACCEPT:
rdevlin.croninac8ce8c2015-05-27 23:00:02139 OnDialogClosed(CLOSE_ACTION_UNINSTALL);
140 break;
rdevlin.cronin66209492015-06-10 20:44:05141 case ScopedTestDialogAutoConfirm::CANCEL:
rdevlin.croninac8ce8c2015-05-27 23:00:02142 OnDialogClosed(CLOSE_ACTION_CANCELED);
143 break;
144 }
[email protected]5f1ba412012-06-25 20:10:52145}
[email protected]226d79ad2014-03-14 21:34:57146
147std::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()));
153 }
154 return l10n_util::GetStringFUTF8(IDS_EXTENSION_UNINSTALL_PROMPT_HEADING,
155 base::UTF8ToUTF16(extension_->name()));
156}
[email protected]d4050672014-06-04 09:18:40157
rdevlin.croninf3af70d52015-03-20 03:55:04158bool ExtensionUninstallDialog::ShouldShowReportAbuseCheckbox() const {
rdevlin.cronin903676442015-05-15 18:34:10159 return ManifestURL::UpdatesFromGallery(extension_.get());
rdevlin.croninf3af70d52015-03-20 03:55:04160}
161
rdevlin.cronin4f01c5f12015-05-07 17:52:00162void 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",
167 action,
168 CLOSE_ACTION_LAST);
169 }
rdevlin.croninac8ce8c2015-05-27 23:00:02170
171 bool success = false;
172 base::string16 error;
173 switch (action) {
174 case CLOSE_ACTION_UNINSTALL_AND_REPORT_ABUSE:
175 HandleReportAbuse();
176 // Fall through.
177 case CLOSE_ACTION_UNINSTALL: {
178 const Extension* current_extension =
179 ExtensionRegistry::Get(profile_)->GetExtensionById(
180 extension_->id(), ExtensionRegistry::EVERYTHING);
181 if (current_extension) {
182 success =
183 ExtensionSystem::Get(profile_)
184 ->extension_service()
185 ->UninstallExtension(extension_->id(), uninstall_reason_,
186 base::Bind(&base::DoNothing), &error);
187 } else {
188 error = base::ASCIIToUTF16(kExtensionRemovedError);
189 }
190 break;
191 }
192 case CLOSE_ACTION_CANCELED:
193 error = base::ASCIIToUTF16("User canceled uninstall dialog");
194 break;
195 case CLOSE_ACTION_LAST:
196 NOTREACHED();
197 }
198
199 delegate_->OnExtensionUninstallDialogClosed(success, error);
rdevlin.cronin4f01c5f12015-05-07 17:52:00200}
201
rdevlin.croninf3af70d52015-03-20 03:55:04202void ExtensionUninstallDialog::HandleReportAbuse() {
203 chrome::NavigateParams params(
204 profile_,
rdevlin.croninde23cac2015-07-15 23:51:39205 extension_urls::GetWebstoreReportAbuseUrl(extension_->id(), kReferrerId),
rdevlin.croninf3af70d52015-03-20 03:55:04206 ui::PAGE_TRANSITION_LINK);
207 params.disposition = NEW_FOREGROUND_TAB;
208 chrome::Navigate(&params);
209}
210
[email protected]d4050672014-06-04 09:18:40211} // namespace extensions