blob: 389b421740d6243a4b32da135b39759d4305410b [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/extensions/extension_install_prompt.h"
#include <utility>
#include "base/callback_helpers.h"
#include "base/location.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chrome/browser/extensions/extension_install_prompt_show_params.h"
#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/extensions/permissions_updater.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/extensions/extension_install_ui_factory.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/grit/theme_resources.h"
#include "components/strings/grit/components_strings.h"
#include "content/public/browser/web_contents.h"
#include "extensions/browser/disable_reason.h"
#include "extensions/browser/extension_dialog_auto_confirm.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_util.h"
#include "extensions/browser/image_loader.h"
#include "extensions/browser/install/extension_install_ui.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_icon_set.h"
#include "extensions/common/extension_resource.h"
#include "extensions/common/feature_switch.h"
#include "extensions/common/manifest.h"
#include "extensions/common/manifest_constants.h"
#include "extensions/common/manifest_handlers/icons_handler.h"
#include "extensions/common/manifest_handlers/permissions_parser.h"
#include "extensions/common/permissions/permission_message_provider.h"
#include "extensions/common/permissions/permission_set.h"
#include "extensions/common/permissions/permissions_data.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/ui_base_types.h"
#include "ui/gfx/image/image_skia.h"
using extensions::Extension;
using extensions::Manifest;
using extensions::PermissionMessage;
using extensions::PermissionMessages;
using extensions::PermissionSet;
namespace {
bool AllowWebstoreData(ExtensionInstallPrompt::PromptType type) {
return type == ExtensionInstallPrompt::INLINE_INSTALL_PROMPT ||
type == ExtensionInstallPrompt::EXTERNAL_INSTALL_PROMPT ||
type == ExtensionInstallPrompt::REPAIR_PROMPT;
}
// Returns bitmap for the default icon with size equal to the default icon's
// pixel size under maximal supported scale factor.
SkBitmap GetDefaultIconBitmapForMaxScaleFactor(bool is_app) {
const gfx::ImageSkia& image = is_app ?
extensions::util::GetDefaultAppIcon() :
extensions::util::GetDefaultExtensionIcon();
return image.GetRepresentation(
gfx::ImageSkia::GetMaxSupportedScale()).sk_bitmap();
}
// If auto confirm is enabled then posts a task to proceed with or cancel the
// install and returns true. Otherwise returns false.
bool AutoConfirmPrompt(ExtensionInstallPrompt::DoneCallback* callback) {
switch (extensions::ScopedTestDialogAutoConfirm::GetAutoConfirmValue()) {
case extensions::ScopedTestDialogAutoConfirm::NONE:
return false;
// We use PostTask instead of calling the callback directly here, because in
// the real implementations it's highly likely the message loop will be
// pumping a few times before the user clicks accept or cancel.
case extensions::ScopedTestDialogAutoConfirm::ACCEPT:
case extensions::ScopedTestDialogAutoConfirm::ACCEPT_AND_OPTION:
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(base::ResetAndReturn(callback),
ExtensionInstallPrompt::Result::ACCEPTED));
return true;
case extensions::ScopedTestDialogAutoConfirm::CANCEL:
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(base::ResetAndReturn(callback),
ExtensionInstallPrompt::Result::USER_CANCELED));
return true;
}
NOTREACHED();
return false;
}
Profile* ProfileForWebContents(content::WebContents* web_contents) {
if (!web_contents)
return NULL;
return Profile::FromBrowserContext(web_contents->GetBrowserContext());
}
} // namespace
ExtensionInstallPrompt::Prompt::InstallPromptPermissions::
InstallPromptPermissions() {
}
ExtensionInstallPrompt::Prompt::InstallPromptPermissions::
~InstallPromptPermissions() {
}
ExtensionInstallPrompt::PromptType
ExtensionInstallPrompt::g_last_prompt_type_for_tests =
ExtensionInstallPrompt::UNSET_PROMPT_TYPE;
// This should match the PromptType enum.
std::string ExtensionInstallPrompt::PromptTypeToString(PromptType type) {
switch (type) {
case INSTALL_PROMPT:
return "INSTALL_PROMPT";
case INLINE_INSTALL_PROMPT:
return "INLINE_INSTALL_PROMPT";
case RE_ENABLE_PROMPT:
return "RE_ENABLE_PROMPT";
case PERMISSIONS_PROMPT:
return "PERMISSIONS_PROMPT";
case EXTERNAL_INSTALL_PROMPT:
return "EXTERNAL_INSTALL_PROMPT";
case POST_INSTALL_PERMISSIONS_PROMPT:
return "POST_INSTALL_PERMISSIONS_PROMPT";
case REMOTE_INSTALL_PROMPT:
return "REMOTE_INSTALL_PROMPT";
case REPAIR_PROMPT:
return "REPAIR_PROMPT";
case DELEGATED_PERMISSIONS_PROMPT:
return "DELEGATED_PERMISSIONS_PROMPT";
case UNSET_PROMPT_TYPE:
case NUM_PROMPT_TYPES:
NOTREACHED();
break;
}
return "OTHER";
}
ExtensionInstallPrompt::Prompt::Prompt(PromptType type)
: type_(type),
is_showing_details_for_retained_files_(false),
is_showing_details_for_retained_devices_(false),
extension_(NULL),
average_rating_(0.0),
rating_count_(0),
show_user_count_(false),
has_webstore_data_(false) {
DCHECK_NE(type_, UNSET_PROMPT_TYPE);
DCHECK_NE(type_, NUM_PROMPT_TYPES);
}
ExtensionInstallPrompt::Prompt::~Prompt() {
}
void ExtensionInstallPrompt::Prompt::AddPermissions(
const PermissionMessages& permissions,
PermissionsType permissions_type) {
InstallPromptPermissions& install_permissions =
GetPermissionsForType(permissions_type);
for (const PermissionMessage& msg : permissions) {
install_permissions.permissions.push_back(msg.message());
// Add a dash to the front of each permission detail.
base::string16 details;
if (!msg.submessages().empty()) {
std::vector<base::string16> detail_lines_with_bullets;
for (const auto& detail_line : msg.submessages()) {
detail_lines_with_bullets.push_back(base::ASCIIToUTF16("- ") +
detail_line);
}
details = base::JoinString(detail_lines_with_bullets,
base::ASCIIToUTF16("\n"));
}
install_permissions.details.push_back(details);
install_permissions.is_showing_details.push_back(false);
}
}
void ExtensionInstallPrompt::Prompt::SetIsShowingDetails(
DetailsType type,
size_t index,
bool is_showing_details) {
switch (type) {
case PERMISSIONS_DETAILS:
prompt_permissions_.is_showing_details[index] = is_showing_details;
break;
case WITHHELD_PERMISSIONS_DETAILS:
withheld_prompt_permissions_.is_showing_details[index] =
is_showing_details;
break;
case RETAINED_FILES_DETAILS:
is_showing_details_for_retained_files_ = is_showing_details;
break;
case RETAINED_DEVICES_DETAILS:
is_showing_details_for_retained_devices_ = is_showing_details;
break;
}
}
void ExtensionInstallPrompt::Prompt::SetWebstoreData(
const std::string& localized_user_count,
bool show_user_count,
double average_rating,
int rating_count) {
CHECK(AllowWebstoreData(type_));
localized_user_count_ = localized_user_count;
show_user_count_ = show_user_count;
average_rating_ = average_rating;
rating_count_ = rating_count;
has_webstore_data_ = true;
}
base::string16 ExtensionInstallPrompt::Prompt::GetDialogTitle() const {
int id = -1;
switch (type_) {
case INSTALL_PROMPT:
case INLINE_INSTALL_PROMPT:
id = IDS_EXTENSION_INSTALL_PROMPT_TITLE;
break;
case RE_ENABLE_PROMPT:
id = IDS_EXTENSION_RE_ENABLE_PROMPT_TITLE;
break;
case PERMISSIONS_PROMPT:
id = IDS_EXTENSION_PERMISSIONS_PROMPT_TITLE;
break;
case EXTERNAL_INSTALL_PROMPT:
if (extension_->is_app())
id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_TITLE_APP;
else if (extension_->is_theme())
id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_TITLE_THEME;
else
id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_TITLE_EXTENSION;
break;
case POST_INSTALL_PERMISSIONS_PROMPT:
id = IDS_EXTENSION_POST_INSTALL_PERMISSIONS_PROMPT_TITLE;
break;
case REMOTE_INSTALL_PROMPT:
id = IDS_EXTENSION_REMOTE_INSTALL_PROMPT_TITLE;
break;
case REPAIR_PROMPT:
id = IDS_EXTENSION_REPAIR_PROMPT_TITLE;
break;
case DELEGATED_PERMISSIONS_PROMPT:
// Special case: need to include the delegated username.
return l10n_util::GetStringFUTF16(
IDS_EXTENSION_DELEGATED_INSTALL_PROMPT_TITLE,
base::UTF8ToUTF16(extension_->name()),
base::UTF8ToUTF16(delegated_username_));
case UNSET_PROMPT_TYPE:
case NUM_PROMPT_TYPES:
NOTREACHED();
}
return l10n_util::GetStringFUTF16(id, base::UTF8ToUTF16(extension_->name()));
}
int ExtensionInstallPrompt::Prompt::GetDialogButtons() const {
// The "OK" button in the post install permissions dialog allows revoking
// file/device access, and is only shown if such permissions exist; see
// ShouldDisplayRevokeButton().
if (type_ == POST_INSTALL_PERMISSIONS_PROMPT &&
!ShouldDisplayRevokeButton()) {
return ui::DIALOG_BUTTON_CANCEL;
}
return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL;
}
base::string16 ExtensionInstallPrompt::Prompt::GetAcceptButtonLabel() const {
int id = -1;
switch (type_) {
case INSTALL_PROMPT:
case INLINE_INSTALL_PROMPT:
if (extension_->is_app())
id = IDS_EXTENSION_INSTALL_PROMPT_ACCEPT_BUTTON_APP;
else if (extension_->is_theme())
id = IDS_EXTENSION_INSTALL_PROMPT_ACCEPT_BUTTON_THEME;
else
id = IDS_EXTENSION_INSTALL_PROMPT_ACCEPT_BUTTON_EXTENSION;
break;
case RE_ENABLE_PROMPT:
id = IDS_EXTENSION_PROMPT_RE_ENABLE_BUTTON;
break;
case PERMISSIONS_PROMPT:
id = IDS_EXTENSION_PROMPT_PERMISSIONS_BUTTON;
break;
case EXTERNAL_INSTALL_PROMPT:
if (extension_->is_app())
id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_APP;
else if (extension_->is_theme())
id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_THEME;
else
id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ACCEPT_BUTTON_EXTENSION;
break;
case POST_INSTALL_PERMISSIONS_PROMPT:
if (GetRetainedFileCount() && GetRetainedDeviceCount()) {
id =
IDS_EXTENSION_PROMPT_PERMISSIONS_CLEAR_RETAINED_FILES_AND_DEVICES_BUTTON;
} else if (GetRetainedFileCount()) {
id = IDS_EXTENSION_PROMPT_PERMISSIONS_CLEAR_RETAINED_FILES_BUTTON;
} else if (GetRetainedDeviceCount()) {
id = IDS_EXTENSION_PROMPT_PERMISSIONS_CLEAR_RETAINED_DEVICES_BUTTON;
}
// If there are neither retained files nor devices, leave id -1 so there
// will be no "accept" button.
break;
case REMOTE_INSTALL_PROMPT:
if (extension_->is_app())
id = IDS_EXTENSION_PROMPT_REMOTE_INSTALL_BUTTON_APP;
else
id = IDS_EXTENSION_PROMPT_REMOTE_INSTALL_BUTTON_EXTENSION;
break;
case REPAIR_PROMPT:
if (extension_->is_app())
id = IDS_EXTENSION_PROMPT_REPAIR_BUTTON_APP;
else
id = IDS_EXTENSION_PROMPT_REPAIR_BUTTON_EXTENSION;
break;
case DELEGATED_PERMISSIONS_PROMPT:
id = IDS_EXTENSION_PROMPT_INSTALL_BUTTON;
break;
case UNSET_PROMPT_TYPE:
case NUM_PROMPT_TYPES:
NOTREACHED();
}
return id != -1 ? l10n_util::GetStringUTF16(id) : base::string16();
}
base::string16 ExtensionInstallPrompt::Prompt::GetAbortButtonLabel() const {
int id = -1;
switch (type_) {
case INSTALL_PROMPT:
case INLINE_INSTALL_PROMPT:
case RE_ENABLE_PROMPT:
case REMOTE_INSTALL_PROMPT:
case REPAIR_PROMPT:
case DELEGATED_PERMISSIONS_PROMPT:
id = IDS_CANCEL;
break;
case PERMISSIONS_PROMPT:
id = IDS_EXTENSION_PROMPT_PERMISSIONS_ABORT_BUTTON;
break;
case EXTERNAL_INSTALL_PROMPT:
id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ABORT_BUTTON;
break;
case POST_INSTALL_PERMISSIONS_PROMPT:
id = IDS_CLOSE;
break;
case UNSET_PROMPT_TYPE:
case NUM_PROMPT_TYPES:
NOTREACHED();
}
return l10n_util::GetStringUTF16(id);
}
base::string16 ExtensionInstallPrompt::Prompt::GetPermissionsHeading(
PermissionsType permissions_type) const {
switch (permissions_type) {
case REGULAR_PERMISSIONS: {
int id = -1;
switch (type_) {
case INSTALL_PROMPT:
case INLINE_INSTALL_PROMPT:
case EXTERNAL_INSTALL_PROMPT:
case REMOTE_INSTALL_PROMPT:
case DELEGATED_PERMISSIONS_PROMPT:
id = IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO;
break;
case RE_ENABLE_PROMPT:
id = IDS_EXTENSION_PROMPT_WILL_NOW_HAVE_ACCESS_TO;
break;
case PERMISSIONS_PROMPT:
id = IDS_EXTENSION_PROMPT_WANTS_ACCESS_TO;
break;
case POST_INSTALL_PERMISSIONS_PROMPT:
case REPAIR_PROMPT:
id = IDS_EXTENSION_PROMPT_CAN_ACCESS;
break;
case UNSET_PROMPT_TYPE:
case NUM_PROMPT_TYPES:
NOTREACHED();
}
return l10n_util::GetStringUTF16(id);
}
case WITHHELD_PERMISSIONS:
return l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WITHHELD);
case ALL_PERMISSIONS:
NOTREACHED();
return base::string16();
}
NOTREACHED();
return base::string16();
}
base::string16 ExtensionInstallPrompt::Prompt::GetRetainedFilesHeading() const {
return l10n_util::GetPluralStringFUTF16(
IDS_EXTENSION_PROMPT_RETAINED_FILES, GetRetainedFileCount());
}
base::string16 ExtensionInstallPrompt::Prompt::GetRetainedDevicesHeading()
const {
return l10n_util::GetPluralStringFUTF16(
IDS_EXTENSION_PROMPT_RETAINED_DEVICES, GetRetainedDeviceCount());
}
bool ExtensionInstallPrompt::Prompt::ShouldShowPermissions() const {
return GetPermissionCount(ALL_PERMISSIONS) > 0 ||
type_ == POST_INSTALL_PERMISSIONS_PROMPT;
}
bool ExtensionInstallPrompt::Prompt::ShouldUseTabModalDialog() const {
// For inline install, we want the install prompt to be tab modal so that the
// dialog is always clearly associated with the page that made the inline
// install request.
return type_ == INLINE_INSTALL_PROMPT;
}
void ExtensionInstallPrompt::Prompt::AppendRatingStars(
StarAppender appender, void* data) const {
CHECK(appender);
CHECK(AllowWebstoreData(type_));
int rating_integer = floor(average_rating_);
double rating_fractional = average_rating_ - rating_integer;
if (rating_fractional > 0.66) {
rating_integer++;
}
if (rating_fractional < 0.33 || rating_fractional > 0.66) {
rating_fractional = 0;
}
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
int i;
for (i = 0; i < rating_integer; i++) {
appender(rb.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_ON), data);
}
if (rating_fractional) {
appender(rb.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_HALF_LEFT), data);
i++;
}
for (; i < kMaxExtensionRating; i++) {
appender(rb.GetImageSkiaNamed(IDR_EXTENSIONS_RATING_STAR_OFF), data);
}
}
base::string16 ExtensionInstallPrompt::Prompt::GetRatingCount() const {
CHECK(AllowWebstoreData(type_));
return l10n_util::GetStringFUTF16(IDS_EXTENSION_RATING_COUNT,
base::IntToString16(rating_count_));
}
base::string16 ExtensionInstallPrompt::Prompt::GetUserCount() const {
CHECK(AllowWebstoreData(type_));
if (show_user_count_) {
return l10n_util::GetStringFUTF16(IDS_EXTENSION_USER_COUNT,
base::UTF8ToUTF16(localized_user_count_));
}
return base::string16();
}
size_t ExtensionInstallPrompt::Prompt::GetPermissionCount(
PermissionsType permissions_type) const {
switch (permissions_type) {
case REGULAR_PERMISSIONS:
return prompt_permissions_.permissions.size();
case WITHHELD_PERMISSIONS:
return withheld_prompt_permissions_.permissions.size();
case ALL_PERMISSIONS:
return prompt_permissions_.permissions.size() +
withheld_prompt_permissions_.permissions.size();
default:
NOTREACHED();
return 0u;
}
}
size_t ExtensionInstallPrompt::Prompt::GetPermissionsDetailsCount(
PermissionsType permissions_type) const {
switch (permissions_type) {
case REGULAR_PERMISSIONS:
return prompt_permissions_.details.size();
case WITHHELD_PERMISSIONS:
return withheld_prompt_permissions_.details.size();
case ALL_PERMISSIONS:
return prompt_permissions_.details.size() +
withheld_prompt_permissions_.details.size();
default:
NOTREACHED();
return 0u;
}
}
base::string16 ExtensionInstallPrompt::Prompt::GetPermission(
size_t index,
PermissionsType permissions_type) const {
const InstallPromptPermissions& install_permissions =
GetPermissionsForType(permissions_type);
CHECK_LT(index, install_permissions.permissions.size());
return install_permissions.permissions[index];
}
base::string16 ExtensionInstallPrompt::Prompt::GetPermissionsDetails(
size_t index,
PermissionsType permissions_type) const {
const InstallPromptPermissions& install_permissions =
GetPermissionsForType(permissions_type);
CHECK_LT(index, install_permissions.details.size());
return install_permissions.details[index];
}
bool ExtensionInstallPrompt::Prompt::GetIsShowingDetails(
DetailsType type, size_t index) const {
switch (type) {
case PERMISSIONS_DETAILS:
CHECK_LT(index, prompt_permissions_.is_showing_details.size());
return prompt_permissions_.is_showing_details[index];
case WITHHELD_PERMISSIONS_DETAILS:
CHECK_LT(index, withheld_prompt_permissions_.is_showing_details.size());
return withheld_prompt_permissions_.is_showing_details[index];
case RETAINED_FILES_DETAILS:
return is_showing_details_for_retained_files_;
case RETAINED_DEVICES_DETAILS:
return is_showing_details_for_retained_devices_;
}
return false;
}
size_t ExtensionInstallPrompt::Prompt::GetRetainedFileCount() const {
return retained_files_.size();
}
base::string16 ExtensionInstallPrompt::Prompt::GetRetainedFile(size_t index)
const {
CHECK_LT(index, retained_files_.size());
return retained_files_[index].AsUTF16Unsafe();
}
size_t ExtensionInstallPrompt::Prompt::GetRetainedDeviceCount() const {
return retained_device_messages_.size();
}
base::string16 ExtensionInstallPrompt::Prompt::GetRetainedDeviceMessageString(
size_t index) const {
CHECK_LT(index, retained_device_messages_.size());
return retained_device_messages_[index];
}
bool ExtensionInstallPrompt::Prompt::ShouldDisplayRevokeButton() const {
return !retained_files_.empty() || !retained_device_messages_.empty();
}
ExtensionInstallPrompt::Prompt::InstallPromptPermissions&
ExtensionInstallPrompt::Prompt::GetPermissionsForType(
PermissionsType permissions_type) {
DCHECK_NE(ALL_PERMISSIONS, permissions_type);
return permissions_type == REGULAR_PERMISSIONS ? prompt_permissions_
: withheld_prompt_permissions_;
}
const ExtensionInstallPrompt::Prompt::InstallPromptPermissions&
ExtensionInstallPrompt::Prompt::GetPermissionsForType(
PermissionsType permissions_type) const {
DCHECK_NE(ALL_PERMISSIONS, permissions_type);
return permissions_type == REGULAR_PERMISSIONS ? prompt_permissions_
: withheld_prompt_permissions_;
}
bool ExtensionInstallPrompt::Prompt::ShouldDisplayRevokeFilesButton() const {
return !retained_files_.empty();
}
// static
ExtensionInstallPrompt::PromptType
ExtensionInstallPrompt::GetReEnablePromptTypeForExtension(
content::BrowserContext* context,
const extensions::Extension* extension) {
bool is_remote_install =
context &&
extensions::ExtensionPrefs::Get(context)->HasDisableReason(
extension->id(), extensions::disable_reason::DISABLE_REMOTE_INSTALL);
return is_remote_install ? REMOTE_INSTALL_PROMPT : RE_ENABLE_PROMPT;
}
// static
scoped_refptr<Extension>
ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
const base::DictionaryValue* manifest,
int flags,
const std::string& id,
const std::string& localized_name,
const std::string& localized_description,
std::string* error) {
std::unique_ptr<base::DictionaryValue> localized_manifest;
if (!localized_name.empty() || !localized_description.empty()) {
localized_manifest.reset(manifest->DeepCopy());
if (!localized_name.empty()) {
localized_manifest->SetString(extensions::manifest_keys::kName,
localized_name);
}
if (!localized_description.empty()) {
localized_manifest->SetString(extensions::manifest_keys::kDescription,
localized_description);
}
}
return Extension::Create(
base::FilePath(), Manifest::INTERNAL,
localized_manifest.get() ? *localized_manifest : *manifest, flags, id,
error);
}
ExtensionInstallPrompt::ExtensionInstallPrompt(content::WebContents* contents)
: profile_(ProfileForWebContents(contents)),
extension_(NULL),
install_ui_(extensions::CreateExtensionInstallUI(
ProfileForWebContents(contents))),
show_params_(new ExtensionInstallPromptShowParams(contents)),
did_call_show_dialog_(false),
weak_factory_(this) {
}
ExtensionInstallPrompt::ExtensionInstallPrompt(Profile* profile,
gfx::NativeWindow native_window)
: profile_(profile),
extension_(NULL),
install_ui_(extensions::CreateExtensionInstallUI(profile)),
show_params_(
new ExtensionInstallPromptShowParams(profile, native_window)),
did_call_show_dialog_(false),
weak_factory_(this) {
}
ExtensionInstallPrompt::~ExtensionInstallPrompt() {
}
void ExtensionInstallPrompt::ShowDialog(
const DoneCallback& done_callback,
const Extension* extension,
const SkBitmap* icon,
const ShowDialogCallback& show_dialog_callback) {
ShowDialog(done_callback, extension, icon,
std::make_unique<Prompt>(INSTALL_PROMPT), show_dialog_callback);
}
void ExtensionInstallPrompt::ShowDialog(
const DoneCallback& done_callback,
const Extension* extension,
const SkBitmap* icon,
std::unique_ptr<Prompt> prompt,
const ShowDialogCallback& show_dialog_callback) {
ShowDialog(done_callback, extension, icon, std::move(prompt), nullptr,
show_dialog_callback);
}
void ExtensionInstallPrompt::ShowDialog(
const DoneCallback& done_callback,
const Extension* extension,
const SkBitmap* icon,
std::unique_ptr<Prompt> prompt,
std::unique_ptr<const PermissionSet> custom_permissions,
const ShowDialogCallback& show_dialog_callback) {
DCHECK(ui_thread_checker_.CalledOnValidThread());
DCHECK(prompt);
extension_ = extension;
done_callback_ = done_callback;
if (icon && !icon->empty())
SetIcon(icon);
prompt_ = std::move(prompt);
custom_permissions_ = std::move(custom_permissions);
show_dialog_callback_ = show_dialog_callback;
// We special-case themes to not show any confirm UI. Instead they are
// immediately installed, and then we show an infobar (see OnInstallSuccess)
// to allow the user to revert if they don't like it.
if (extension->is_theme() && extension->from_webstore()) {
base::ResetAndReturn(&done_callback_).Run(Result::ACCEPTED);
return;
}
LoadImageIfNeeded();
}
void ExtensionInstallPrompt::OnInstallSuccess(const Extension* extension,
SkBitmap* icon) {
extension_ = extension;
SetIcon(icon);
install_ui_->OnInstallSuccess(extension, &icon_);
}
void ExtensionInstallPrompt::OnInstallFailure(
const extensions::CrxInstallError& error) {
install_ui_->OnInstallFailure(error);
}
void ExtensionInstallPrompt::SetIcon(const SkBitmap* image) {
if (image)
icon_ = *image;
else
icon_ = SkBitmap();
if (icon_.empty()) {
// Let's set default icon bitmap whose size is equal to the default icon's
// pixel size under maximal supported scale factor. If the bitmap is larger
// than the one we need, it will be scaled down by the ui code.
icon_ = GetDefaultIconBitmapForMaxScaleFactor(
extension_ ? extension_->is_app() : false);
}
}
void ExtensionInstallPrompt::OnImageLoaded(const gfx::Image& image) {
SetIcon(image.IsEmpty() ? NULL : image.ToSkBitmap());
ShowConfirmation();
}
void ExtensionInstallPrompt::LoadImageIfNeeded() {
// Don't override an icon that was passed in. Also, |profile_| can be null in
// unit tests.
if (!icon_.empty() || !profile_) {
ShowConfirmation();
return;
}
extensions::ExtensionResource image = extensions::IconsInfo::GetIconResource(
extension_,
extension_misc::EXTENSION_ICON_LARGE,
ExtensionIconSet::MATCH_BIGGER);
// Load the image asynchronously. The response will be sent to OnImageLoaded.
extensions::ImageLoader* loader = extensions::ImageLoader::Get(profile_);
std::vector<extensions::ImageLoader::ImageRepresentation> images_list;
images_list.push_back(extensions::ImageLoader::ImageRepresentation(
image,
extensions::ImageLoader::ImageRepresentation::NEVER_RESIZE,
gfx::Size(),
ui::SCALE_FACTOR_100P));
loader->LoadImagesAsync(
extension_,
images_list,
base::Bind(&ExtensionInstallPrompt::OnImageLoaded,
weak_factory_.GetWeakPtr()));
}
void ExtensionInstallPrompt::ShowConfirmation() {
std::unique_ptr<const PermissionSet> permissions_wrapper;
const PermissionSet* permissions_to_display = nullptr;
if (custom_permissions_.get()) {
permissions_to_display = custom_permissions_.get();
} else if (extension_) {
// Initialize permissions if they have not already been set so that
// withheld permissions are displayed properly in the install prompt.
extensions::PermissionsUpdater(
profile_, extensions::PermissionsUpdater::INIT_FLAG_TRANSIENT)
.InitializePermissions(extension_);
permissions_to_display =
&extension_->permissions_data()->active_permissions();
// For delegated installs, all optional permissions are pre-approved by the
// person who triggers the install, so add them to the list.
if (prompt_->type() == DELEGATED_PERMISSIONS_PROMPT) {
const PermissionSet& optional_permissions =
extensions::PermissionsParser::GetOptionalPermissions(extension_);
permissions_wrapper = PermissionSet::CreateUnion(*permissions_to_display,
optional_permissions);
permissions_to_display = permissions_wrapper.get();
}
}
if (permissions_to_display &&
(!extension_ ||
!extensions::PermissionsData::ShouldSkipPermissionWarnings(
extension_->id()))) {
Manifest::Type type =
extension_ ? extension_->GetType() : Manifest::TYPE_UNKNOWN;
const extensions::PermissionMessageProvider* message_provider =
extensions::PermissionMessageProvider::Get();
prompt_->AddPermissions(message_provider->GetPermissionMessages(
message_provider->GetAllPermissionIDs(
*permissions_to_display, type)),
REGULAR_PERMISSIONS);
const PermissionSet* withheld =
extension_ ? &extension_->permissions_data()->withheld_permissions()
: nullptr;
if (withheld && !withheld->IsEmpty()) {
prompt_->AddPermissions(
message_provider->GetPermissionMessages(
message_provider->GetAllPermissionIDs(*withheld, type)),
WITHHELD_PERMISSIONS);
}
}
prompt_->set_extension(extension_);
prompt_->set_icon(gfx::Image::CreateFrom1xBitmap(icon_));
if (show_params_->WasParentDestroyed()) {
base::ResetAndReturn(&done_callback_).Run(Result::ABORTED);
return;
}
g_last_prompt_type_for_tests = prompt_->type();
did_call_show_dialog_ = true;
if (AutoConfirmPrompt(&done_callback_))
return;
if (show_dialog_callback_.is_null())
show_dialog_callback_ = GetDefaultShowDialogCallback();
base::ResetAndReturn(&show_dialog_callback_)
.Run(show_params_.get(), base::ResetAndReturn(&done_callback_),
std::move(prompt_));
}