blob: 2324e9f8cd598cda049a36a5d0e3fbeccf90f8e4 [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"
12#include "base/string_number_conversions.h"
13#include "base/string_util.h"
14#include "base/stringprintf.h"
15#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]fc5077942012-08-15 21:37:5918#include "chrome/browser/prefs/pref_service.h"
[email protected]c82da8c42012-06-08 19:49:1119#include "chrome/browser/profiles/profile.h"
[email protected]b70a2d92012-06-28 19:51:2120#include "chrome/browser/signin/token_service.h"
21#include "chrome/browser/signin/token_service_factory.h"
[email protected]32fc4ff72012-06-15 21:50:0122#include "chrome/browser/ui/browser.h"
[email protected]619f86182012-07-03 21:30:1823#include "chrome/browser/ui/browser_window.h"
[email protected]b62084b2012-06-12 01:53:3024#include "chrome/browser/ui/tab_contents/tab_contents.h"
[email protected]c82da8c42012-06-08 19:49:1125#include "chrome/common/chrome_switches.h"
26#include "chrome/common/extensions/extension.h"
[email protected]faf87192012-08-17 00:07:5927#include "chrome/common/extensions/extension_constants.h"
[email protected]c82da8c42012-06-08 19:49:1128#include "chrome/common/extensions/extension_icon_set.h"
29#include "chrome/common/extensions/extension_manifest_constants.h"
30#include "chrome/common/extensions/extension_resource.h"
[email protected]544471a2012-10-13 05:27:0931#include "chrome/common/extensions/feature_switch.h"
[email protected]bebe1d02012-08-02 20:17:0932#include "chrome/common/extensions/permissions/permission_set.h"
[email protected]c82da8c42012-06-08 19:49:1133#include "chrome/common/extensions/url_pattern.h"
[email protected]fc5077942012-08-15 21:37:5934#include "chrome/common/pref_names.h"
[email protected]619f86182012-07-03 21:30:1835#include "content/public/browser/page_navigator.h"
[email protected]c82da8c42012-06-08 19:49:1136#include "grit/chromium_strings.h"
37#include "grit/generated_resources.h"
[email protected]2a281332012-07-11 22:20:2338#include "grit/theme_resources.h"
[email protected]c82da8c42012-06-08 19:49:1139#include "ui/base/l10n/l10n_util.h"
40#include "ui/base/resource/resource_bundle.h"
41#include "ui/gfx/image/image.h"
42
[email protected]c82da8c42012-06-08 19:49:1143using extensions::BundleInstaller;
44using extensions::Extension;
[email protected]c2e66e12012-06-27 06:27:0645using extensions::PermissionSet;
[email protected]c82da8c42012-06-08 19:49:1146
[email protected]612a1cb12012-10-17 13:18:0347namespace {
48
[email protected]c82da8c42012-06-08 19:49:1149static const int kTitleIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
50 0, // The regular install prompt depends on what's being installed.
51 IDS_EXTENSION_INLINE_INSTALL_PROMPT_TITLE,
52 IDS_EXTENSION_INSTALL_PROMPT_TITLE,
53 IDS_EXTENSION_RE_ENABLE_PROMPT_TITLE,
[email protected]612a1cb12012-10-17 13:18:0354 IDS_EXTENSION_PERMISSIONS_PROMPT_TITLE,
55 IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_TITLE,
[email protected]c82da8c42012-06-08 19:49:1156};
57static const int kHeadingIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
58 IDS_EXTENSION_INSTALL_PROMPT_HEADING,
59 0, // Inline installs use the extension name.
60 0, // Heading for bundle installs depends on the bundle contents.
61 IDS_EXTENSION_RE_ENABLE_PROMPT_HEADING,
[email protected]612a1cb12012-10-17 13:18:0362 IDS_EXTENSION_PERMISSIONS_PROMPT_HEADING,
63 IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_HEADING,
[email protected]c82da8c42012-06-08 19:49:1164};
65static const int kAcceptButtonIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
66 IDS_EXTENSION_PROMPT_INSTALL_BUTTON,
67 IDS_EXTENSION_PROMPT_INSTALL_BUTTON,
68 IDS_EXTENSION_PROMPT_INSTALL_BUTTON,
69 IDS_EXTENSION_PROMPT_RE_ENABLE_BUTTON,
[email protected]612a1cb12012-10-17 13:18:0370 IDS_EXTENSION_PROMPT_PERMISSIONS_BUTTON,
71 IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON,
[email protected]c82da8c42012-06-08 19:49:1172};
73static const int kAbortButtonIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
74 0, // These all use the platform's default cancel label.
75 0,
76 0,
77 0,
[email protected]612a1cb12012-10-17 13:18:0378 IDS_EXTENSION_PROMPT_PERMISSIONS_ABORT_BUTTON,
79 IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ABORT_BUTTON,
[email protected]c82da8c42012-06-08 19:49:1180};
81static const int kPermissionsHeaderIds[
82 ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
83 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
84 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
85 IDS_EXTENSION_PROMPT_THESE_WILL_HAVE_ACCESS_TO,
86 IDS_EXTENSION_PROMPT_WILL_NOW_HAVE_ACCESS_TO,
87 IDS_EXTENSION_PROMPT_WANTS_ACCESS_TO,
[email protected]612a1cb12012-10-17 13:18:0388 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
[email protected]c82da8c42012-06-08 19:49:1189};
[email protected]612a1cb12012-10-17 13:18:0390static const int kOAuthHeaderIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
[email protected]fc5077942012-08-15 21:37:5991 IDS_EXTENSION_PROMPT_OAUTH_HEADER,
92 0, // Inline installs don't show OAuth permissions.
93 0, // Bundle installs don't show OAuth permissions.
94 IDS_EXTENSION_PROMPT_OAUTH_REENABLE_HEADER,
95 IDS_EXTENSION_PROMPT_OAUTH_PERMISSIONS_HEADER,
[email protected]612a1cb12012-10-17 13:18:0396 // TODO(mpcomplete): Do we need this for external install UI? If we do,
97 // we need to update FetchOAuthIssueAdviceIfNeeded.
98 0,
[email protected]fc5077942012-08-15 21:37:5999};
[email protected]c82da8c42012-06-08 19:49:11100
[email protected]c82da8c42012-06-08 19:49:11101// Size of extension icon in top left of dialog.
102const int kIconSize = 69;
103
[email protected]dd46a4ce2012-09-15 10:50:50104// Returns pixel size under maximal scale factor for the icon whose device
105// independent size is |size_in_dip|
106int GetSizeForMaxScaleFactor(int size_in_dip) {
107 std::vector<ui::ScaleFactor> supported_scale_factors =
108 ui::GetSupportedScaleFactors();
109 // Scale factors are in ascending order, so the last one is the one we need.
110 ui::ScaleFactor max_scale_factor = supported_scale_factors.back();
111 float max_scale_factor_scale = ui::GetScaleFactorScale(max_scale_factor);
112
113 return static_cast<int>(size_in_dip * max_scale_factor_scale);
114}
115
116// Returns bitmap for the default icon with size equal to the default icon's
117// pixel size under maximal supported scale factor.
118SkBitmap GetDefaultIconBitmapForMaxScaleFactor(bool is_app) {
119 std::vector<ui::ScaleFactor> supported_scale_factors =
120 ui::GetSupportedScaleFactors();
121 // Scale factors are in ascending order, so the last one is the one we need.
122 ui::ScaleFactor max_scale_factor =
123 supported_scale_factors[supported_scale_factors.size() - 1];
124
125 return Extension::GetDefaultIcon(is_app).
126 GetRepresentation(max_scale_factor).sk_bitmap();
127}
128
[email protected]af6efb22012-10-12 02:23:05129// If auto confirm is enabled then posts a task to proceed with or cancel the
130// install and returns true. Otherwise returns false.
131bool AutoConfirmPrompt(ExtensionInstallPrompt::Delegate* delegate) {
132 const CommandLine* cmdline = CommandLine::ForCurrentProcess();
133 if (!cmdline->HasSwitch(switches::kAppsGalleryInstallAutoConfirmForTests))
134 return false;
135 std::string value = cmdline->GetSwitchValueASCII(
136 switches::kAppsGalleryInstallAutoConfirmForTests);
137
138 // We use PostTask instead of calling the delegate directly here, because in
139 // the real implementations it's highly likely the message loop will be
140 // pumping a few times before the user clicks accept or cancel.
141 if (value == "accept") {
142 MessageLoop::current()->PostTask(
143 FROM_HERE,
144 base::Bind(&ExtensionInstallPrompt::Delegate::InstallUIProceed,
145 base::Unretained(delegate)));
146 return true;
147 }
148
149 if (value == "cancel") {
150 MessageLoop::current()->PostTask(
151 FROM_HERE,
152 base::Bind(&ExtensionInstallPrompt::Delegate::InstallUIAbort,
153 base::Unretained(delegate),
154 true));
155 return true;
156 }
157
158 NOTREACHED();
159 return false;
160}
161
[email protected]c82da8c42012-06-08 19:49:11162} // namespace
163
[email protected]fc5077942012-08-15 21:37:59164ExtensionInstallPrompt::Prompt::Prompt(Profile* profile, PromptType type)
[email protected]c82da8c42012-06-08 19:49:11165 : type_(type),
166 extension_(NULL),
167 bundle_(NULL),
168 average_rating_(0.0),
[email protected]fc5077942012-08-15 21:37:59169 rating_count_(0),
170 profile_(profile) {
[email protected]c82da8c42012-06-08 19:49:11171}
172
173ExtensionInstallPrompt::Prompt::~Prompt() {
174}
175
176void ExtensionInstallPrompt::Prompt::SetPermissions(
177 const std::vector<string16>& permissions) {
178 permissions_ = permissions;
179}
180
[email protected]b70a2d92012-06-28 19:51:21181void ExtensionInstallPrompt::Prompt::SetOAuthIssueAdvice(
182 const IssueAdviceInfo& issue_advice) {
183 oauth_issue_advice_ = issue_advice;
184}
185
[email protected]c82da8c42012-06-08 19:49:11186void ExtensionInstallPrompt::Prompt::SetInlineInstallWebstoreData(
187 const std::string& localized_user_count,
188 double average_rating,
189 int rating_count) {
190 CHECK_EQ(INLINE_INSTALL_PROMPT, type_);
191 localized_user_count_ = localized_user_count;
192 average_rating_ = average_rating;
193 rating_count_ = rating_count;
194}
195
196string16 ExtensionInstallPrompt::Prompt::GetDialogTitle() const {
[email protected]c82da8c42012-06-08 19:49:11197 int resource_id = kTitleIds[type_];
198
199 if (type_ == INSTALL_PROMPT) {
200 if (extension_->is_app())
201 resource_id = IDS_EXTENSION_INSTALL_APP_PROMPT_TITLE;
202 else if (extension_->is_theme())
203 resource_id = IDS_EXTENSION_INSTALL_THEME_PROMPT_TITLE;
204 else
205 resource_id = IDS_EXTENSION_INSTALL_EXTENSION_PROMPT_TITLE;
[email protected]612a1cb12012-10-17 13:18:03206 } else if (type_ == EXTERNAL_INSTALL_PROMPT) {
207 return l10n_util::GetStringFUTF16(
208 resource_id, UTF8ToUTF16(extension_->name()));
[email protected]c82da8c42012-06-08 19:49:11209 }
210
211 return l10n_util::GetStringUTF16(resource_id);
212}
213
214string16 ExtensionInstallPrompt::Prompt::GetHeading() const {
215 if (type_ == INLINE_INSTALL_PROMPT) {
216 return UTF8ToUTF16(extension_->name());
217 } else if (type_ == BUNDLE_INSTALL_PROMPT) {
218 return bundle_->GetHeadingTextFor(BundleInstaller::Item::STATE_PENDING);
[email protected]612a1cb12012-10-17 13:18:03219 } else if (type_ == EXTERNAL_INSTALL_PROMPT) {
220 return l10n_util::GetStringUTF16(kHeadingIds[type_]);
[email protected]c82da8c42012-06-08 19:49:11221 } else {
222 return l10n_util::GetStringFUTF16(
223 kHeadingIds[type_], UTF8ToUTF16(extension_->name()));
224 }
225}
226
227string16 ExtensionInstallPrompt::Prompt::GetAcceptButtonLabel() const {
228 return l10n_util::GetStringUTF16(kAcceptButtonIds[type_]);
229}
230
231bool ExtensionInstallPrompt::Prompt::HasAbortButtonLabel() const {
232 return kAbortButtonIds[type_] > 0;
233}
234
235string16 ExtensionInstallPrompt::Prompt::GetAbortButtonLabel() const {
236 CHECK(HasAbortButtonLabel());
237 return l10n_util::GetStringUTF16(kAbortButtonIds[type_]);
238}
239
240string16 ExtensionInstallPrompt::Prompt::GetPermissionsHeading() const {
241 return l10n_util::GetStringUTF16(kPermissionsHeaderIds[type_]);
242}
243
[email protected]813475e2012-07-02 23:54:18244string16 ExtensionInstallPrompt::Prompt::GetOAuthHeading() const {
[email protected]fc5077942012-08-15 21:37:59245 string16 username(ASCIIToUTF16("[email protected]"));
246 // |profile_| can be NULL in unit tests.
247 if (profile_) {
248 username = UTF8ToUTF16(profile_->GetPrefs()->GetString(
249 prefs::kGoogleServicesUsername));
250 }
251 int resource_id = kOAuthHeaderIds[type_];
252 return l10n_util::GetStringFUTF16(resource_id, username);
[email protected]813475e2012-07-02 23:54:18253}
254
[email protected]c82da8c42012-06-08 19:49:11255void ExtensionInstallPrompt::Prompt::AppendRatingStars(
256 StarAppender appender, void* data) const {
257 CHECK(appender);
258 CHECK_EQ(INLINE_INSTALL_PROMPT, type_);
259 int rating_integer = floor(average_rating_);
260 double rating_fractional = average_rating_ - rating_integer;
261
262 if (rating_fractional > 0.66) {
263 rating_integer++;
264 }
265
266 if (rating_fractional < 0.33 || rating_fractional > 0.66) {
267 rating_fractional = 0;
268 }
269
270 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
271 int i;
272 for (i = 0; i < rating_integer; i++) {
273 appender(rb.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_ON), data);
274 }
275 if (rating_fractional) {
276 appender(rb.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_HALF_LEFT), data);
277 i++;
278 }
279 for (; i < kMaxExtensionRating; i++) {
280 appender(rb.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_OFF), data);
281 }
282}
283
284string16 ExtensionInstallPrompt::Prompt::GetRatingCount() const {
285 CHECK_EQ(INLINE_INSTALL_PROMPT, type_);
286 return l10n_util::GetStringFUTF16(
287 IDS_EXTENSION_RATING_COUNT,
288 UTF8ToUTF16(base::IntToString(rating_count_)));
289}
290
291string16 ExtensionInstallPrompt::Prompt::GetUserCount() const {
292 CHECK_EQ(INLINE_INSTALL_PROMPT, type_);
293 return l10n_util::GetStringFUTF16(
294 IDS_EXTENSION_USER_COUNT,
295 UTF8ToUTF16(localized_user_count_));
296}
297
298size_t ExtensionInstallPrompt::Prompt::GetPermissionCount() const {
299 return permissions_.size();
300}
301
302string16 ExtensionInstallPrompt::Prompt::GetPermission(size_t index) const {
303 CHECK_LT(index, permissions_.size());
[email protected]ef2654e42012-08-11 03:57:56304 return permissions_[index];
[email protected]c82da8c42012-06-08 19:49:11305}
306
[email protected]b70a2d92012-06-28 19:51:21307size_t ExtensionInstallPrompt::Prompt::GetOAuthIssueCount() const {
308 return oauth_issue_advice_.size();
309}
310
311const IssueAdviceInfoEntry& ExtensionInstallPrompt::Prompt::GetOAuthIssue(
312 size_t index) const {
313 CHECK_LT(index, oauth_issue_advice_.size());
314 return oauth_issue_advice_[index];
315}
316
[email protected]c82da8c42012-06-08 19:49:11317// static
318scoped_refptr<Extension>
319 ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
320 const DictionaryValue* manifest,
[email protected]c422a862012-07-31 15:46:13321 int flags,
[email protected]c82da8c42012-06-08 19:49:11322 const std::string& id,
323 const std::string& localized_name,
324 const std::string& localized_description,
325 std::string* error) {
326 scoped_ptr<DictionaryValue> localized_manifest;
327 if (!localized_name.empty() || !localized_description.empty()) {
328 localized_manifest.reset(manifest->DeepCopy());
329 if (!localized_name.empty()) {
330 localized_manifest->SetString(extension_manifest_keys::kName,
331 localized_name);
332 }
333 if (!localized_description.empty()) {
334 localized_manifest->SetString(extension_manifest_keys::kDescription,
335 localized_description);
336 }
337 }
338
339 return Extension::Create(
340 FilePath(),
341 Extension::INTERNAL,
342 localized_manifest.get() ? *localized_manifest.get() : *manifest,
[email protected]c422a862012-07-31 15:46:13343 flags,
[email protected]c82da8c42012-06-08 19:49:11344 id,
345 error);
346}
347
[email protected]619f86182012-07-03 21:30:18348ExtensionInstallPrompt::ExtensionInstallPrompt(
349 gfx::NativeWindow parent,
350 content::PageNavigator* navigator,
351 Profile* profile)
[email protected]16798da832012-08-30 20:46:04352 : record_oauth2_grant_(false),
[email protected]619f86182012-07-03 21:30:18353 parent_(parent),
354 navigator_(navigator),
[email protected]c82da8c42012-06-08 19:49:11355 ui_loop_(MessageLoop::current()),
356 extension_(NULL),
[email protected]619f86182012-07-03 21:30:18357 install_ui_(ExtensionInstallUI::Create(profile)),
[email protected]c82da8c42012-06-08 19:49:11358 delegate_(NULL),
[email protected]fc5077942012-08-15 21:37:59359 prompt_(profile, UNSET_PROMPT_TYPE),
[email protected]c82da8c42012-06-08 19:49:11360 prompt_type_(UNSET_PROMPT_TYPE),
361 ALLOW_THIS_IN_INITIALIZER_LIST(tracker_(this)) {
362}
363
364ExtensionInstallPrompt::~ExtensionInstallPrompt() {
365}
366
367void ExtensionInstallPrompt::ConfirmBundleInstall(
368 extensions::BundleInstaller* bundle,
[email protected]c2e66e12012-06-27 06:27:06369 const PermissionSet* permissions) {
[email protected]c82da8c42012-06-08 19:49:11370 DCHECK(ui_loop_ == MessageLoop::current());
371 bundle_ = bundle;
372 permissions_ = permissions;
373 delegate_ = bundle;
374 prompt_type_ = BUNDLE_INSTALL_PROMPT;
375
[email protected]b70a2d92012-06-28 19:51:21376 FetchOAuthIssueAdviceIfNeeded();
[email protected]c82da8c42012-06-08 19:49:11377}
378
[email protected]734bcec2012-10-08 20:29:05379void ExtensionInstallPrompt::ConfirmStandaloneInstall(
[email protected]c82da8c42012-06-08 19:49:11380 Delegate* delegate,
381 const Extension* extension,
382 SkBitmap* icon,
383 const ExtensionInstallPrompt::Prompt& prompt) {
384 DCHECK(ui_loop_ == MessageLoop::current());
385 extension_ = extension;
386 permissions_ = extension->GetActivePermissions();
387 delegate_ = delegate;
388 prompt_ = prompt;
[email protected]734bcec2012-10-08 20:29:05389 prompt_type_ = prompt.type();
[email protected]c82da8c42012-06-08 19:49:11390
391 SetIcon(icon);
[email protected]b70a2d92012-06-28 19:51:21392 FetchOAuthIssueAdviceIfNeeded();
[email protected]c82da8c42012-06-08 19:49:11393}
394
[email protected]af6efb22012-10-12 02:23:05395void ExtensionInstallPrompt::ConfirmWebstoreInstall(
396 Delegate* delegate,
397 const Extension* extension,
398 const SkBitmap* icon,
399 const ShowDialogCallback& show_dialog_callback) {
[email protected]c82da8c42012-06-08 19:49:11400 // SetIcon requires |extension_| to be set. ConfirmInstall will setup the
401 // remaining fields.
402 extension_ = extension;
403 SetIcon(icon);
[email protected]af6efb22012-10-12 02:23:05404 ConfirmInstall(delegate, extension, show_dialog_callback);
[email protected]c82da8c42012-06-08 19:49:11405}
406
[email protected]af6efb22012-10-12 02:23:05407void ExtensionInstallPrompt::ConfirmInstall(
408 Delegate* delegate,
409 const Extension* extension,
410 const ShowDialogCallback& show_dialog_callback) {
[email protected]c82da8c42012-06-08 19:49:11411 DCHECK(ui_loop_ == MessageLoop::current());
412 extension_ = extension;
413 permissions_ = extension->GetActivePermissions();
414 delegate_ = delegate;
415 prompt_type_ = INSTALL_PROMPT;
[email protected]af6efb22012-10-12 02:23:05416 show_dialog_callback_ = show_dialog_callback;
[email protected]c82da8c42012-06-08 19:49:11417
418 // We special-case themes to not show any confirm UI. Instead they are
419 // immediately installed, and then we show an infobar (see OnInstallSuccess)
420 // to allow the user to revert if they don't like it.
421 //
422 // We don't do this in the case where off-store extension installs are
423 // disabled because in that case, we don't show the dangerous download UI, so
424 // we need the UI confirmation.
425 if (extension->is_theme()) {
426 if (extension->from_webstore() ||
[email protected]544471a2012-10-13 05:27:09427 extensions::FeatureSwitch::easy_off_store_install()->IsEnabled()) {
[email protected]c82da8c42012-06-08 19:49:11428 delegate->InstallUIProceed();
429 return;
430 }
431 }
432
433 LoadImageIfNeeded();
434}
435
436void ExtensionInstallPrompt::ConfirmReEnable(Delegate* delegate,
437 const Extension* extension) {
438 DCHECK(ui_loop_ == MessageLoop::current());
439 extension_ = extension;
440 permissions_ = extension->GetActivePermissions();
441 delegate_ = delegate;
442 prompt_type_ = RE_ENABLE_PROMPT;
443
444 LoadImageIfNeeded();
445}
446
[email protected]612a1cb12012-10-17 13:18:03447void ExtensionInstallPrompt::ConfirmExternalInstall(
448 Delegate* delegate, const Extension* extension) {
449 DCHECK(ui_loop_ == MessageLoop::current());
450 extension_ = extension;
451 permissions_ = extension->GetActivePermissions();
452 delegate_ = delegate;
453 prompt_type_ = EXTERNAL_INSTALL_PROMPT;
454
455 LoadImageIfNeeded();
456}
457
[email protected]c82da8c42012-06-08 19:49:11458void ExtensionInstallPrompt::ConfirmPermissions(
459 Delegate* delegate,
460 const Extension* extension,
[email protected]c2e66e12012-06-27 06:27:06461 const PermissionSet* permissions) {
[email protected]c82da8c42012-06-08 19:49:11462 DCHECK(ui_loop_ == MessageLoop::current());
463 extension_ = extension;
464 permissions_ = permissions;
465 delegate_ = delegate;
466 prompt_type_ = PERMISSIONS_PROMPT;
467
468 LoadImageIfNeeded();
469}
470
[email protected]f746b3f2012-07-03 17:53:37471void ExtensionInstallPrompt::ConfirmIssueAdvice(
472 Delegate* delegate,
473 const Extension* extension,
474 const IssueAdviceInfo& issue_advice) {
475 DCHECK(ui_loop_ == MessageLoop::current());
476 extension_ = extension;
477 delegate_ = delegate;
478 prompt_type_ = PERMISSIONS_PROMPT;
479
480 record_oauth2_grant_ = true;
481 prompt_.SetOAuthIssueAdvice(issue_advice);
482
483 LoadImageIfNeeded();
484}
485
[email protected]c82da8c42012-06-08 19:49:11486void ExtensionInstallPrompt::OnInstallSuccess(const Extension* extension,
487 SkBitmap* icon) {
488 extension_ = extension;
489 SetIcon(icon);
490
491 install_ui_->OnInstallSuccess(extension, &icon_);
492}
493
[email protected]bf3d9df2012-07-24 23:20:27494void ExtensionInstallPrompt::OnInstallFailure(
495 const extensions::CrxInstallerError& error) {
[email protected]c82da8c42012-06-08 19:49:11496 install_ui_->OnInstallFailure(error);
497}
498
499void ExtensionInstallPrompt::SetIcon(const SkBitmap* image) {
500 if (image)
501 icon_ = *image;
502 else
503 icon_ = SkBitmap();
[email protected]dd46a4ce2012-09-15 10:50:50504 if (icon_.empty()) {
505 // Let's set default icon bitmap whose size is equal to the default icon's
506 // pixel size under maximal supported scale factor. If the bitmap is larger
507 // than the one we need, it will be scaled down by the ui code.
508 icon_ = GetDefaultIconBitmapForMaxScaleFactor(extension_->is_app());
509 }
[email protected]c82da8c42012-06-08 19:49:11510}
511
512void ExtensionInstallPrompt::OnImageLoaded(const gfx::Image& image,
513 const std::string& extension_id,
514 int index) {
515 SetIcon(image.IsEmpty() ? NULL : image.ToSkBitmap());
[email protected]b70a2d92012-06-28 19:51:21516 FetchOAuthIssueAdviceIfNeeded();
[email protected]c82da8c42012-06-08 19:49:11517}
518
519void ExtensionInstallPrompt::LoadImageIfNeeded() {
520 // Bundle install prompts do not have an icon.
521 if (!icon_.empty()) {
[email protected]b70a2d92012-06-28 19:51:21522 FetchOAuthIssueAdviceIfNeeded();
[email protected]c82da8c42012-06-08 19:49:11523 return;
524 }
525
526 // Load the image asynchronously. For the response, check OnImageLoaded.
527 ExtensionResource image =
[email protected]faf87192012-08-17 00:07:59528 extension_->GetIconResource(extension_misc::EXTENSION_ICON_LARGE,
[email protected]c82da8c42012-06-08 19:49:11529 ExtensionIconSet::MATCH_BIGGER);
[email protected]dd46a4ce2012-09-15 10:50:50530 // Load the icon whose pixel size is large enough to be displayed under
531 // maximal supported scale factor. UI code will scale the icon down if needed.
532 // TODO(tbarzic): We should use IconImage here and load the required bitmap
533 // lazily.
534 int pixel_size = GetSizeForMaxScaleFactor(kIconSize);
[email protected]c82da8c42012-06-08 19:49:11535 tracker_.LoadImage(extension_, image,
[email protected]dd46a4ce2012-09-15 10:50:50536 gfx::Size(pixel_size, pixel_size),
[email protected]c82da8c42012-06-08 19:49:11537 ImageLoadingTracker::DONT_CACHE);
538}
539
[email protected]b70a2d92012-06-28 19:51:21540void ExtensionInstallPrompt::FetchOAuthIssueAdviceIfNeeded() {
[email protected]668ed2c2012-09-12 10:52:41541 // |extension_| may be NULL, e.g. in the bundle install case.
542 if (!extension_ ||
[email protected]b70a2d92012-06-28 19:51:21543 prompt_type_ == BUNDLE_INSTALL_PROMPT ||
[email protected]668ed2c2012-09-12 10:52:41544 prompt_type_ == INLINE_INSTALL_PROMPT ||
[email protected]612a1cb12012-10-17 13:18:03545 prompt_type_ == EXTERNAL_INSTALL_PROMPT ||
[email protected]668ed2c2012-09-12 10:52:41546 prompt_.GetOAuthIssueCount() != 0U) {
547 ShowConfirmation();
548 return;
549 }
550
551 const Extension::OAuth2Info& oauth2_info = extension_->oauth2_info();
552 if (oauth2_info.client_id.empty() ||
553 oauth2_info.scopes.empty()) {
[email protected]b70a2d92012-06-28 19:51:21554 ShowConfirmation();
555 return;
556 }
557
[email protected]7cac5262012-09-26 17:32:25558 Profile* profile = install_ui_->profile();
[email protected]b70a2d92012-06-28 19:51:21559 TokenService* token_service = TokenServiceFactory::GetForProfile(profile);
[email protected]b70a2d92012-06-28 19:51:21560
561 token_flow_.reset(new OAuth2MintTokenFlow(
562 profile->GetRequestContext(),
563 this,
564 OAuth2MintTokenFlow::Parameters(
565 token_service->GetOAuth2LoginRefreshToken(),
566 extension_->id(),
567 oauth2_info.client_id,
[email protected]d4a37f1c2012-07-09 21:36:13568 oauth2_info.scopes,
[email protected]b70a2d92012-06-28 19:51:21569 OAuth2MintTokenFlow::MODE_ISSUE_ADVICE)));
570 token_flow_->Start();
571}
572
573void ExtensionInstallPrompt::OnIssueAdviceSuccess(
574 const IssueAdviceInfo& advice_info) {
575 prompt_.SetOAuthIssueAdvice(advice_info);
576 record_oauth2_grant_ = true;
577 ShowConfirmation();
578}
579
580void ExtensionInstallPrompt::OnMintTokenFailure(
581 const GoogleServiceAuthError& error) {
582 ShowConfirmation();
583}
584
[email protected]c82da8c42012-06-08 19:49:11585void ExtensionInstallPrompt::ShowConfirmation() {
586 prompt_.set_type(prompt_type_);
[email protected]f746b3f2012-07-03 17:53:37587
[email protected]bebe1d02012-08-02 20:17:09588 if (permissions_) {
[email protected]dcb1c3912012-10-16 01:31:44589 Extension::Type extension_type = extension_ ? extension_->GetType() :
590 Extension::TYPE_UNKNOWN;
[email protected]a6e5c9b2012-08-09 04:06:25591 prompt_.SetPermissions(permissions_->GetWarningMessages(extension_type));
[email protected]bebe1d02012-08-02 20:17:09592 }
[email protected]c82da8c42012-06-08 19:49:11593
594 switch (prompt_type_) {
595 case PERMISSIONS_PROMPT:
596 case RE_ENABLE_PROMPT:
597 case INLINE_INSTALL_PROMPT:
[email protected]612a1cb12012-10-17 13:18:03598 case EXTERNAL_INSTALL_PROMPT:
[email protected]c82da8c42012-06-08 19:49:11599 case INSTALL_PROMPT: {
600 prompt_.set_extension(extension_);
601 prompt_.set_icon(gfx::Image(icon_));
[email protected]c82da8c42012-06-08 19:49:11602 break;
603 }
604 case BUNDLE_INSTALL_PROMPT: {
605 prompt_.set_bundle(bundle_);
[email protected]c82da8c42012-06-08 19:49:11606 break;
607 }
608 default:
609 NOTREACHED() << "Unknown message";
[email protected]af6efb22012-10-12 02:23:05610 return;
[email protected]c82da8c42012-06-08 19:49:11611 }
[email protected]af6efb22012-10-12 02:23:05612
613 if (AutoConfirmPrompt(delegate_))
614 return;
615
[email protected]db854262012-10-13 06:59:44616 if (show_dialog_callback_.is_null())
617 GetDefaultShowDialogCallback().Run(parent_, navigator_, delegate_, prompt_);
618 else
619 show_dialog_callback_.Run(parent_, navigator_, delegate_, prompt_);
[email protected]c82da8c42012-06-08 19:49:11620}
[email protected]b70a2d92012-06-28 19:51:21621
[email protected]619f86182012-07-03 21:30:18622namespace chrome {
623
624ExtensionInstallPrompt* CreateExtensionInstallPromptWithBrowser(
625 Browser* browser) {
626 // |browser| can be NULL in unit tests.
627 if (!browser)
628 return new ExtensionInstallPrompt(NULL, NULL, NULL);
629 gfx::NativeWindow parent =
630 browser->window() ? browser->window()->GetNativeWindow() : NULL;
631 return new ExtensionInstallPrompt(parent, browser, browser->profile());
632}
633
634} // namespace chrome