1// 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/message_loop/message_loop.h" 11#include "base/prefs/pref_service.h" 12#include "base/strings/string_number_conversions.h" 13#include "base/strings/string_util.h" 14#include "base/strings/stringprintf.h" 15#include "base/strings/utf_string_conversions.h" 16#include "chrome/browser/extensions/bundle_installer.h" 17#include "chrome/browser/extensions/extension_install_ui.h" 18#include "chrome/browser/extensions/image_loader.h" 19#include "chrome/browser/profiles/profile.h" 20#include "chrome/browser/signin/profile_oauth2_token_service.h" 21#include "chrome/browser/signin/profile_oauth2_token_service_factory.h" 22#include "chrome/browser/ui/browser.h" 23#include "chrome/browser/ui/browser_window.h" 24#include "chrome/common/chrome_switches.h" 25#include "chrome/common/extensions/api/identity/oauth2_manifest_handler.h" 26#include "chrome/common/extensions/extension_constants.h" 27#include "chrome/common/extensions/extension_icon_set.h" 28#include "chrome/common/extensions/manifest_handlers/icons_handler.h" 29#include "chrome/common/pref_names.h" 30#include "content/public/browser/web_contents.h" 31#include "content/public/browser/web_contents_view.h" 32#include "extensions/common/extension.h" 33#include "extensions/common/extension_resource.h" 34#include "extensions/common/feature_switch.h" 35#include "extensions/common/manifest.h" 36#include "extensions/common/manifest_constants.h" 37#include "extensions/common/permissions/permission_message_provider.h" 38#include "extensions/common/permissions/permission_set.h" 39#include "extensions/common/permissions/permissions_data.h" 40#include "extensions/common/url_pattern.h" 41#include "grit/chromium_strings.h" 42#include "grit/generated_resources.h" 43#include "grit/theme_resources.h" 44#include "ui/base/l10n/l10n_util.h" 45#include "ui/base/resource/resource_bundle.h" 46#include "ui/gfx/image/image.h" 47 48using extensions::BundleInstaller; 49using extensions::Extension; 50using extensions::Manifest; 51using extensions::PermissionSet; 52 53namespace { 54 55static const int kTitleIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = { 56 0, // The regular install prompt depends on what's being installed. 57 IDS_EXTENSION_INLINE_INSTALL_PROMPT_TITLE, 58 IDS_EXTENSION_INSTALL_PROMPT_TITLE, 59 IDS_EXTENSION_RE_ENABLE_PROMPT_TITLE, 60 IDS_EXTENSION_PERMISSIONS_PROMPT_TITLE, 61 IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_TITLE, 62 IDS_EXTENSION_POST_INSTALL_PERMISSIONS_PROMPT_TITLE, 63 IDS_EXTENSION_LAUNCH_APP_PROMPT_TITLE, 64}; 65static const int kHeadingIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = { 66 IDS_EXTENSION_INSTALL_PROMPT_HEADING, 67 0, // Inline installs use the extension name. 68 0, // Heading for bundle installs depends on the bundle contents. 69 IDS_EXTENSION_RE_ENABLE_PROMPT_HEADING, 70 IDS_EXTENSION_PERMISSIONS_PROMPT_HEADING, 71 0, // External installs use different strings for extensions/apps. 72 IDS_EXTENSION_POST_INSTALL_PERMISSIONS_PROMPT_HEADING, 73 IDS_EXTENSION_LAUNCH_APP_PROMPT_HEADING, 74}; 75static const int kButtons[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = { 76 ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL, 77 ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL, 78 ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL, 79 ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL, 80 ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL, 81 ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL, 82 ui::DIALOG_BUTTON_CANCEL, 83 ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL, 84}; 85static const int kAcceptButtonIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = { 86 IDS_EXTENSION_PROMPT_INSTALL_BUTTON, 87 IDS_EXTENSION_PROMPT_INSTALL_BUTTON, 88 IDS_EXTENSION_PROMPT_INSTALL_BUTTON, 89 IDS_EXTENSION_PROMPT_RE_ENABLE_BUTTON, 90 IDS_EXTENSION_PROMPT_PERMISSIONS_BUTTON, 91 0, // External installs use different strings for extensions/apps. 92 IDS_EXTENSION_PROMPT_PERMISSIONS_CLEAR_RETAINED_FILES_BUTTON, 93 IDS_EXTENSION_PROMPT_LAUNCH_BUTTON, 94}; 95static const int kAbortButtonIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = { 96 0, // These all use the platform's default cancel label. 97 0, 98 0, 99 0, 100 IDS_EXTENSION_PROMPT_PERMISSIONS_ABORT_BUTTON, 101 IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ABORT_BUTTON, 102 IDS_CLOSE, 103 0, // Platform dependent cancel button. 104}; 105static const int kPermissionsHeaderIds[ 106 ExtensionInstallPrompt::NUM_PROMPT_TYPES] = { 107 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO, 108 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO, 109 IDS_EXTENSION_PROMPT_THESE_WILL_HAVE_ACCESS_TO, 110 IDS_EXTENSION_PROMPT_WILL_NOW_HAVE_ACCESS_TO, 111 IDS_EXTENSION_PROMPT_WANTS_ACCESS_TO, 112 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO, 113 IDS_EXTENSION_PROMPT_CAN_ACCESS, 114 IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO, 115}; 116static const int kOAuthHeaderIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = { 117 IDS_EXTENSION_PROMPT_OAUTH_HEADER, 118 0, // Inline installs don't show OAuth permissions. 119 0, // Bundle installs don't show OAuth permissions. 120 IDS_EXTENSION_PROMPT_OAUTH_REENABLE_HEADER, 121 IDS_EXTENSION_PROMPT_OAUTH_PERMISSIONS_HEADER, 122 0, 123 0, 124 IDS_EXTENSION_PROMPT_OAUTH_HEADER, 125}; 126 127// Size of extension icon in top left of dialog. 128const int kIconSize = 69; 129 130// Returns pixel size under maximal scale factor for the icon whose device 131// independent size is |size_in_dip| 132int GetSizeForMaxScaleFactor(int size_in_dip) { 133 return static_cast<int>(size_in_dip * gfx::ImageSkia::GetMaxSupportedScale()); 134} 135 136// Returns bitmap for the default icon with size equal to the default icon's 137// pixel size under maximal supported scale factor. 138SkBitmap GetDefaultIconBitmapForMaxScaleFactor(bool is_app) { 139 const gfx::ImageSkia& image = is_app ? 140 extensions::IconsInfo::GetDefaultAppIcon() : 141 extensions::IconsInfo::GetDefaultExtensionIcon(); 142 return image.GetRepresentation( 143 gfx::ImageSkia::GetMaxSupportedScale()).sk_bitmap(); 144} 145 146// If auto confirm is enabled then posts a task to proceed with or cancel the 147// install and returns true. Otherwise returns false. 148bool AutoConfirmPrompt(ExtensionInstallPrompt::Delegate* delegate) { 149 const CommandLine* cmdline = CommandLine::ForCurrentProcess(); 150 if (!cmdline->HasSwitch(switches::kAppsGalleryInstallAutoConfirmForTests)) 151 return false; 152 std::string value = cmdline->GetSwitchValueASCII( 153 switches::kAppsGalleryInstallAutoConfirmForTests); 154 155 // We use PostTask instead of calling the delegate directly here, because in 156 // the real implementations it's highly likely the message loop will be 157 // pumping a few times before the user clicks accept or cancel. 158 if (value == "accept") { 159 base::MessageLoop::current()->PostTask( 160 FROM_HERE, 161 base::Bind(&ExtensionInstallPrompt::Delegate::InstallUIProceed, 162 base::Unretained(delegate))); 163 return true; 164 } 165 166 if (value == "cancel") { 167 base::MessageLoop::current()->PostTask( 168 FROM_HERE, 169 base::Bind(&ExtensionInstallPrompt::Delegate::InstallUIAbort, 170 base::Unretained(delegate), 171 true)); 172 return true; 173 } 174 175 NOTREACHED(); 176 return false; 177} 178 179Profile* ProfileForWebContents(content::WebContents* web_contents) { 180 if (!web_contents) 181 return NULL; 182 return Profile::FromBrowserContext(web_contents->GetBrowserContext()); 183} 184 185gfx::NativeWindow NativeWindowForWebContents(content::WebContents* contents) { 186 if (!contents) 187 return NULL; 188 189 return contents->GetView()->GetTopLevelNativeWindow(); 190} 191 192} // namespace 193 194ExtensionInstallPrompt::Prompt::Prompt(PromptType type) 195 : type_(type), 196 is_showing_details_for_retained_files_(false), 197 extension_(NULL), 198 bundle_(NULL), 199 average_rating_(0.0), 200 rating_count_(0), 201 show_user_count_(false) { 202} 203 204ExtensionInstallPrompt::Prompt::~Prompt() { 205} 206 207void ExtensionInstallPrompt::Prompt::SetPermissions( 208 const std::vector<base::string16>& permissions) { 209 permissions_ = permissions; 210} 211 212void ExtensionInstallPrompt::Prompt::SetPermissionsDetails( 213 const std::vector<base::string16>& details) { 214 details_ = details; 215 is_showing_details_for_permissions_.clear(); 216 for (size_t i = 0; i < details.size(); ++i) 217 is_showing_details_for_permissions_.push_back(false); 218} 219 220void ExtensionInstallPrompt::Prompt::SetIsShowingDetails( 221 DetailsType type, 222 size_t index, 223 bool is_showing_details) { 224 switch (type) { 225 case PERMISSIONS_DETAILS: 226 is_showing_details_for_permissions_[index] = is_showing_details; 227 break; 228 case OAUTH_DETAILS: 229 is_showing_details_for_oauth_[index] = is_showing_details; 230 break; 231 case RETAINED_FILES_DETAILS: 232 is_showing_details_for_retained_files_ = is_showing_details; 233 break; 234 } 235} 236 237void ExtensionInstallPrompt::Prompt::SetOAuthIssueAdvice( 238 const IssueAdviceInfo& issue_advice) { 239 is_showing_details_for_oauth_.clear(); 240 for (size_t i = 0; i < issue_advice.size(); ++i) 241 is_showing_details_for_oauth_.push_back(false); 242 243 oauth_issue_advice_ = issue_advice; 244} 245 246void ExtensionInstallPrompt::Prompt::SetUserNameFromProfile(Profile* profile) { 247 // |profile| can be NULL in unit tests. 248 if (profile) { 249 oauth_user_name_ = UTF8ToUTF16(profile->GetPrefs()->GetString( 250 prefs::kGoogleServicesUsername)); 251 } else { 252 oauth_user_name_.clear(); 253 } 254} 255 256void ExtensionInstallPrompt::Prompt::SetInlineInstallWebstoreData( 257 const std::string& localized_user_count, 258 bool show_user_count, 259 double average_rating, 260 int rating_count) { 261 CHECK_EQ(INLINE_INSTALL_PROMPT, type_); 262 localized_user_count_ = localized_user_count; 263 show_user_count_ = show_user_count; 264 average_rating_ = average_rating; 265 rating_count_ = rating_count; 266} 267 268base::string16 ExtensionInstallPrompt::Prompt::GetDialogTitle() const { 269 int resource_id = kTitleIds[type_]; 270 271 if (type_ == INSTALL_PROMPT) { 272 if (extension_->is_app()) 273 resource_id = IDS_EXTENSION_INSTALL_APP_PROMPT_TITLE; 274 else if (extension_->is_theme()) 275 resource_id = IDS_EXTENSION_INSTALL_THEME_PROMPT_TITLE; 276 else 277 resource_id = IDS_EXTENSION_INSTALL_EXTENSION_PROMPT_TITLE; 278 } else if (type_ == EXTERNAL_INSTALL_PROMPT) { 279 return l10n_util::GetStringFUTF16( 280 resource_id, UTF8ToUTF16(extension_->name())); 281 } 282 283 return l10n_util::GetStringUTF16(resource_id); 284} 285 286base::string16 ExtensionInstallPrompt::Prompt::GetHeading() const { 287 if (type_ == INLINE_INSTALL_PROMPT) { 288 return UTF8ToUTF16(extension_->name()); 289 } else if (type_ == BUNDLE_INSTALL_PROMPT) { 290 return bundle_->GetHeadingTextFor(BundleInstaller::Item::STATE_PENDING); 291 } else if (type_ == EXTERNAL_INSTALL_PROMPT) { 292 int resource_id = -1; 293 if (extension_->is_app()) 294 resource_id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_HEADING_APP; 295 else if (extension_->is_theme()) 296 resource_id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_HEADING_THEME; 297 else 298 resource_id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_HEADING_EXTENSION; 299 return l10n_util::GetStringUTF16(resource_id); 300 } else { 301 return l10n_util::GetStringFUTF16( 302 kHeadingIds[type_], UTF8ToUTF16(extension_->name())); 303 } 304} 305 306int ExtensionInstallPrompt::Prompt::GetDialogButtons() const { 307 if (type_ == POST_INSTALL_PERMISSIONS_PROMPT && 308 ShouldDisplayRevokeFilesButton()) { 309 return kButtons[type_] | ui::DIALOG_BUTTON_OK; 310 } 311 312 return kButtons[type_]; 313} 314 315bool ExtensionInstallPrompt::Prompt::HasAcceptButtonLabel() const { 316 if (kAcceptButtonIds[type_] == 0) 317 return false; 318 319 if (type_ == POST_INSTALL_PERMISSIONS_PROMPT) 320 return ShouldDisplayRevokeFilesButton(); 321 322 return true; 323} 324 325base::string16 ExtensionInstallPrompt::Prompt::GetAcceptButtonLabel() const { 326 if (type_ == EXTERNAL_INSTALL_PROMPT) { 327 int id = -1; 328 if (extension_->is_app()) 329 id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_APP; 330 else if (extension_->is_theme()) 331 id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_THEME; 332 else 333 id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_EXTENSION; 334 return l10n_util::GetStringUTF16(id); 335 } 336 return l10n_util::GetStringUTF16(kAcceptButtonIds[type_]); 337} 338 339bool ExtensionInstallPrompt::Prompt::HasAbortButtonLabel() const { 340 return kAbortButtonIds[type_] > 0; 341} 342 343base::string16 ExtensionInstallPrompt::Prompt::GetAbortButtonLabel() const { 344 CHECK(HasAbortButtonLabel()); 345 return l10n_util::GetStringUTF16(kAbortButtonIds[type_]); 346} 347 348base::string16 ExtensionInstallPrompt::Prompt::GetPermissionsHeading() const { 349 return l10n_util::GetStringUTF16(kPermissionsHeaderIds[type_]); 350} 351 352base::string16 ExtensionInstallPrompt::Prompt::GetOAuthHeading() const { 353 return l10n_util::GetStringFUTF16(kOAuthHeaderIds[type_], oauth_user_name_); 354} 355 356base::string16 ExtensionInstallPrompt::Prompt::GetRetainedFilesHeading() const { 357 const int kRetainedFilesMessageIDs[6] = { 358 IDS_EXTENSION_PROMPT_RETAINED_FILES_DEFAULT, 359 IDS_EXTENSION_PROMPT_RETAINED_FILE_SINGULAR, 360 IDS_EXTENSION_PROMPT_RETAINED_FILES_ZERO, 361 IDS_EXTENSION_PROMPT_RETAINED_FILES_TWO, 362 IDS_EXTENSION_PROMPT_RETAINED_FILES_FEW, 363 IDS_EXTENSION_PROMPT_RETAINED_FILES_MANY, 364 }; 365 std::vector<int> message_ids; 366 for (size_t i = 0; i < arraysize(kRetainedFilesMessageIDs); i++) { 367 message_ids.push_back(kRetainedFilesMessageIDs[i]); 368 } 369 return l10n_util::GetPluralStringFUTF16(message_ids, GetRetainedFileCount()); 370} 371 372bool ExtensionInstallPrompt::Prompt::ShouldShowPermissions() const { 373 return GetPermissionCount() > 0 || type_ == POST_INSTALL_PERMISSIONS_PROMPT; 374} 375 376void ExtensionInstallPrompt::Prompt::AppendRatingStars( 377 StarAppender appender, void* data) const { 378 CHECK(appender); 379 CHECK_EQ(INLINE_INSTALL_PROMPT, type_); 380 int rating_integer = floor(average_rating_); 381 double rating_fractional = average_rating_ - rating_integer; 382 383 if (rating_fractional > 0.66) { 384 rating_integer++; 385 } 386 387 if (rating_fractional < 0.33 || rating_fractional > 0.66) { 388 rating_fractional = 0; 389 } 390 391 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 392 int i; 393 for (i = 0; i < rating_integer; i++) { 394 appender(rb.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_ON), data); 395 } 396 if (rating_fractional) { 397 appender(rb.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_HALF_LEFT), data); 398 i++; 399 } 400 for (; i < kMaxExtensionRating; i++) { 401 appender(rb.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_OFF), data); 402 } 403} 404 405base::string16 ExtensionInstallPrompt::Prompt::GetRatingCount() const { 406 CHECK_EQ(INLINE_INSTALL_PROMPT, type_); 407 return l10n_util::GetStringFUTF16(IDS_EXTENSION_RATING_COUNT, 408 base::IntToString16(rating_count_)); 409} 410 411base::string16 ExtensionInstallPrompt::Prompt::GetUserCount() const { 412 CHECK_EQ(INLINE_INSTALL_PROMPT, type_); 413 414 if (show_user_count_) { 415 return l10n_util::GetStringFUTF16(IDS_EXTENSION_USER_COUNT, 416 base::UTF8ToUTF16(localized_user_count_)); 417 } 418 return base::string16(); 419} 420 421size_t ExtensionInstallPrompt::Prompt::GetPermissionCount() const { 422 return permissions_.size(); 423} 424 425size_t ExtensionInstallPrompt::Prompt::GetPermissionsDetailsCount() const { 426 return details_.size(); 427} 428 429base::string16 ExtensionInstallPrompt::Prompt::GetPermission(size_t index) 430 const { 431 CHECK_LT(index, permissions_.size()); 432 return permissions_[index]; 433} 434 435base::string16 ExtensionInstallPrompt::Prompt::GetPermissionsDetails( 436 size_t index) const { 437 CHECK_LT(index, details_.size()); 438 return details_[index]; 439} 440 441bool ExtensionInstallPrompt::Prompt::GetIsShowingDetails( 442 DetailsType type, size_t index) const { 443 switch (type) { 444 case PERMISSIONS_DETAILS: 445 CHECK_LT(index, is_showing_details_for_permissions_.size()); 446 return is_showing_details_for_permissions_[index]; 447 case OAUTH_DETAILS: 448 CHECK_LT(index, is_showing_details_for_oauth_.size()); 449 return is_showing_details_for_oauth_[index]; 450 case RETAINED_FILES_DETAILS: 451 return is_showing_details_for_retained_files_; 452 } 453 return false; 454} 455 456size_t ExtensionInstallPrompt::Prompt::GetOAuthIssueCount() const { 457 return oauth_issue_advice_.size(); 458} 459 460const IssueAdviceInfoEntry& ExtensionInstallPrompt::Prompt::GetOAuthIssue( 461 size_t index) const { 462 CHECK_LT(index, oauth_issue_advice_.size()); 463 return oauth_issue_advice_[index]; 464} 465 466size_t ExtensionInstallPrompt::Prompt::GetRetainedFileCount() const { 467 return retained_files_.size(); 468} 469 470base::string16 ExtensionInstallPrompt::Prompt::GetRetainedFile(size_t index) 471 const { 472 CHECK_LT(index, retained_files_.size()); 473 return retained_files_[index].AsUTF16Unsafe(); 474} 475 476bool ExtensionInstallPrompt::Prompt::ShouldDisplayRevokeFilesButton() const { 477 return !retained_files_.empty(); 478} 479 480ExtensionInstallPrompt::ShowParams::ShowParams(content::WebContents* contents) 481 : parent_web_contents(contents), 482 parent_window(NativeWindowForWebContents(contents)), 483 navigator(contents) { 484} 485 486ExtensionInstallPrompt::ShowParams::ShowParams( 487 gfx::NativeWindow window, 488 content::PageNavigator* navigator) 489 : parent_web_contents(NULL), 490 parent_window(window), 491 navigator(navigator) { 492} 493 494// static 495scoped_refptr<Extension> 496 ExtensionInstallPrompt::GetLocalizedExtensionForDisplay( 497 const DictionaryValue* manifest, 498 int flags, 499 const std::string& id, 500 const std::string& localized_name, 501 const std::string& localized_description, 502 std::string* error) { 503 scoped_ptr<DictionaryValue> localized_manifest; 504 if (!localized_name.empty() || !localized_description.empty()) { 505 localized_manifest.reset(manifest->DeepCopy()); 506 if (!localized_name.empty()) { 507 localized_manifest->SetString(extensions::manifest_keys::kName, 508 localized_name); 509 } 510 if (!localized_description.empty()) { 511 localized_manifest->SetString(extensions::manifest_keys::kDescription, 512 localized_description); 513 } 514 } 515 516 return Extension::Create( 517 base::FilePath(), 518 Manifest::INTERNAL, 519 localized_manifest.get() ? *localized_manifest.get() : *manifest, 520 flags, 521 id, 522 error); 523} 524 525ExtensionInstallPrompt::ExtensionInstallPrompt(content::WebContents* contents) 526 : record_oauth2_grant_(false), 527 ui_loop_(base::MessageLoop::current()), 528 extension_(NULL), 529 bundle_(NULL), 530 install_ui_(ExtensionInstallUI::Create(ProfileForWebContents(contents))), 531 show_params_(contents), 532 delegate_(NULL), 533 prompt_(UNSET_PROMPT_TYPE) { 534 prompt_.SetUserNameFromProfile(install_ui_->profile()); 535} 536 537ExtensionInstallPrompt::ExtensionInstallPrompt( 538 Profile* profile, 539 gfx::NativeWindow native_window, 540 content::PageNavigator* navigator) 541 : record_oauth2_grant_(false), 542 ui_loop_(base::MessageLoop::current()), 543 extension_(NULL), 544 bundle_(NULL), 545 install_ui_(ExtensionInstallUI::Create(profile)), 546 show_params_(native_window, navigator), 547 delegate_(NULL), 548 prompt_(UNSET_PROMPT_TYPE) { 549 prompt_.SetUserNameFromProfile(install_ui_->profile()); 550} 551 552ExtensionInstallPrompt::~ExtensionInstallPrompt() { 553} 554 555void ExtensionInstallPrompt::ConfirmBundleInstall( 556 extensions::BundleInstaller* bundle, 557 const PermissionSet* permissions) { 558 DCHECK(ui_loop_ == base::MessageLoop::current()); 559 bundle_ = bundle; 560 permissions_ = permissions; 561 delegate_ = bundle; 562 prompt_.set_type(BUNDLE_INSTALL_PROMPT); 563 564 ShowConfirmation(); 565} 566 567void ExtensionInstallPrompt::ConfirmStandaloneInstall( 568 Delegate* delegate, 569 const Extension* extension, 570 SkBitmap* icon, 571 const ExtensionInstallPrompt::Prompt& prompt) { 572 DCHECK(ui_loop_ == base::MessageLoop::current()); 573 extension_ = extension; 574 permissions_ = extension->GetActivePermissions(); 575 delegate_ = delegate; 576 prompt_ = prompt; 577 578 SetIcon(icon); 579 ShowConfirmation(); 580} 581 582void ExtensionInstallPrompt::ConfirmWebstoreInstall( 583 Delegate* delegate, 584 const Extension* extension, 585 const SkBitmap* icon, 586 const ShowDialogCallback& show_dialog_callback) { 587 // SetIcon requires |extension_| to be set. ConfirmInstall will setup the 588 // remaining fields. 589 extension_ = extension; 590 SetIcon(icon); 591 ConfirmInstall(delegate, extension, show_dialog_callback); 592} 593 594void ExtensionInstallPrompt::ConfirmInstall( 595 Delegate* delegate, 596 const Extension* extension, 597 const ShowDialogCallback& show_dialog_callback) { 598 DCHECK(ui_loop_ == base::MessageLoop::current()); 599 extension_ = extension; 600 permissions_ = extension->GetActivePermissions(); 601 delegate_ = delegate; 602 prompt_.set_type(INSTALL_PROMPT); 603 show_dialog_callback_ = show_dialog_callback; 604 605 // We special-case themes to not show any confirm UI. Instead they are 606 // immediately installed, and then we show an infobar (see OnInstallSuccess) 607 // to allow the user to revert if they don't like it. 608 // 609 // We don't do this in the case where off-store extension installs are 610 // disabled because in that case, we don't show the dangerous download UI, so 611 // we need the UI confirmation. 612 if (extension->is_theme()) { 613 if (extension->from_webstore() || 614 extensions::FeatureSwitch::easy_off_store_install()->IsEnabled()) { 615 delegate->InstallUIProceed(); 616 return; 617 } 618 } 619 620 LoadImageIfNeeded(); 621} 622 623void ExtensionInstallPrompt::ConfirmReEnable(Delegate* delegate, 624 const Extension* extension) { 625 DCHECK(ui_loop_ == base::MessageLoop::current()); 626 extension_ = extension; 627 permissions_ = extension->GetActivePermissions(); 628 delegate_ = delegate; 629 prompt_.set_type(RE_ENABLE_PROMPT); 630 631 LoadImageIfNeeded(); 632} 633 634void ExtensionInstallPrompt::ConfirmExternalInstall( 635 Delegate* delegate, 636 const Extension* extension, 637 const ShowDialogCallback& show_dialog_callback) { 638 DCHECK(ui_loop_ == base::MessageLoop::current()); 639 extension_ = extension; 640 permissions_ = extension->GetActivePermissions(); 641 delegate_ = delegate; 642 prompt_.set_type(EXTERNAL_INSTALL_PROMPT); 643 show_dialog_callback_ = show_dialog_callback; 644 645 LoadImageIfNeeded(); 646} 647 648void ExtensionInstallPrompt::ConfirmPermissions( 649 Delegate* delegate, 650 const Extension* extension, 651 const PermissionSet* permissions) { 652 DCHECK(ui_loop_ == base::MessageLoop::current()); 653 extension_ = extension; 654 permissions_ = permissions; 655 delegate_ = delegate; 656 prompt_.set_type(PERMISSIONS_PROMPT); 657 658 LoadImageIfNeeded(); 659} 660 661void ExtensionInstallPrompt::ConfirmIssueAdvice( 662 Delegate* delegate, 663 const Extension* extension, 664 const IssueAdviceInfo& issue_advice) { 665 DCHECK(ui_loop_ == base::MessageLoop::current()); 666 extension_ = extension; 667 delegate_ = delegate; 668 prompt_.set_type(PERMISSIONS_PROMPT); 669 670 record_oauth2_grant_ = true; 671 prompt_.SetOAuthIssueAdvice(issue_advice); 672 673 LoadImageIfNeeded(); 674} 675 676void ExtensionInstallPrompt::ReviewPermissions( 677 Delegate* delegate, 678 const Extension* extension, 679 const std::vector<base::FilePath>& retained_file_paths) { 680 DCHECK(ui_loop_ == base::MessageLoop::current()); 681 extension_ = extension; 682 permissions_ = extension->GetActivePermissions(); 683 prompt_.set_retained_files(retained_file_paths); 684 delegate_ = delegate; 685 prompt_.set_type(POST_INSTALL_PERMISSIONS_PROMPT); 686 687 LoadImageIfNeeded(); 688} 689 690void ExtensionInstallPrompt::OnInstallSuccess(const Extension* extension, 691 SkBitmap* icon) { 692 extension_ = extension; 693 SetIcon(icon); 694 695 install_ui_->OnInstallSuccess(extension, &icon_); 696} 697 698void ExtensionInstallPrompt::OnInstallFailure( 699 const extensions::CrxInstallerError& error) { 700 install_ui_->OnInstallFailure(error); 701} 702 703void ExtensionInstallPrompt::SetIcon(const SkBitmap* image) { 704 if (image) 705 icon_ = *image; 706 else 707 icon_ = SkBitmap(); 708 if (icon_.empty()) { 709 // Let's set default icon bitmap whose size is equal to the default icon's 710 // pixel size under maximal supported scale factor. If the bitmap is larger 711 // than the one we need, it will be scaled down by the ui code. 712 icon_ = GetDefaultIconBitmapForMaxScaleFactor(extension_->is_app()); 713 } 714} 715 716void ExtensionInstallPrompt::OnImageLoaded(const gfx::Image& image) { 717 SetIcon(image.IsEmpty() ? NULL : image.ToSkBitmap()); 718 ShowConfirmation(); 719} 720 721void ExtensionInstallPrompt::LoadImageIfNeeded() { 722 // Bundle install prompts do not have an icon. 723 // Also |install_ui_.profile()| can be NULL in unit tests. 724 if (!icon_.empty() || !install_ui_->profile()) { 725 ShowConfirmation(); 726 return; 727 } 728 729 // Load the image asynchronously. For the response, check OnImageLoaded. 730 extensions::ExtensionResource image = extensions::IconsInfo::GetIconResource( 731 extension_, 732 extension_misc::EXTENSION_ICON_LARGE, 733 ExtensionIconSet::MATCH_BIGGER); 734 // Load the icon whose pixel size is large enough to be displayed under 735 // maximal supported scale factor. UI code will scale the icon down if needed. 736 // TODO(tbarzic): We should use IconImage here and load the required bitmap 737 // lazily. 738 int pixel_size = GetSizeForMaxScaleFactor(kIconSize); 739 extensions::ImageLoader::Get(install_ui_->profile())->LoadImageAsync( 740 extension_, image, gfx::Size(pixel_size, pixel_size), 741 base::Bind(&ExtensionInstallPrompt::OnImageLoaded, AsWeakPtr())); 742} 743 744void ExtensionInstallPrompt::OnGetTokenSuccess( 745 const OAuth2TokenService::Request* request, 746 const std::string& access_token, 747 const base::Time& expiration_time) { 748 DCHECK_EQ(login_token_request_.get(), request); 749 login_token_request_.reset(); 750 751 const extensions::OAuth2Info& oauth2_info = 752 extensions::OAuth2Info::GetOAuth2Info(extension_); 753 754 token_flow_.reset(new OAuth2MintTokenFlow( 755 install_ui_->profile()->GetRequestContext(), 756 this, 757 OAuth2MintTokenFlow::Parameters( 758 access_token, 759 extension_->id(), 760 oauth2_info.client_id, 761 oauth2_info.scopes, 762 OAuth2MintTokenFlow::MODE_ISSUE_ADVICE))); 763 token_flow_->Start(); 764} 765 766void ExtensionInstallPrompt::OnGetTokenFailure( 767 const OAuth2TokenService::Request* request, 768 const GoogleServiceAuthError& error) { 769 DCHECK_EQ(login_token_request_.get(), request); 770 login_token_request_.reset(); 771 ShowConfirmation(); 772} 773 774void ExtensionInstallPrompt::OnIssueAdviceSuccess( 775 const IssueAdviceInfo& advice_info) { 776 prompt_.SetOAuthIssueAdvice(advice_info); 777 record_oauth2_grant_ = true; 778 ShowConfirmation(); 779} 780 781void ExtensionInstallPrompt::OnMintTokenFailure( 782 const GoogleServiceAuthError& error) { 783 ShowConfirmation(); 784} 785 786void ExtensionInstallPrompt::ShowConfirmation() { 787 if (permissions_.get() && 788 (!extension_ || 789 !extensions::PermissionsData::ShouldSkipPermissionWarnings( 790 extension_))) { 791 Manifest::Type extension_type = extension_ ? 792 extension_->GetType() : Manifest::TYPE_UNKNOWN; 793 prompt_.SetPermissions( 794 extensions::PermissionMessageProvider::Get()-> 795 GetWarningMessages(permissions_, extension_type)); 796 prompt_.SetPermissionsDetails( 797 extensions::PermissionMessageProvider::Get()-> 798 GetWarningMessagesDetails(permissions_, extension_type)); 799 } 800 801 switch (prompt_.type()) { 802 case PERMISSIONS_PROMPT: 803 case RE_ENABLE_PROMPT: 804 case INLINE_INSTALL_PROMPT: 805 case EXTERNAL_INSTALL_PROMPT: 806 case INSTALL_PROMPT: 807 case LAUNCH_PROMPT: 808 case POST_INSTALL_PERMISSIONS_PROMPT: { 809 prompt_.set_extension(extension_); 810 prompt_.set_icon(gfx::Image::CreateFrom1xBitmap(icon_)); 811 break; 812 } 813 case BUNDLE_INSTALL_PROMPT: { 814 prompt_.set_bundle(bundle_); 815 break; 816 } 817 default: 818 NOTREACHED() << "Unknown message"; 819 return; 820 } 821 822 if (AutoConfirmPrompt(delegate_)) 823 return; 824 825 if (show_dialog_callback_.is_null()) 826 GetDefaultShowDialogCallback().Run(show_params_, delegate_, prompt_); 827 else 828 show_dialog_callback_.Run(show_params_, delegate_, prompt_); 829} 830