blob: 7c4c54429e304aac9bef45d1673b31156a967169 [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
47static const int kTitleIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
48 0, // The regular install prompt depends on what's being installed.
49 IDS_EXTENSION_INLINE_INSTALL_PROMPT_TITLE,
50 IDS_EXTENSION_INSTALL_PROMPT_TITLE,
51 IDS_EXTENSION_RE_ENABLE_PROMPT_TITLE,
52 IDS_EXTENSION_PERMISSIONS_PROMPT_TITLE
53};
54static const int kHeadingIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
55 IDS_EXTENSION_INSTALL_PROMPT_HEADING,
56 0, // Inline installs use the extension name.
57 0, // Heading for bundle installs depends on the bundle contents.
58 IDS_EXTENSION_RE_ENABLE_PROMPT_HEADING,
59 IDS_EXTENSION_PERMISSIONS_PROMPT_HEADING
60};
61static const int kAcceptButtonIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
62 IDS_EXTENSION_PROMPT_INSTALL_BUTTON,
63 IDS_EXTENSION_PROMPT_INSTALL_BUTTON,
64 IDS_EXTENSION_PROMPT_INSTALL_BUTTON,
65 IDS_EXTENSION_PROMPT_RE_ENABLE_BUTTON,
66 IDS_EXTENSION_PROMPT_PERMISSIONS_BUTTON
67};
68static const int kAbortButtonIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
69 0, // These all use the platform's default cancel label.
70 0,
71 0,
72 0,
73 IDS_EXTENSION_PROMPT_PERMISSIONS_ABORT_BUTTON
74};
75static const int kPermissionsHeaderIds[
76 ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
77 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
78 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
79 IDS_EXTENSION_PROMPT_THESE_WILL_HAVE_ACCESS_TO,
80 IDS_EXTENSION_PROMPT_WILL_NOW_HAVE_ACCESS_TO,
81 IDS_EXTENSION_PROMPT_WANTS_ACCESS_TO,
82};
[email protected]fc5077942012-08-15 21:37:5983static const int kOAuthHeaderIds[
84 ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
85 IDS_EXTENSION_PROMPT_OAUTH_HEADER,
86 0, // Inline installs don't show OAuth permissions.
87 0, // Bundle installs don't show OAuth permissions.
88 IDS_EXTENSION_PROMPT_OAUTH_REENABLE_HEADER,
89 IDS_EXTENSION_PROMPT_OAUTH_PERMISSIONS_HEADER,
90};
[email protected]c82da8c42012-06-08 19:49:1191
92namespace {
93
94// Size of extension icon in top left of dialog.
95const int kIconSize = 69;
96
[email protected]dd46a4ce2012-09-15 10:50:5097// Returns pixel size under maximal scale factor for the icon whose device
98// independent size is |size_in_dip|
99int GetSizeForMaxScaleFactor(int size_in_dip) {
100 std::vector<ui::ScaleFactor> supported_scale_factors =
101 ui::GetSupportedScaleFactors();
102 // Scale factors are in ascending order, so the last one is the one we need.
103 ui::ScaleFactor max_scale_factor = supported_scale_factors.back();
104 float max_scale_factor_scale = ui::GetScaleFactorScale(max_scale_factor);
105
106 return static_cast<int>(size_in_dip * max_scale_factor_scale);
107}
108
109// Returns bitmap for the default icon with size equal to the default icon's
110// pixel size under maximal supported scale factor.
111SkBitmap GetDefaultIconBitmapForMaxScaleFactor(bool is_app) {
112 std::vector<ui::ScaleFactor> supported_scale_factors =
113 ui::GetSupportedScaleFactors();
114 // Scale factors are in ascending order, so the last one is the one we need.
115 ui::ScaleFactor max_scale_factor =
116 supported_scale_factors[supported_scale_factors.size() - 1];
117
118 return Extension::GetDefaultIcon(is_app).
119 GetRepresentation(max_scale_factor).sk_bitmap();
120}
121
[email protected]af6efb22012-10-12 02:23:05122// If auto confirm is enabled then posts a task to proceed with or cancel the
123// install and returns true. Otherwise returns false.
124bool AutoConfirmPrompt(ExtensionInstallPrompt::Delegate* delegate) {
125 const CommandLine* cmdline = CommandLine::ForCurrentProcess();
126 if (!cmdline->HasSwitch(switches::kAppsGalleryInstallAutoConfirmForTests))
127 return false;
128 std::string value = cmdline->GetSwitchValueASCII(
129 switches::kAppsGalleryInstallAutoConfirmForTests);
130
131 // We use PostTask instead of calling the delegate directly here, because in
132 // the real implementations it's highly likely the message loop will be
133 // pumping a few times before the user clicks accept or cancel.
134 if (value == "accept") {
135 MessageLoop::current()->PostTask(
136 FROM_HERE,
137 base::Bind(&ExtensionInstallPrompt::Delegate::InstallUIProceed,
138 base::Unretained(delegate)));
139 return true;
140 }
141
142 if (value == "cancel") {
143 MessageLoop::current()->PostTask(
144 FROM_HERE,
145 base::Bind(&ExtensionInstallPrompt::Delegate::InstallUIAbort,
146 base::Unretained(delegate),
147 true));
148 return true;
149 }
150
151 NOTREACHED();
152 return false;
153}
154
[email protected]c82da8c42012-06-08 19:49:11155} // namespace
156
[email protected]fc5077942012-08-15 21:37:59157ExtensionInstallPrompt::Prompt::Prompt(Profile* profile, PromptType type)
[email protected]c82da8c42012-06-08 19:49:11158 : type_(type),
159 extension_(NULL),
160 bundle_(NULL),
161 average_rating_(0.0),
[email protected]fc5077942012-08-15 21:37:59162 rating_count_(0),
163 profile_(profile) {
[email protected]c82da8c42012-06-08 19:49:11164}
165
166ExtensionInstallPrompt::Prompt::~Prompt() {
167}
168
169void ExtensionInstallPrompt::Prompt::SetPermissions(
170 const std::vector<string16>& permissions) {
171 permissions_ = permissions;
172}
173
[email protected]b70a2d92012-06-28 19:51:21174void ExtensionInstallPrompt::Prompt::SetOAuthIssueAdvice(
175 const IssueAdviceInfo& issue_advice) {
176 oauth_issue_advice_ = issue_advice;
177}
178
[email protected]c82da8c42012-06-08 19:49:11179void ExtensionInstallPrompt::Prompt::SetInlineInstallWebstoreData(
180 const std::string& localized_user_count,
181 double average_rating,
182 int rating_count) {
183 CHECK_EQ(INLINE_INSTALL_PROMPT, type_);
184 localized_user_count_ = localized_user_count;
185 average_rating_ = average_rating;
186 rating_count_ = rating_count;
187}
188
189string16 ExtensionInstallPrompt::Prompt::GetDialogTitle() const {
[email protected]c82da8c42012-06-08 19:49:11190 int resource_id = kTitleIds[type_];
191
192 if (type_ == INSTALL_PROMPT) {
193 if (extension_->is_app())
194 resource_id = IDS_EXTENSION_INSTALL_APP_PROMPT_TITLE;
195 else if (extension_->is_theme())
196 resource_id = IDS_EXTENSION_INSTALL_THEME_PROMPT_TITLE;
197 else
198 resource_id = IDS_EXTENSION_INSTALL_EXTENSION_PROMPT_TITLE;
199 }
200
201 return l10n_util::GetStringUTF16(resource_id);
202}
203
204string16 ExtensionInstallPrompt::Prompt::GetHeading() const {
205 if (type_ == INLINE_INSTALL_PROMPT) {
206 return UTF8ToUTF16(extension_->name());
207 } else if (type_ == BUNDLE_INSTALL_PROMPT) {
208 return bundle_->GetHeadingTextFor(BundleInstaller::Item::STATE_PENDING);
209 } else {
210 return l10n_util::GetStringFUTF16(
211 kHeadingIds[type_], UTF8ToUTF16(extension_->name()));
212 }
213}
214
215string16 ExtensionInstallPrompt::Prompt::GetAcceptButtonLabel() const {
216 return l10n_util::GetStringUTF16(kAcceptButtonIds[type_]);
217}
218
219bool ExtensionInstallPrompt::Prompt::HasAbortButtonLabel() const {
220 return kAbortButtonIds[type_] > 0;
221}
222
223string16 ExtensionInstallPrompt::Prompt::GetAbortButtonLabel() const {
224 CHECK(HasAbortButtonLabel());
225 return l10n_util::GetStringUTF16(kAbortButtonIds[type_]);
226}
227
228string16 ExtensionInstallPrompt::Prompt::GetPermissionsHeading() const {
229 return l10n_util::GetStringUTF16(kPermissionsHeaderIds[type_]);
230}
231
[email protected]813475e2012-07-02 23:54:18232string16 ExtensionInstallPrompt::Prompt::GetOAuthHeading() const {
[email protected]fc5077942012-08-15 21:37:59233 string16 username(ASCIIToUTF16("[email protected]"));
234 // |profile_| can be NULL in unit tests.
235 if (profile_) {
236 username = UTF8ToUTF16(profile_->GetPrefs()->GetString(
237 prefs::kGoogleServicesUsername));
238 }
239 int resource_id = kOAuthHeaderIds[type_];
240 return l10n_util::GetStringFUTF16(resource_id, username);
[email protected]813475e2012-07-02 23:54:18241}
242
[email protected]c82da8c42012-06-08 19:49:11243void ExtensionInstallPrompt::Prompt::AppendRatingStars(
244 StarAppender appender, void* data) const {
245 CHECK(appender);
246 CHECK_EQ(INLINE_INSTALL_PROMPT, type_);
247 int rating_integer = floor(average_rating_);
248 double rating_fractional = average_rating_ - rating_integer;
249
250 if (rating_fractional > 0.66) {
251 rating_integer++;
252 }
253
254 if (rating_fractional < 0.33 || rating_fractional > 0.66) {
255 rating_fractional = 0;
256 }
257
258 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
259 int i;
260 for (i = 0; i < rating_integer; i++) {
261 appender(rb.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_ON), data);
262 }
263 if (rating_fractional) {
264 appender(rb.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_HALF_LEFT), data);
265 i++;
266 }
267 for (; i < kMaxExtensionRating; i++) {
268 appender(rb.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_OFF), data);
269 }
270}
271
272string16 ExtensionInstallPrompt::Prompt::GetRatingCount() const {
273 CHECK_EQ(INLINE_INSTALL_PROMPT, type_);
274 return l10n_util::GetStringFUTF16(
275 IDS_EXTENSION_RATING_COUNT,
276 UTF8ToUTF16(base::IntToString(rating_count_)));
277}
278
279string16 ExtensionInstallPrompt::Prompt::GetUserCount() const {
280 CHECK_EQ(INLINE_INSTALL_PROMPT, type_);
281 return l10n_util::GetStringFUTF16(
282 IDS_EXTENSION_USER_COUNT,
283 UTF8ToUTF16(localized_user_count_));
284}
285
286size_t ExtensionInstallPrompt::Prompt::GetPermissionCount() const {
287 return permissions_.size();
288}
289
290string16 ExtensionInstallPrompt::Prompt::GetPermission(size_t index) const {
291 CHECK_LT(index, permissions_.size());
[email protected]ef2654e42012-08-11 03:57:56292 return permissions_[index];
[email protected]c82da8c42012-06-08 19:49:11293}
294
[email protected]b70a2d92012-06-28 19:51:21295size_t ExtensionInstallPrompt::Prompt::GetOAuthIssueCount() const {
296 return oauth_issue_advice_.size();
297}
298
299const IssueAdviceInfoEntry& ExtensionInstallPrompt::Prompt::GetOAuthIssue(
300 size_t index) const {
301 CHECK_LT(index, oauth_issue_advice_.size());
302 return oauth_issue_advice_[index];
303}
304
[email protected]c82da8c42012-06-08 19:49:11305// static
306scoped_refptr<Extension>
307 ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
308 const DictionaryValue* manifest,
[email protected]c422a862012-07-31 15:46:13309 int flags,
[email protected]c82da8c42012-06-08 19:49:11310 const std::string& id,
311 const std::string& localized_name,
312 const std::string& localized_description,
313 std::string* error) {
314 scoped_ptr<DictionaryValue> localized_manifest;
315 if (!localized_name.empty() || !localized_description.empty()) {
316 localized_manifest.reset(manifest->DeepCopy());
317 if (!localized_name.empty()) {
318 localized_manifest->SetString(extension_manifest_keys::kName,
319 localized_name);
320 }
321 if (!localized_description.empty()) {
322 localized_manifest->SetString(extension_manifest_keys::kDescription,
323 localized_description);
324 }
325 }
326
327 return Extension::Create(
328 FilePath(),
329 Extension::INTERNAL,
330 localized_manifest.get() ? *localized_manifest.get() : *manifest,
[email protected]c422a862012-07-31 15:46:13331 flags,
[email protected]c82da8c42012-06-08 19:49:11332 id,
333 error);
334}
335
[email protected]619f86182012-07-03 21:30:18336ExtensionInstallPrompt::ExtensionInstallPrompt(
337 gfx::NativeWindow parent,
338 content::PageNavigator* navigator,
339 Profile* profile)
[email protected]16798da832012-08-30 20:46:04340 : record_oauth2_grant_(false),
[email protected]619f86182012-07-03 21:30:18341 parent_(parent),
342 navigator_(navigator),
[email protected]c82da8c42012-06-08 19:49:11343 ui_loop_(MessageLoop::current()),
344 extension_(NULL),
[email protected]619f86182012-07-03 21:30:18345 install_ui_(ExtensionInstallUI::Create(profile)),
[email protected]c82da8c42012-06-08 19:49:11346 delegate_(NULL),
[email protected]fc5077942012-08-15 21:37:59347 prompt_(profile, UNSET_PROMPT_TYPE),
[email protected]c82da8c42012-06-08 19:49:11348 prompt_type_(UNSET_PROMPT_TYPE),
349 ALLOW_THIS_IN_INITIALIZER_LIST(tracker_(this)) {
350}
351
352ExtensionInstallPrompt::~ExtensionInstallPrompt() {
353}
354
355void ExtensionInstallPrompt::ConfirmBundleInstall(
356 extensions::BundleInstaller* bundle,
[email protected]c2e66e12012-06-27 06:27:06357 const PermissionSet* permissions) {
[email protected]c82da8c42012-06-08 19:49:11358 DCHECK(ui_loop_ == MessageLoop::current());
359 bundle_ = bundle;
360 permissions_ = permissions;
361 delegate_ = bundle;
362 prompt_type_ = BUNDLE_INSTALL_PROMPT;
363
[email protected]b70a2d92012-06-28 19:51:21364 FetchOAuthIssueAdviceIfNeeded();
[email protected]c82da8c42012-06-08 19:49:11365}
366
[email protected]734bcec2012-10-08 20:29:05367void ExtensionInstallPrompt::ConfirmStandaloneInstall(
[email protected]c82da8c42012-06-08 19:49:11368 Delegate* delegate,
369 const Extension* extension,
370 SkBitmap* icon,
371 const ExtensionInstallPrompt::Prompt& prompt) {
372 DCHECK(ui_loop_ == MessageLoop::current());
373 extension_ = extension;
374 permissions_ = extension->GetActivePermissions();
375 delegate_ = delegate;
376 prompt_ = prompt;
[email protected]734bcec2012-10-08 20:29:05377 prompt_type_ = prompt.type();
[email protected]c82da8c42012-06-08 19:49:11378
379 SetIcon(icon);
[email protected]b70a2d92012-06-28 19:51:21380 FetchOAuthIssueAdviceIfNeeded();
[email protected]c82da8c42012-06-08 19:49:11381}
382
[email protected]af6efb22012-10-12 02:23:05383void ExtensionInstallPrompt::ConfirmWebstoreInstall(
384 Delegate* delegate,
385 const Extension* extension,
386 const SkBitmap* icon,
387 const ShowDialogCallback& show_dialog_callback) {
[email protected]c82da8c42012-06-08 19:49:11388 // SetIcon requires |extension_| to be set. ConfirmInstall will setup the
389 // remaining fields.
390 extension_ = extension;
391 SetIcon(icon);
[email protected]af6efb22012-10-12 02:23:05392 ConfirmInstall(delegate, extension, show_dialog_callback);
[email protected]c82da8c42012-06-08 19:49:11393}
394
[email protected]af6efb22012-10-12 02:23:05395void ExtensionInstallPrompt::ConfirmInstall(
396 Delegate* delegate,
397 const Extension* extension,
398 const ShowDialogCallback& show_dialog_callback) {
[email protected]c82da8c42012-06-08 19:49:11399 DCHECK(ui_loop_ == MessageLoop::current());
400 extension_ = extension;
401 permissions_ = extension->GetActivePermissions();
402 delegate_ = delegate;
403 prompt_type_ = INSTALL_PROMPT;
[email protected]af6efb22012-10-12 02:23:05404 show_dialog_callback_ = show_dialog_callback;
405 DCHECK(!show_dialog_callback_.is_null());
[email protected]c82da8c42012-06-08 19:49:11406
407 // We special-case themes to not show any confirm UI. Instead they are
408 // immediately installed, and then we show an infobar (see OnInstallSuccess)
409 // to allow the user to revert if they don't like it.
410 //
411 // We don't do this in the case where off-store extension installs are
412 // disabled because in that case, we don't show the dangerous download UI, so
413 // we need the UI confirmation.
414 if (extension->is_theme()) {
415 if (extension->from_webstore() ||
[email protected]544471a2012-10-13 05:27:09416 extensions::FeatureSwitch::easy_off_store_install()->IsEnabled()) {
[email protected]c82da8c42012-06-08 19:49:11417 delegate->InstallUIProceed();
418 return;
419 }
420 }
421
422 LoadImageIfNeeded();
423}
424
425void ExtensionInstallPrompt::ConfirmReEnable(Delegate* delegate,
426 const Extension* extension) {
427 DCHECK(ui_loop_ == MessageLoop::current());
428 extension_ = extension;
429 permissions_ = extension->GetActivePermissions();
430 delegate_ = delegate;
431 prompt_type_ = RE_ENABLE_PROMPT;
432
433 LoadImageIfNeeded();
434}
435
436void ExtensionInstallPrompt::ConfirmPermissions(
437 Delegate* delegate,
438 const Extension* extension,
[email protected]c2e66e12012-06-27 06:27:06439 const PermissionSet* permissions) {
[email protected]c82da8c42012-06-08 19:49:11440 DCHECK(ui_loop_ == MessageLoop::current());
441 extension_ = extension;
442 permissions_ = permissions;
443 delegate_ = delegate;
444 prompt_type_ = PERMISSIONS_PROMPT;
445
446 LoadImageIfNeeded();
447}
448
[email protected]f746b3f2012-07-03 17:53:37449void ExtensionInstallPrompt::ConfirmIssueAdvice(
450 Delegate* delegate,
451 const Extension* extension,
452 const IssueAdviceInfo& issue_advice) {
453 DCHECK(ui_loop_ == MessageLoop::current());
454 extension_ = extension;
455 delegate_ = delegate;
456 prompt_type_ = PERMISSIONS_PROMPT;
457
458 record_oauth2_grant_ = true;
459 prompt_.SetOAuthIssueAdvice(issue_advice);
460
461 LoadImageIfNeeded();
462}
463
[email protected]c82da8c42012-06-08 19:49:11464void ExtensionInstallPrompt::OnInstallSuccess(const Extension* extension,
465 SkBitmap* icon) {
466 extension_ = extension;
467 SetIcon(icon);
468
469 install_ui_->OnInstallSuccess(extension, &icon_);
470}
471
[email protected]bf3d9df2012-07-24 23:20:27472void ExtensionInstallPrompt::OnInstallFailure(
473 const extensions::CrxInstallerError& error) {
[email protected]c82da8c42012-06-08 19:49:11474 install_ui_->OnInstallFailure(error);
475}
476
477void ExtensionInstallPrompt::SetIcon(const SkBitmap* image) {
478 if (image)
479 icon_ = *image;
480 else
481 icon_ = SkBitmap();
[email protected]dd46a4ce2012-09-15 10:50:50482 if (icon_.empty()) {
483 // Let's set default icon bitmap whose size is equal to the default icon's
484 // pixel size under maximal supported scale factor. If the bitmap is larger
485 // than the one we need, it will be scaled down by the ui code.
486 icon_ = GetDefaultIconBitmapForMaxScaleFactor(extension_->is_app());
487 }
[email protected]c82da8c42012-06-08 19:49:11488}
489
490void ExtensionInstallPrompt::OnImageLoaded(const gfx::Image& image,
491 const std::string& extension_id,
492 int index) {
493 SetIcon(image.IsEmpty() ? NULL : image.ToSkBitmap());
[email protected]b70a2d92012-06-28 19:51:21494 FetchOAuthIssueAdviceIfNeeded();
[email protected]c82da8c42012-06-08 19:49:11495}
496
497void ExtensionInstallPrompt::LoadImageIfNeeded() {
498 // Bundle install prompts do not have an icon.
499 if (!icon_.empty()) {
[email protected]b70a2d92012-06-28 19:51:21500 FetchOAuthIssueAdviceIfNeeded();
[email protected]c82da8c42012-06-08 19:49:11501 return;
502 }
503
504 // Load the image asynchronously. For the response, check OnImageLoaded.
505 ExtensionResource image =
[email protected]faf87192012-08-17 00:07:59506 extension_->GetIconResource(extension_misc::EXTENSION_ICON_LARGE,
[email protected]c82da8c42012-06-08 19:49:11507 ExtensionIconSet::MATCH_BIGGER);
[email protected]dd46a4ce2012-09-15 10:50:50508 // Load the icon whose pixel size is large enough to be displayed under
509 // maximal supported scale factor. UI code will scale the icon down if needed.
510 // TODO(tbarzic): We should use IconImage here and load the required bitmap
511 // lazily.
512 int pixel_size = GetSizeForMaxScaleFactor(kIconSize);
[email protected]c82da8c42012-06-08 19:49:11513 tracker_.LoadImage(extension_, image,
[email protected]dd46a4ce2012-09-15 10:50:50514 gfx::Size(pixel_size, pixel_size),
[email protected]c82da8c42012-06-08 19:49:11515 ImageLoadingTracker::DONT_CACHE);
516}
517
[email protected]b70a2d92012-06-28 19:51:21518void ExtensionInstallPrompt::FetchOAuthIssueAdviceIfNeeded() {
[email protected]668ed2c2012-09-12 10:52:41519 // |extension_| may be NULL, e.g. in the bundle install case.
520 if (!extension_ ||
[email protected]b70a2d92012-06-28 19:51:21521 prompt_type_ == BUNDLE_INSTALL_PROMPT ||
[email protected]668ed2c2012-09-12 10:52:41522 prompt_type_ == INLINE_INSTALL_PROMPT ||
523 prompt_.GetOAuthIssueCount() != 0U) {
524 ShowConfirmation();
525 return;
526 }
527
528 const Extension::OAuth2Info& oauth2_info = extension_->oauth2_info();
529 if (oauth2_info.client_id.empty() ||
530 oauth2_info.scopes.empty()) {
[email protected]b70a2d92012-06-28 19:51:21531 ShowConfirmation();
532 return;
533 }
534
[email protected]7cac5262012-09-26 17:32:25535 Profile* profile = install_ui_->profile();
[email protected]b70a2d92012-06-28 19:51:21536 TokenService* token_service = TokenServiceFactory::GetForProfile(profile);
[email protected]b70a2d92012-06-28 19:51:21537
538 token_flow_.reset(new OAuth2MintTokenFlow(
539 profile->GetRequestContext(),
540 this,
541 OAuth2MintTokenFlow::Parameters(
542 token_service->GetOAuth2LoginRefreshToken(),
543 extension_->id(),
544 oauth2_info.client_id,
[email protected]d4a37f1c2012-07-09 21:36:13545 oauth2_info.scopes,
[email protected]b70a2d92012-06-28 19:51:21546 OAuth2MintTokenFlow::MODE_ISSUE_ADVICE)));
547 token_flow_->Start();
548}
549
550void ExtensionInstallPrompt::OnIssueAdviceSuccess(
551 const IssueAdviceInfo& advice_info) {
552 prompt_.SetOAuthIssueAdvice(advice_info);
553 record_oauth2_grant_ = true;
554 ShowConfirmation();
555}
556
557void ExtensionInstallPrompt::OnMintTokenFailure(
558 const GoogleServiceAuthError& error) {
559 ShowConfirmation();
560}
561
[email protected]c82da8c42012-06-08 19:49:11562void ExtensionInstallPrompt::ShowConfirmation() {
563 prompt_.set_type(prompt_type_);
[email protected]f746b3f2012-07-03 17:53:37564
[email protected]bebe1d02012-08-02 20:17:09565 if (permissions_) {
[email protected]a6e5c9b2012-08-09 04:06:25566 Extension::Type extension_type = prompt_type_ == BUNDLE_INSTALL_PROMPT ?
567 Extension::TYPE_UNKNOWN : extension_->GetType();
568 prompt_.SetPermissions(permissions_->GetWarningMessages(extension_type));
[email protected]bebe1d02012-08-02 20:17:09569 }
[email protected]c82da8c42012-06-08 19:49:11570
571 switch (prompt_type_) {
572 case PERMISSIONS_PROMPT:
573 case RE_ENABLE_PROMPT:
574 case INLINE_INSTALL_PROMPT:
575 case INSTALL_PROMPT: {
576 prompt_.set_extension(extension_);
577 prompt_.set_icon(gfx::Image(icon_));
[email protected]c82da8c42012-06-08 19:49:11578 break;
579 }
580 case BUNDLE_INSTALL_PROMPT: {
581 prompt_.set_bundle(bundle_);
[email protected]c82da8c42012-06-08 19:49:11582 break;
583 }
584 default:
585 NOTREACHED() << "Unknown message";
[email protected]af6efb22012-10-12 02:23:05586 return;
[email protected]c82da8c42012-06-08 19:49:11587 }
[email protected]af6efb22012-10-12 02:23:05588
589 if (AutoConfirmPrompt(delegate_))
590 return;
591
592 DCHECK(!show_dialog_callback_.is_null());
593 show_dialog_callback_.Run(parent_, navigator_, delegate_, prompt_);
[email protected]c82da8c42012-06-08 19:49:11594}
[email protected]b70a2d92012-06-28 19:51:21595
[email protected]619f86182012-07-03 21:30:18596namespace chrome {
597
598ExtensionInstallPrompt* CreateExtensionInstallPromptWithBrowser(
599 Browser* browser) {
600 // |browser| can be NULL in unit tests.
601 if (!browser)
602 return new ExtensionInstallPrompt(NULL, NULL, NULL);
603 gfx::NativeWindow parent =
604 browser->window() ? browser->window()->GetNativeWindow() : NULL;
605 return new ExtensionInstallPrompt(parent, browser, browser->profile());
606}
607
608} // namespace chrome