Home | History | Annotate | Download | only in extensions
      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 
     48 using extensions::BundleInstaller;
     49 using extensions::Extension;
     50 using extensions::Manifest;
     51 using extensions::PermissionSet;
     52 
     53 namespace {
     54 
     55 static 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 };
     65 static 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 };
     75 static 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 };
     85 static 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 };
     95 static 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 };
    105 static 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 };
    116 static 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.
    128 const int kIconSize = 69;
    129 
    130 // Returns pixel size under maximal scale factor for the icon whose device
    131 // independent size is |size_in_dip|
    132 int 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.
    138 SkBitmap 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.
    148 bool 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 
    179 Profile* ProfileForWebContents(content::WebContents* web_contents) {
    180   if (!web_contents)
    181     return NULL;
    182   return Profile::FromBrowserContext(web_contents->GetBrowserContext());
    183 }
    184 
    185 gfx::NativeWindow NativeWindowForWebContents(content::WebContents* contents) {
    186   if (!contents)
    187     return NULL;
    188 
    189   return contents->GetView()->GetTopLevelNativeWindow();
    190 }
    191 
    192 }  // namespace
    193 
    194 ExtensionInstallPrompt::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 
    204 ExtensionInstallPrompt::Prompt::~Prompt() {
    205 }
    206 
    207 void ExtensionInstallPrompt::Prompt::SetPermissions(
    208     const std::vector<base::string16>& permissions) {
    209   permissions_ = permissions;
    210 }
    211 
    212 void 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 
    220 void 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 
    237 void 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 
    246 void 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 
    256 void 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 
    268 base::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 
    286 base::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 
    306 int 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 
    315 bool 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 
    325 base::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 
    339 bool ExtensionInstallPrompt::Prompt::HasAbortButtonLabel() const {
    340   return kAbortButtonIds[type_] > 0;
    341 }
    342 
    343 base::string16 ExtensionInstallPrompt::Prompt::GetAbortButtonLabel() const {
    344   CHECK(HasAbortButtonLabel());
    345   return l10n_util::GetStringUTF16(kAbortButtonIds[type_]);
    346 }
    347 
    348 base::string16 ExtensionInstallPrompt::Prompt::GetPermissionsHeading() const {
    349   return l10n_util::GetStringUTF16(kPermissionsHeaderIds[type_]);
    350 }
    351 
    352 base::string16 ExtensionInstallPrompt::Prompt::GetOAuthHeading() const {
    353   return l10n_util::GetStringFUTF16(kOAuthHeaderIds[type_], oauth_user_name_);
    354 }
    355 
    356 base::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 
    372 bool ExtensionInstallPrompt::Prompt::ShouldShowPermissions() const {
    373   return GetPermissionCount() > 0 || type_ == POST_INSTALL_PERMISSIONS_PROMPT;
    374 }
    375 
    376 void 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 
    405 base::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 
    411 base::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 
    421 size_t ExtensionInstallPrompt::Prompt::GetPermissionCount() const {
    422   return permissions_.size();
    423 }
    424 
    425 size_t ExtensionInstallPrompt::Prompt::GetPermissionsDetailsCount() const {
    426   return details_.size();
    427 }
    428 
    429 base::string16 ExtensionInstallPrompt::Prompt::GetPermission(size_t index)
    430     const {
    431   CHECK_LT(index, permissions_.size());
    432   return permissions_[index];
    433 }
    434 
    435 base::string16 ExtensionInstallPrompt::Prompt::GetPermissionsDetails(
    436     size_t index) const {
    437   CHECK_LT(index, details_.size());
    438   return details_[index];
    439 }
    440 
    441 bool 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 
    456 size_t ExtensionInstallPrompt::Prompt::GetOAuthIssueCount() const {
    457   return oauth_issue_advice_.size();
    458 }
    459 
    460 const 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 
    466 size_t ExtensionInstallPrompt::Prompt::GetRetainedFileCount() const {
    467   return retained_files_.size();
    468 }
    469 
    470 base::string16 ExtensionInstallPrompt::Prompt::GetRetainedFile(size_t index)
    471     const {
    472   CHECK_LT(index, retained_files_.size());
    473   return retained_files_[index].AsUTF16Unsafe();
    474 }
    475 
    476 bool ExtensionInstallPrompt::Prompt::ShouldDisplayRevokeFilesButton() const {
    477   return !retained_files_.empty();
    478 }
    479 
    480 ExtensionInstallPrompt::ShowParams::ShowParams(content::WebContents* contents)
    481     : parent_web_contents(contents),
    482       parent_window(NativeWindowForWebContents(contents)),
    483       navigator(contents) {
    484 }
    485 
    486 ExtensionInstallPrompt::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
    495 scoped_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 
    525 ExtensionInstallPrompt::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 
    537 ExtensionInstallPrompt::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 
    552 ExtensionInstallPrompt::~ExtensionInstallPrompt() {
    553 }
    554 
    555 void 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 
    567 void 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 
    582 void 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 
    594 void 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 
    623 void 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 
    634 void 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 
    648 void 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 
    661 void 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 
    676 void 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 
    690 void ExtensionInstallPrompt::OnInstallSuccess(const Extension* extension,
    691                                               SkBitmap* icon) {
    692   extension_ = extension;
    693   SetIcon(icon);
    694 
    695   install_ui_->OnInstallSuccess(extension, &icon_);
    696 }
    697 
    698 void ExtensionInstallPrompt::OnInstallFailure(
    699     const extensions::CrxInstallerError& error) {
    700   install_ui_->OnInstallFailure(error);
    701 }
    702 
    703 void 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 
    716 void ExtensionInstallPrompt::OnImageLoaded(const gfx::Image& image) {
    717   SetIcon(image.IsEmpty() ? NULL : image.ToSkBitmap());
    718   ShowConfirmation();
    719 }
    720 
    721 void 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 
    744 void 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 
    766 void 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 
    774 void ExtensionInstallPrompt::OnIssueAdviceSuccess(
    775     const IssueAdviceInfo& advice_info) {
    776   prompt_.SetOAuthIssueAdvice(advice_info);
    777   record_oauth2_grant_ = true;
    778   ShowConfirmation();
    779 }
    780 
    781 void ExtensionInstallPrompt::OnMintTokenFailure(
    782     const GoogleServiceAuthError& error) {
    783   ShowConfirmation();
    784 }
    785 
    786 void 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