blob: c8b3521c127caeba163fa51bde4e1116da57e481 [file] [log] [blame]
[email protected]c82da8c42012-06-08 19:49:111// 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_install_prompt.h"
6
7#include <map>
8
9#include "base/command_line.h"
10#include "base/file_util.h"
11#include "base/message_loop.h"
[email protected]c82da8c42012-06-08 19:49:1112#include "base/string_util.h"
13#include "base/stringprintf.h"
[email protected]3ea1b182013-02-08 22:38:4114#include "base/strings/string_number_conversions.h"
[email protected]c82da8c42012-06-08 19:49:1115#include "base/utf_string_conversions.h"
16#include "chrome/browser/extensions/bundle_installer.h"
[email protected]c82da8c42012-06-08 19:49:1117#include "chrome/browser/extensions/extension_install_ui.h"
[email protected]ec7de0c5a2012-11-16 07:40:4718#include "chrome/browser/extensions/image_loader.h"
[email protected]fc5077942012-08-15 21:37:5919#include "chrome/browser/prefs/pref_service.h"
[email protected]c82da8c42012-06-08 19:49:1120#include "chrome/browser/profiles/profile.h"
[email protected]b70a2d92012-06-28 19:51:2121#include "chrome/browser/signin/token_service.h"
22#include "chrome/browser/signin/token_service_factory.h"
[email protected]32fc4ff72012-06-15 21:50:0123#include "chrome/browser/ui/browser.h"
[email protected]619f86182012-07-03 21:30:1824#include "chrome/browser/ui/browser_window.h"
[email protected]c82da8c42012-06-08 19:49:1125#include "chrome/common/chrome_switches.h"
[email protected]29e0c4e72013-02-01 04:42:5626#include "chrome/common/extensions/api/identity/oauth2_manifest_handler.h"
[email protected]c82da8c42012-06-08 19:49:1127#include "chrome/common/extensions/extension.h"
[email protected]faf87192012-08-17 00:07:5928#include "chrome/common/extensions/extension_constants.h"
[email protected]c82da8c42012-06-08 19:49:1129#include "chrome/common/extensions/extension_icon_set.h"
30#include "chrome/common/extensions/extension_manifest_constants.h"
31#include "chrome/common/extensions/extension_resource.h"
[email protected]544471a2012-10-13 05:27:0932#include "chrome/common/extensions/feature_switch.h"
[email protected]1d5e58b2013-01-31 08:41:4033#include "chrome/common/extensions/manifest.h"
[email protected]bebe1d02012-08-02 20:17:0934#include "chrome/common/extensions/permissions/permission_set.h"
[email protected]fc5077942012-08-15 21:37:5935#include "chrome/common/pref_names.h"
[email protected]91e51d612012-10-21 23:03:0536#include "content/public/browser/web_contents.h"
[email protected]5db2e882012-12-20 10:17:2637#include "content/public/browser/web_contents_view.h"
[email protected]885c0e92012-11-13 20:27:4238#include "extensions/common/url_pattern.h"
[email protected]c82da8c42012-06-08 19:49:1139#include "grit/chromium_strings.h"
40#include "grit/generated_resources.h"
[email protected]2a281332012-07-11 22:20:2341#include "grit/theme_resources.h"
[email protected]c82da8c42012-06-08 19:49:1142#include "ui/base/l10n/l10n_util.h"
43#include "ui/base/resource/resource_bundle.h"
44#include "ui/gfx/image/image.h"
45
[email protected]c82da8c42012-06-08 19:49:1146using extensions::BundleInstaller;
47using extensions::Extension;
[email protected]1d5e58b2013-01-31 08:41:4048using extensions::Manifest;
[email protected]c2e66e12012-06-27 06:27:0649using extensions::PermissionSet;
[email protected]c82da8c42012-06-08 19:49:1150
[email protected]612a1cb12012-10-17 13:18:0351namespace {
52
[email protected]c82da8c42012-06-08 19:49:1153static const int kTitleIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
54 0, // The regular install prompt depends on what's being installed.
55 IDS_EXTENSION_INLINE_INSTALL_PROMPT_TITLE,
56 IDS_EXTENSION_INSTALL_PROMPT_TITLE,
57 IDS_EXTENSION_RE_ENABLE_PROMPT_TITLE,
[email protected]612a1cb12012-10-17 13:18:0358 IDS_EXTENSION_PERMISSIONS_PROMPT_TITLE,
59 IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_TITLE,
[email protected]3b035252013-01-31 19:05:0860 IDS_EXTENSION_POST_INSTALL_PERMISSIONS_PROMPT_TITLE,
[email protected]c82da8c42012-06-08 19:49:1161};
62static const int kHeadingIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
63 IDS_EXTENSION_INSTALL_PROMPT_HEADING,
64 0, // Inline installs use the extension name.
65 0, // Heading for bundle installs depends on the bundle contents.
66 IDS_EXTENSION_RE_ENABLE_PROMPT_HEADING,
[email protected]612a1cb12012-10-17 13:18:0367 IDS_EXTENSION_PERMISSIONS_PROMPT_HEADING,
[email protected]846606012012-10-19 18:42:2568 0, // External installs use different strings for extensions/apps.
[email protected]3b035252013-01-31 19:05:0869 IDS_EXTENSION_POST_INSTALL_PERMISSIONS_PROMPT_HEADING,
70};
71static const int kButtons[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
72 ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
73 ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
74 ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
75 ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
76 ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
77 ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
78 ui::DIALOG_BUTTON_CANCEL,
[email protected]c82da8c42012-06-08 19:49:1179};
80static const int kAcceptButtonIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
81 IDS_EXTENSION_PROMPT_INSTALL_BUTTON,
82 IDS_EXTENSION_PROMPT_INSTALL_BUTTON,
83 IDS_EXTENSION_PROMPT_INSTALL_BUTTON,
84 IDS_EXTENSION_PROMPT_RE_ENABLE_BUTTON,
[email protected]612a1cb12012-10-17 13:18:0385 IDS_EXTENSION_PROMPT_PERMISSIONS_BUTTON,
[email protected]846606012012-10-19 18:42:2586 0, // External installs use different strings for extensions/apps.
[email protected]3b035252013-01-31 19:05:0887 0,
[email protected]c82da8c42012-06-08 19:49:1188};
89static const int kAbortButtonIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
90 0, // These all use the platform's default cancel label.
91 0,
92 0,
93 0,
[email protected]612a1cb12012-10-17 13:18:0394 IDS_EXTENSION_PROMPT_PERMISSIONS_ABORT_BUTTON,
95 IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ABORT_BUTTON,
[email protected]3b035252013-01-31 19:05:0896 IDS_CLOSE,
[email protected]c82da8c42012-06-08 19:49:1197};
98static const int kPermissionsHeaderIds[
99 ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
100 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
101 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
102 IDS_EXTENSION_PROMPT_THESE_WILL_HAVE_ACCESS_TO,
103 IDS_EXTENSION_PROMPT_WILL_NOW_HAVE_ACCESS_TO,
104 IDS_EXTENSION_PROMPT_WANTS_ACCESS_TO,
[email protected]612a1cb12012-10-17 13:18:03105 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
[email protected]3b035252013-01-31 19:05:08106 IDS_EXTENSION_PROMPT_CAN_ACCESS,
[email protected]c82da8c42012-06-08 19:49:11107};
[email protected]612a1cb12012-10-17 13:18:03108static const int kOAuthHeaderIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
[email protected]fc5077942012-08-15 21:37:59109 IDS_EXTENSION_PROMPT_OAUTH_HEADER,
110 0, // Inline installs don't show OAuth permissions.
111 0, // Bundle installs don't show OAuth permissions.
112 IDS_EXTENSION_PROMPT_OAUTH_REENABLE_HEADER,
113 IDS_EXTENSION_PROMPT_OAUTH_PERMISSIONS_HEADER,
[email protected]612a1cb12012-10-17 13:18:03114 // TODO(mpcomplete): Do we need this for external install UI? If we do,
115 // we need to update FetchOAuthIssueAdviceIfNeeded.
116 0,
[email protected]3b035252013-01-31 19:05:08117 0,
[email protected]fc5077942012-08-15 21:37:59118};
[email protected]c82da8c42012-06-08 19:49:11119
[email protected]c82da8c42012-06-08 19:49:11120// Size of extension icon in top left of dialog.
121const int kIconSize = 69;
122
[email protected]dd46a4ce2012-09-15 10:50:50123// Returns pixel size under maximal scale factor for the icon whose device
124// independent size is |size_in_dip|
125int GetSizeForMaxScaleFactor(int size_in_dip) {
[email protected]059d76b2012-11-16 17:25:42126 float max_scale_factor_scale =
127 ui::GetScaleFactorScale(ui::GetMaxScaleFactor());
[email protected]dd46a4ce2012-09-15 10:50:50128 return static_cast<int>(size_in_dip * max_scale_factor_scale);
129}
130
131// Returns bitmap for the default icon with size equal to the default icon's
132// pixel size under maximal supported scale factor.
133SkBitmap GetDefaultIconBitmapForMaxScaleFactor(bool is_app) {
[email protected]dd46a4ce2012-09-15 10:50:50134 return Extension::GetDefaultIcon(is_app).
[email protected]059d76b2012-11-16 17:25:42135 GetRepresentation(ui::GetMaxScaleFactor()).sk_bitmap();
[email protected]dd46a4ce2012-09-15 10:50:50136}
137
[email protected]af6efb22012-10-12 02:23:05138// If auto confirm is enabled then posts a task to proceed with or cancel the
139// install and returns true. Otherwise returns false.
140bool AutoConfirmPrompt(ExtensionInstallPrompt::Delegate* delegate) {
141 const CommandLine* cmdline = CommandLine::ForCurrentProcess();
142 if (!cmdline->HasSwitch(switches::kAppsGalleryInstallAutoConfirmForTests))
143 return false;
144 std::string value = cmdline->GetSwitchValueASCII(
145 switches::kAppsGalleryInstallAutoConfirmForTests);
146
147 // We use PostTask instead of calling the delegate directly here, because in
148 // the real implementations it's highly likely the message loop will be
149 // pumping a few times before the user clicks accept or cancel.
150 if (value == "accept") {
151 MessageLoop::current()->PostTask(
152 FROM_HERE,
153 base::Bind(&ExtensionInstallPrompt::Delegate::InstallUIProceed,
154 base::Unretained(delegate)));
155 return true;
156 }
157
158 if (value == "cancel") {
159 MessageLoop::current()->PostTask(
160 FROM_HERE,
161 base::Bind(&ExtensionInstallPrompt::Delegate::InstallUIAbort,
162 base::Unretained(delegate),
163 true));
164 return true;
165 }
166
167 NOTREACHED();
168 return false;
169}
170
[email protected]91e51d612012-10-21 23:03:05171Profile* ProfileForWebContents(content::WebContents* web_contents) {
172 if (!web_contents)
173 return NULL;
174 return Profile::FromBrowserContext(web_contents->GetBrowserContext());
175}
176
[email protected]5db2e882012-12-20 10:17:26177gfx::NativeWindow NativeWindowForWebContents(content::WebContents* contents) {
178 if (!contents)
179 return NULL;
180
181 return contents->GetView()->GetTopLevelNativeWindow();
182}
183
[email protected]c82da8c42012-06-08 19:49:11184} // namespace
185
[email protected]5db2e882012-12-20 10:17:26186ExtensionInstallPrompt::Prompt::Prompt(PromptType type)
[email protected]c82da8c42012-06-08 19:49:11187 : type_(type),
188 extension_(NULL),
189 bundle_(NULL),
190 average_rating_(0.0),
[email protected]5db2e882012-12-20 10:17:26191 rating_count_(0) {
[email protected]c82da8c42012-06-08 19:49:11192}
193
194ExtensionInstallPrompt::Prompt::~Prompt() {
195}
196
197void ExtensionInstallPrompt::Prompt::SetPermissions(
198 const std::vector<string16>& permissions) {
199 permissions_ = permissions;
200}
201
[email protected]b70a2d92012-06-28 19:51:21202void ExtensionInstallPrompt::Prompt::SetOAuthIssueAdvice(
203 const IssueAdviceInfo& issue_advice) {
204 oauth_issue_advice_ = issue_advice;
205}
206
[email protected]5db2e882012-12-20 10:17:26207void ExtensionInstallPrompt::Prompt::SetUserNameFromProfile(Profile* profile) {
208 // |profile| can be NULL in unit tests.
209 if (profile) {
210 oauth_user_name_ = UTF8ToUTF16(profile->GetPrefs()->GetString(
211 prefs::kGoogleServicesUsername));
212 } else {
213 oauth_user_name_.clear();
214 }
215}
216
[email protected]c82da8c42012-06-08 19:49:11217void ExtensionInstallPrompt::Prompt::SetInlineInstallWebstoreData(
218 const std::string& localized_user_count,
219 double average_rating,
220 int rating_count) {
221 CHECK_EQ(INLINE_INSTALL_PROMPT, type_);
222 localized_user_count_ = localized_user_count;
223 average_rating_ = average_rating;
224 rating_count_ = rating_count;
225}
226
227string16 ExtensionInstallPrompt::Prompt::GetDialogTitle() const {
[email protected]c82da8c42012-06-08 19:49:11228 int resource_id = kTitleIds[type_];
229
230 if (type_ == INSTALL_PROMPT) {
231 if (extension_->is_app())
232 resource_id = IDS_EXTENSION_INSTALL_APP_PROMPT_TITLE;
233 else if (extension_->is_theme())
234 resource_id = IDS_EXTENSION_INSTALL_THEME_PROMPT_TITLE;
235 else
236 resource_id = IDS_EXTENSION_INSTALL_EXTENSION_PROMPT_TITLE;
[email protected]612a1cb12012-10-17 13:18:03237 } else if (type_ == EXTERNAL_INSTALL_PROMPT) {
238 return l10n_util::GetStringFUTF16(
239 resource_id, UTF8ToUTF16(extension_->name()));
[email protected]c82da8c42012-06-08 19:49:11240 }
241
242 return l10n_util::GetStringUTF16(resource_id);
243}
244
245string16 ExtensionInstallPrompt::Prompt::GetHeading() const {
246 if (type_ == INLINE_INSTALL_PROMPT) {
247 return UTF8ToUTF16(extension_->name());
248 } else if (type_ == BUNDLE_INSTALL_PROMPT) {
249 return bundle_->GetHeadingTextFor(BundleInstaller::Item::STATE_PENDING);
[email protected]612a1cb12012-10-17 13:18:03250 } else if (type_ == EXTERNAL_INSTALL_PROMPT) {
[email protected]846606012012-10-19 18:42:25251 int resource_id = -1;
252 if (extension_->is_app())
253 resource_id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_HEADING_APP;
254 else if (extension_->is_theme())
255 resource_id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_HEADING_THEME;
256 else
257 resource_id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_HEADING_EXTENSION;
258 return l10n_util::GetStringUTF16(resource_id);
[email protected]c82da8c42012-06-08 19:49:11259 } else {
260 return l10n_util::GetStringFUTF16(
261 kHeadingIds[type_], UTF8ToUTF16(extension_->name()));
262 }
263}
264
[email protected]3b035252013-01-31 19:05:08265int ExtensionInstallPrompt::Prompt::GetDialogButtons() const {
266 return kButtons[type_];
267}
268
[email protected]c82da8c42012-06-08 19:49:11269string16 ExtensionInstallPrompt::Prompt::GetAcceptButtonLabel() const {
[email protected]846606012012-10-19 18:42:25270 if (type_ == EXTERNAL_INSTALL_PROMPT) {
271 int id = -1;
272 if (extension_->is_app())
273 id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_APP;
274 else if (extension_->is_theme())
275 id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_THEME;
276 else
277 id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_EXTENSION;
278 return l10n_util::GetStringUTF16(id);
279 }
[email protected]c82da8c42012-06-08 19:49:11280 return l10n_util::GetStringUTF16(kAcceptButtonIds[type_]);
281}
282
283bool ExtensionInstallPrompt::Prompt::HasAbortButtonLabel() const {
284 return kAbortButtonIds[type_] > 0;
285}
286
287string16 ExtensionInstallPrompt::Prompt::GetAbortButtonLabel() const {
288 CHECK(HasAbortButtonLabel());
289 return l10n_util::GetStringUTF16(kAbortButtonIds[type_]);
290}
291
292string16 ExtensionInstallPrompt::Prompt::GetPermissionsHeading() const {
293 return l10n_util::GetStringUTF16(kPermissionsHeaderIds[type_]);
294}
295
[email protected]813475e2012-07-02 23:54:18296string16 ExtensionInstallPrompt::Prompt::GetOAuthHeading() const {
[email protected]5db2e882012-12-20 10:17:26297 return l10n_util::GetStringFUTF16(kOAuthHeaderIds[type_], oauth_user_name_);
[email protected]813475e2012-07-02 23:54:18298}
299
[email protected]c82da8c42012-06-08 19:49:11300void ExtensionInstallPrompt::Prompt::AppendRatingStars(
301 StarAppender appender, void* data) const {
302 CHECK(appender);
303 CHECK_EQ(INLINE_INSTALL_PROMPT, type_);
304 int rating_integer = floor(average_rating_);
305 double rating_fractional = average_rating_ - rating_integer;
306
307 if (rating_fractional > 0.66) {
308 rating_integer++;
309 }
310
311 if (rating_fractional < 0.33 || rating_fractional > 0.66) {
312 rating_fractional = 0;
313 }
314
315 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
316 int i;
317 for (i = 0; i < rating_integer; i++) {
318 appender(rb.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_ON), data);
319 }
320 if (rating_fractional) {
321 appender(rb.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_HALF_LEFT), data);
322 i++;
323 }
324 for (; i < kMaxExtensionRating; i++) {
325 appender(rb.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_OFF), data);
326 }
327}
328
329string16 ExtensionInstallPrompt::Prompt::GetRatingCount() const {
330 CHECK_EQ(INLINE_INSTALL_PROMPT, type_);
331 return l10n_util::GetStringFUTF16(
332 IDS_EXTENSION_RATING_COUNT,
333 UTF8ToUTF16(base::IntToString(rating_count_)));
334}
335
336string16 ExtensionInstallPrompt::Prompt::GetUserCount() const {
337 CHECK_EQ(INLINE_INSTALL_PROMPT, type_);
338 return l10n_util::GetStringFUTF16(
339 IDS_EXTENSION_USER_COUNT,
340 UTF8ToUTF16(localized_user_count_));
341}
342
343size_t ExtensionInstallPrompt::Prompt::GetPermissionCount() const {
344 return permissions_.size();
345}
346
347string16 ExtensionInstallPrompt::Prompt::GetPermission(size_t index) const {
348 CHECK_LT(index, permissions_.size());
[email protected]ef2654e42012-08-11 03:57:56349 return permissions_[index];
[email protected]c82da8c42012-06-08 19:49:11350}
351
[email protected]b70a2d92012-06-28 19:51:21352size_t ExtensionInstallPrompt::Prompt::GetOAuthIssueCount() const {
353 return oauth_issue_advice_.size();
354}
355
356const IssueAdviceInfoEntry& ExtensionInstallPrompt::Prompt::GetOAuthIssue(
357 size_t index) const {
358 CHECK_LT(index, oauth_issue_advice_.size());
359 return oauth_issue_advice_[index];
360}
361
[email protected]5db2e882012-12-20 10:17:26362ExtensionInstallPrompt::ShowParams::ShowParams(content::WebContents* contents)
363 : parent_web_contents(contents),
364 parent_window(NativeWindowForWebContents(contents)),
365 navigator(contents) {
366}
367
368ExtensionInstallPrompt::ShowParams::ShowParams(
369 gfx::NativeWindow window,
370 content::PageNavigator* navigator)
371 : parent_web_contents(NULL),
372 parent_window(window),
373 navigator(navigator) {
374}
375
[email protected]c82da8c42012-06-08 19:49:11376// static
377scoped_refptr<Extension>
378 ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
379 const DictionaryValue* manifest,
[email protected]c422a862012-07-31 15:46:13380 int flags,
[email protected]c82da8c42012-06-08 19:49:11381 const std::string& id,
382 const std::string& localized_name,
383 const std::string& localized_description,
384 std::string* error) {
385 scoped_ptr<DictionaryValue> localized_manifest;
386 if (!localized_name.empty() || !localized_description.empty()) {
387 localized_manifest.reset(manifest->DeepCopy());
388 if (!localized_name.empty()) {
389 localized_manifest->SetString(extension_manifest_keys::kName,
390 localized_name);
391 }
392 if (!localized_description.empty()) {
393 localized_manifest->SetString(extension_manifest_keys::kDescription,
394 localized_description);
395 }
396 }
397
398 return Extension::Create(
399 FilePath(),
[email protected]1d5e58b2013-01-31 08:41:40400 Manifest::INTERNAL,
[email protected]c82da8c42012-06-08 19:49:11401 localized_manifest.get() ? *localized_manifest.get() : *manifest,
[email protected]c422a862012-07-31 15:46:13402 flags,
[email protected]c82da8c42012-06-08 19:49:11403 id,
404 error);
405}
406
[email protected]619f86182012-07-03 21:30:18407ExtensionInstallPrompt::ExtensionInstallPrompt(
[email protected]91e51d612012-10-21 23:03:05408 content::WebContents* contents)
[email protected]16798da832012-08-30 20:46:04409 : record_oauth2_grant_(false),
[email protected]c82da8c42012-06-08 19:49:11410 ui_loop_(MessageLoop::current()),
411 extension_(NULL),
[email protected]91e51d612012-10-21 23:03:05412 install_ui_(ExtensionInstallUI::Create(ProfileForWebContents(contents))),
[email protected]5db2e882012-12-20 10:17:26413 show_params_(contents),
[email protected]c82da8c42012-06-08 19:49:11414 delegate_(NULL),
[email protected]5db2e882012-12-20 10:17:26415 prompt_(UNSET_PROMPT_TYPE) {
416 prompt_.SetUserNameFromProfile(install_ui_->profile());
417}
418
419ExtensionInstallPrompt::ExtensionInstallPrompt(
420 Profile* profile,
421 gfx::NativeWindow native_window,
422 content::PageNavigator* navigator)
423 : record_oauth2_grant_(false),
424 ui_loop_(MessageLoop::current()),
425 extension_(NULL),
426 install_ui_(ExtensionInstallUI::Create(profile)),
427 show_params_(native_window, navigator),
428 delegate_(NULL),
429 prompt_(UNSET_PROMPT_TYPE) {
430 prompt_.SetUserNameFromProfile(install_ui_->profile());
[email protected]c82da8c42012-06-08 19:49:11431}
432
433ExtensionInstallPrompt::~ExtensionInstallPrompt() {
434}
435
436void ExtensionInstallPrompt::ConfirmBundleInstall(
437 extensions::BundleInstaller* bundle,
[email protected]c2e66e12012-06-27 06:27:06438 const PermissionSet* permissions) {
[email protected]c82da8c42012-06-08 19:49:11439 DCHECK(ui_loop_ == MessageLoop::current());
440 bundle_ = bundle;
441 permissions_ = permissions;
442 delegate_ = bundle;
[email protected]5db2e882012-12-20 10:17:26443 prompt_.set_type(BUNDLE_INSTALL_PROMPT);
[email protected]c82da8c42012-06-08 19:49:11444
[email protected]b70a2d92012-06-28 19:51:21445 FetchOAuthIssueAdviceIfNeeded();
[email protected]c82da8c42012-06-08 19:49:11446}
447
[email protected]734bcec2012-10-08 20:29:05448void ExtensionInstallPrompt::ConfirmStandaloneInstall(
[email protected]c82da8c42012-06-08 19:49:11449 Delegate* delegate,
450 const Extension* extension,
451 SkBitmap* icon,
452 const ExtensionInstallPrompt::Prompt& prompt) {
453 DCHECK(ui_loop_ == MessageLoop::current());
454 extension_ = extension;
455 permissions_ = extension->GetActivePermissions();
456 delegate_ = delegate;
457 prompt_ = prompt;
[email protected]c82da8c42012-06-08 19:49:11458
459 SetIcon(icon);
[email protected]b70a2d92012-06-28 19:51:21460 FetchOAuthIssueAdviceIfNeeded();
[email protected]c82da8c42012-06-08 19:49:11461}
462
[email protected]af6efb22012-10-12 02:23:05463void ExtensionInstallPrompt::ConfirmWebstoreInstall(
464 Delegate* delegate,
465 const Extension* extension,
466 const SkBitmap* icon,
467 const ShowDialogCallback& show_dialog_callback) {
[email protected]c82da8c42012-06-08 19:49:11468 // SetIcon requires |extension_| to be set. ConfirmInstall will setup the
469 // remaining fields.
470 extension_ = extension;
471 SetIcon(icon);
[email protected]af6efb22012-10-12 02:23:05472 ConfirmInstall(delegate, extension, show_dialog_callback);
[email protected]c82da8c42012-06-08 19:49:11473}
474
[email protected]af6efb22012-10-12 02:23:05475void ExtensionInstallPrompt::ConfirmInstall(
476 Delegate* delegate,
477 const Extension* extension,
478 const ShowDialogCallback& show_dialog_callback) {
[email protected]c82da8c42012-06-08 19:49:11479 DCHECK(ui_loop_ == MessageLoop::current());
480 extension_ = extension;
481 permissions_ = extension->GetActivePermissions();
482 delegate_ = delegate;
[email protected]5db2e882012-12-20 10:17:26483 prompt_.set_type(INSTALL_PROMPT);
[email protected]af6efb22012-10-12 02:23:05484 show_dialog_callback_ = show_dialog_callback;
[email protected]c82da8c42012-06-08 19:49:11485
486 // We special-case themes to not show any confirm UI. Instead they are
487 // immediately installed, and then we show an infobar (see OnInstallSuccess)
488 // to allow the user to revert if they don't like it.
489 //
490 // We don't do this in the case where off-store extension installs are
491 // disabled because in that case, we don't show the dangerous download UI, so
492 // we need the UI confirmation.
493 if (extension->is_theme()) {
494 if (extension->from_webstore() ||
[email protected]544471a2012-10-13 05:27:09495 extensions::FeatureSwitch::easy_off_store_install()->IsEnabled()) {
[email protected]c82da8c42012-06-08 19:49:11496 delegate->InstallUIProceed();
497 return;
498 }
499 }
500
501 LoadImageIfNeeded();
502}
503
504void ExtensionInstallPrompt::ConfirmReEnable(Delegate* delegate,
505 const Extension* extension) {
506 DCHECK(ui_loop_ == MessageLoop::current());
507 extension_ = extension;
508 permissions_ = extension->GetActivePermissions();
509 delegate_ = delegate;
[email protected]5db2e882012-12-20 10:17:26510 prompt_.set_type(RE_ENABLE_PROMPT);
[email protected]c82da8c42012-06-08 19:49:11511
512 LoadImageIfNeeded();
513}
514
[email protected]612a1cb12012-10-17 13:18:03515void ExtensionInstallPrompt::ConfirmExternalInstall(
516 Delegate* delegate, const Extension* extension) {
517 DCHECK(ui_loop_ == MessageLoop::current());
518 extension_ = extension;
519 permissions_ = extension->GetActivePermissions();
520 delegate_ = delegate;
[email protected]5db2e882012-12-20 10:17:26521 prompt_.set_type(EXTERNAL_INSTALL_PROMPT);
[email protected]612a1cb12012-10-17 13:18:03522
523 LoadImageIfNeeded();
524}
525
[email protected]c82da8c42012-06-08 19:49:11526void ExtensionInstallPrompt::ConfirmPermissions(
527 Delegate* delegate,
528 const Extension* extension,
[email protected]c2e66e12012-06-27 06:27:06529 const PermissionSet* permissions) {
[email protected]c82da8c42012-06-08 19:49:11530 DCHECK(ui_loop_ == MessageLoop::current());
531 extension_ = extension;
532 permissions_ = permissions;
533 delegate_ = delegate;
[email protected]5db2e882012-12-20 10:17:26534 prompt_.set_type(PERMISSIONS_PROMPT);
[email protected]c82da8c42012-06-08 19:49:11535
536 LoadImageIfNeeded();
537}
538
[email protected]f746b3f2012-07-03 17:53:37539void ExtensionInstallPrompt::ConfirmIssueAdvice(
540 Delegate* delegate,
541 const Extension* extension,
542 const IssueAdviceInfo& issue_advice) {
543 DCHECK(ui_loop_ == MessageLoop::current());
544 extension_ = extension;
545 delegate_ = delegate;
[email protected]5db2e882012-12-20 10:17:26546 prompt_.set_type(PERMISSIONS_PROMPT);
[email protected]f746b3f2012-07-03 17:53:37547
548 record_oauth2_grant_ = true;
549 prompt_.SetOAuthIssueAdvice(issue_advice);
550
551 LoadImageIfNeeded();
552}
553
[email protected]3b035252013-01-31 19:05:08554void ExtensionInstallPrompt::ReviewPermissions(Delegate* delegate,
555 const Extension* extension) {
556 DCHECK(ui_loop_ == MessageLoop::current());
557 extension_ = extension;
558 permissions_ = extension->GetActivePermissions();
559 delegate_ = delegate;
560 prompt_.set_type(POST_INSTALL_PERMISSIONS_PROMPT);
561
562 LoadImageIfNeeded();
563}
564
[email protected]c82da8c42012-06-08 19:49:11565void ExtensionInstallPrompt::OnInstallSuccess(const Extension* extension,
566 SkBitmap* icon) {
567 extension_ = extension;
568 SetIcon(icon);
569
570 install_ui_->OnInstallSuccess(extension, &icon_);
571}
572
[email protected]bf3d9df2012-07-24 23:20:27573void ExtensionInstallPrompt::OnInstallFailure(
574 const extensions::CrxInstallerError& error) {
[email protected]c82da8c42012-06-08 19:49:11575 install_ui_->OnInstallFailure(error);
576}
577
578void ExtensionInstallPrompt::SetIcon(const SkBitmap* image) {
579 if (image)
580 icon_ = *image;
581 else
582 icon_ = SkBitmap();
[email protected]dd46a4ce2012-09-15 10:50:50583 if (icon_.empty()) {
584 // Let's set default icon bitmap whose size is equal to the default icon's
585 // pixel size under maximal supported scale factor. If the bitmap is larger
586 // than the one we need, it will be scaled down by the ui code.
587 icon_ = GetDefaultIconBitmapForMaxScaleFactor(extension_->is_app());
588 }
[email protected]c82da8c42012-06-08 19:49:11589}
590
[email protected]ec7de0c5a2012-11-16 07:40:47591void ExtensionInstallPrompt::OnImageLoaded(const gfx::Image& image) {
[email protected]c82da8c42012-06-08 19:49:11592 SetIcon(image.IsEmpty() ? NULL : image.ToSkBitmap());
[email protected]b70a2d92012-06-28 19:51:21593 FetchOAuthIssueAdviceIfNeeded();
[email protected]c82da8c42012-06-08 19:49:11594}
595
596void ExtensionInstallPrompt::LoadImageIfNeeded() {
597 // Bundle install prompts do not have an icon.
[email protected]5db2e882012-12-20 10:17:26598 // Also |install_ui_.profile()| can be NULL in unit tests.
599 if (!icon_.empty() || !install_ui_->profile()) {
[email protected]b70a2d92012-06-28 19:51:21600 FetchOAuthIssueAdviceIfNeeded();
[email protected]c82da8c42012-06-08 19:49:11601 return;
602 }
603
604 // Load the image asynchronously. For the response, check OnImageLoaded.
605 ExtensionResource image =
[email protected]faf87192012-08-17 00:07:59606 extension_->GetIconResource(extension_misc::EXTENSION_ICON_LARGE,
[email protected]c82da8c42012-06-08 19:49:11607 ExtensionIconSet::MATCH_BIGGER);
[email protected]dd46a4ce2012-09-15 10:50:50608 // Load the icon whose pixel size is large enough to be displayed under
609 // maximal supported scale factor. UI code will scale the icon down if needed.
610 // TODO(tbarzic): We should use IconImage here and load the required bitmap
611 // lazily.
612 int pixel_size = GetSizeForMaxScaleFactor(kIconSize);
[email protected]5db2e882012-12-20 10:17:26613 extensions::ImageLoader::Get(install_ui_->profile())->LoadImageAsync(
[email protected]ec7de0c5a2012-11-16 07:40:47614 extension_, image, gfx::Size(pixel_size, pixel_size),
615 base::Bind(&ExtensionInstallPrompt::OnImageLoaded, AsWeakPtr()));
[email protected]c82da8c42012-06-08 19:49:11616}
617
[email protected]b70a2d92012-06-28 19:51:21618void ExtensionInstallPrompt::FetchOAuthIssueAdviceIfNeeded() {
[email protected]668ed2c2012-09-12 10:52:41619 // |extension_| may be NULL, e.g. in the bundle install case.
620 if (!extension_ ||
[email protected]5db2e882012-12-20 10:17:26621 prompt_.type() == BUNDLE_INSTALL_PROMPT ||
622 prompt_.type() == INLINE_INSTALL_PROMPT ||
623 prompt_.type() == EXTERNAL_INSTALL_PROMPT ||
[email protected]668ed2c2012-09-12 10:52:41624 prompt_.GetOAuthIssueCount() != 0U) {
625 ShowConfirmation();
626 return;
627 }
628
[email protected]29e0c4e72013-02-01 04:42:56629 const extensions::OAuth2Info& oauth2_info =
630 extensions::OAuth2Info::GetOAuth2Info(extension_);
[email protected]668ed2c2012-09-12 10:52:41631 if (oauth2_info.client_id.empty() ||
632 oauth2_info.scopes.empty()) {
[email protected]b70a2d92012-06-28 19:51:21633 ShowConfirmation();
634 return;
635 }
636
[email protected]7cac5262012-09-26 17:32:25637 Profile* profile = install_ui_->profile();
[email protected]b70a2d92012-06-28 19:51:21638 TokenService* token_service = TokenServiceFactory::GetForProfile(profile);
[email protected]b70a2d92012-06-28 19:51:21639
640 token_flow_.reset(new OAuth2MintTokenFlow(
641 profile->GetRequestContext(),
642 this,
643 OAuth2MintTokenFlow::Parameters(
644 token_service->GetOAuth2LoginRefreshToken(),
645 extension_->id(),
646 oauth2_info.client_id,
[email protected]d4a37f1c2012-07-09 21:36:13647 oauth2_info.scopes,
[email protected]b70a2d92012-06-28 19:51:21648 OAuth2MintTokenFlow::MODE_ISSUE_ADVICE)));
649 token_flow_->Start();
650}
651
652void ExtensionInstallPrompt::OnIssueAdviceSuccess(
653 const IssueAdviceInfo& advice_info) {
654 prompt_.SetOAuthIssueAdvice(advice_info);
655 record_oauth2_grant_ = true;
656 ShowConfirmation();
657}
658
659void ExtensionInstallPrompt::OnMintTokenFailure(
660 const GoogleServiceAuthError& error) {
661 ShowConfirmation();
662}
663
[email protected]c82da8c42012-06-08 19:49:11664void ExtensionInstallPrompt::ShowConfirmation() {
[email protected]b0d1d0b2012-11-02 21:19:03665 if (permissions_ &&
666 (!extension_ || !extension_->ShouldSkipPermissionWarnings())) {
[email protected]1d5e58b2013-01-31 08:41:40667 Manifest::Type extension_type = extension_ ?
668 extension_->GetType() : Manifest::TYPE_UNKNOWN;
[email protected]a6e5c9b2012-08-09 04:06:25669 prompt_.SetPermissions(permissions_->GetWarningMessages(extension_type));
[email protected]bebe1d02012-08-02 20:17:09670 }
[email protected]c82da8c42012-06-08 19:49:11671
[email protected]5db2e882012-12-20 10:17:26672 switch (prompt_.type()) {
[email protected]c82da8c42012-06-08 19:49:11673 case PERMISSIONS_PROMPT:
674 case RE_ENABLE_PROMPT:
675 case INLINE_INSTALL_PROMPT:
[email protected]612a1cb12012-10-17 13:18:03676 case EXTERNAL_INSTALL_PROMPT:
[email protected]3b035252013-01-31 19:05:08677 case INSTALL_PROMPT:
678 case POST_INSTALL_PERMISSIONS_PROMPT: {
[email protected]c82da8c42012-06-08 19:49:11679 prompt_.set_extension(extension_);
[email protected]32e7a9b2013-01-23 23:00:19680 prompt_.set_icon(gfx::Image::CreateFrom1xBitmap(icon_));
[email protected]c82da8c42012-06-08 19:49:11681 break;
682 }
683 case BUNDLE_INSTALL_PROMPT: {
684 prompt_.set_bundle(bundle_);
[email protected]c82da8c42012-06-08 19:49:11685 break;
686 }
687 default:
688 NOTREACHED() << "Unknown message";
[email protected]af6efb22012-10-12 02:23:05689 return;
[email protected]c82da8c42012-06-08 19:49:11690 }
[email protected]af6efb22012-10-12 02:23:05691
692 if (AutoConfirmPrompt(delegate_))
693 return;
694
[email protected]5db2e882012-12-20 10:17:26695 if (show_dialog_callback_.is_null())
696 GetDefaultShowDialogCallback().Run(show_params_, delegate_, prompt_);
697 else
698 show_dialog_callback_.Run(show_params_, delegate_, prompt_);
[email protected]c82da8c42012-06-08 19:49:11699}