blob: c10dc098bec241aba80a6b1e07a814e197543f05 [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.
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_INSTALL_PROMPT_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_INSTALL_PROMPT_H_
#include <stddef.h>
#include <memory>
#include <string>
#include <vector>
#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string16.h"
#include "base/threading/thread_checker.h"
#include "build/build_config.h"
#include "extensions/common/permissions/permission_message.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/native_widget_types.h"
class ExtensionInstallPromptShowParams;
class Profile;
namespace base {
class DictionaryValue;
} // namespace base
namespace content {
class BrowserContext;
class WebContents;
}
namespace extensions {
class CrxInstallError;
class Extension;
class ExtensionInstallUI;
class PermissionSet;
} // namespace extensions
namespace gfx {
class ImageSkia;
}
// Displays all the UI around extension installation.
class ExtensionInstallPrompt {
public:
// This enum is associated with Extensions.InstallPrompt_Type UMA histogram.
// Do not modify existing values and add new values only to the end.
enum PromptType {
UNSET_PROMPT_TYPE = -1,
INSTALL_PROMPT = 0,
// INLINE_INSTALL_PROMPT_DEPRECATED = 1,
// BUNDLE_INSTALL_PROMPT_DEPRECATED = 2,
RE_ENABLE_PROMPT = 3,
PERMISSIONS_PROMPT = 4,
EXTERNAL_INSTALL_PROMPT = 5,
POST_INSTALL_PERMISSIONS_PROMPT = 6,
// LAUNCH_PROMPT_DEPRECATED = 7,
REMOTE_INSTALL_PROMPT = 8,
REPAIR_PROMPT = 9,
DELEGATED_PERMISSIONS_PROMPT = 10,
// DELEGATED_BUNDLE_PERMISSIONS_PROMPT_DEPRECATED = 11,
NUM_PROMPT_TYPES = 12,
WEBSTORE_WIDGET_PROMPT = 13,
};
// The last prompt type to display; only used for testing.
static PromptType g_last_prompt_type_for_tests;
// Enumeration for permissions and retained files details.
enum DetailsType {
PERMISSIONS_DETAILS = 0,
RETAINED_FILES_DETAILS,
RETAINED_DEVICES_DETAILS,
};
// Extra information needed to display an installation or uninstallation
// prompt. Gets populated with raw data and exposes getters for formatted
// strings so that the GTK/views/Cocoa install dialogs don't have to repeat
// that logic.
class Prompt {
public:
explicit Prompt(PromptType type);
~Prompt();
void AddPermissions(const extensions::PermissionMessages& permissions);
void SetIsShowingDetails(DetailsType type,
size_t index,
bool is_showing_details);
void SetWebstoreData(const std::string& localized_user_count,
bool show_user_count,
double average_rating,
int rating_count);
PromptType type() const { return type_; }
// Getters for UI element labels.
base::string16 GetDialogTitle() const;
int GetDialogButtons() const;
// Returns the empty string when there should be no "accept" button.
base::string16 GetAcceptButtonLabel() const;
base::string16 GetAbortButtonLabel() const;
base::string16 GetPermissionsHeading() const;
base::string16 GetRetainedFilesHeading() const;
base::string16 GetRetainedDevicesHeading() const;
bool ShouldShowPermissions() const;
// Getters for webstore metadata. Only populated when the type is
// INLINE_INSTALL_PROMPT, EXTERNAL_INSTALL_PROMPT, or REPAIR_PROMPT.
// The star display logic replicates the one used by the webstore (from
// components.ratingutils.setFractionalYellowStars). Callers pass in an
// "appender", which will be repeatedly called back with the star images
// that they append to the star display area.
typedef void(*StarAppender)(const gfx::ImageSkia*, void*);
void AppendRatingStars(StarAppender appender, void* data) const;
base::string16 GetRatingCount() const;
base::string16 GetUserCount() const;
size_t GetPermissionCount() const;
size_t GetPermissionsDetailsCount() const;
base::string16 GetPermission(size_t index) const;
base::string16 GetPermissionsDetails(size_t index) const;
bool GetIsShowingDetails(DetailsType type, size_t index) const;
size_t GetRetainedFileCount() const;
base::string16 GetRetainedFile(size_t index) const;
size_t GetRetainedDeviceCount() const;
base::string16 GetRetainedDeviceMessageString(size_t index) const;
const extensions::Extension* extension() const { return extension_; }
void set_extension(const extensions::Extension* extension) {
extension_ = extension;
}
// May be populated for POST_INSTALL_PERMISSIONS_PROMPT.
void set_retained_files(const std::vector<base::FilePath>& retained_files) {
retained_files_ = retained_files;
}
void set_retained_device_messages(
const std::vector<base::string16>& retained_device_messages) {
retained_device_messages_ = retained_device_messages;
}
const std::string& delegated_username() const {
return delegated_username_;
}
void set_delegated_username(const std::string& delegated_username) {
delegated_username_ = delegated_username;
}
const gfx::Image& icon() const { return icon_; }
void set_icon(const gfx::Image& icon) { icon_ = icon; }
double average_rating() const { return average_rating_; }
int rating_count() const { return rating_count_; }
bool has_webstore_data() const { return has_webstore_data_; }
private:
friend class base::RefCountedThreadSafe<Prompt>;
struct InstallPromptPermissions {
InstallPromptPermissions();
~InstallPromptPermissions();
std::vector<base::string16> permissions;
std::vector<base::string16> details;
std::vector<bool> is_showing_details;
};
bool ShouldDisplayRevokeButton() const;
bool ShouldDisplayRevokeFilesButton() const;
const PromptType type_;
// Permissions that are being requested (may not be all of an extension's
// permissions if only additional ones are being requested)
InstallPromptPermissions prompt_permissions_;
bool is_showing_details_for_retained_files_;
bool is_showing_details_for_retained_devices_;
// The extension being installed.
const extensions::Extension* extension_;
std::string delegated_username_;
// The icon to be displayed.
gfx::Image icon_;
// These fields are populated only when the prompt type is
// INLINE_INSTALL_PROMPT
// Already formatted to be locale-specific.
std::string localized_user_count_;
// Range is kMinExtensionRating to kMaxExtensionRating
double average_rating_;
int rating_count_;
// Whether we should display the user count (we anticipate this will be
// false if localized_user_count_ represents the number zero).
bool show_user_count_;
// Whether or not this prompt has been populated with data from the
// webstore.
bool has_webstore_data_;
std::vector<base::FilePath> retained_files_;
std::vector<base::string16> retained_device_messages_;
DISALLOW_COPY_AND_ASSIGN(Prompt);
};
static const int kMinExtensionRating = 0;
static const int kMaxExtensionRating = 5;
enum class Result {
ACCEPTED,
USER_CANCELED,
ABORTED,
};
using DoneCallback = base::Callback<void(Result result)>;
typedef base::Callback<void(ExtensionInstallPromptShowParams*,
const DoneCallback&,
std::unique_ptr<ExtensionInstallPrompt::Prompt>)>
ShowDialogCallback;
// Callback to show the default extension install dialog.
// The implementations of this function are platform-specific.
static ShowDialogCallback GetDefaultShowDialogCallback();
// Returns the appropriate prompt type for the given |extension|.
// TODO(devlin): This method is yucky - callers probably only care about one
// prompt type. We just need to comb through and figure out what it is.
static PromptType GetReEnablePromptTypeForExtension(
content::BrowserContext* context,
const extensions::Extension* extension);
// Creates a dummy extension from the |manifest|, replacing the name and
// description with the localizations if provided.
static scoped_refptr<extensions::Extension> GetLocalizedExtensionForDisplay(
const base::DictionaryValue* manifest,
int flags, // Extension::InitFromValueFlags
const std::string& id,
const std::string& localized_name,
const std::string& localized_description,
std::string* error);
// Creates a prompt with a parent web content.
explicit ExtensionInstallPrompt(content::WebContents* contents);
// Creates a prompt with a profile and a native window. The most recently
// active browser window (or a new browser window if there are no browser
// windows) is used if a new tab needs to be opened.
ExtensionInstallPrompt(Profile* profile, gfx::NativeWindow native_window);
virtual ~ExtensionInstallPrompt();
extensions::ExtensionInstallUI* install_ui() const {
return install_ui_.get();
}
// Starts the process to show the install dialog. Loads the icon (if |icon| is
// null), sets up the Prompt, and calls |show_dialog_callback| when ready to
// show.
// |extension| can be null in the case of a bndle install.
// If |icon| is null, this will attempt to load the extension's icon.
// |prompt| is used to pass in a prompt with additional data (like retained
// device permissions) or a different type. If not provided, |prompt| will
// be created as an INSTALL_PROMPT.
// |custom_permissions| will be used if provided; otherwise, the extensions
// current permissions are used.
//
// The |install_callback| *MUST* eventually be called.
void ShowDialog(const DoneCallback& install_callback,
const extensions::Extension* extension,
const SkBitmap* icon,
const ShowDialogCallback& show_dialog_callback);
void ShowDialog(const DoneCallback& install_callback,
const extensions::Extension* extension,
const SkBitmap* icon,
std::unique_ptr<Prompt> prompt,
const ShowDialogCallback& show_dialog_callback);
// Declared virtual for testing purposes.
// Note: if all you want to do is automatically confirm or cancel, prefer
// ScopedTestDialogAutoConfirm from extension_dialog_auto_confirm.h
virtual void ShowDialog(
const DoneCallback& install_callback,
const extensions::Extension* extension,
const SkBitmap* icon,
std::unique_ptr<Prompt> prompt,
std::unique_ptr<const extensions::PermissionSet> custom_permissions,
const ShowDialogCallback& show_dialog_callback);
// Installation was successful. This is declared virtual for testing.
virtual void OnInstallSuccess(
scoped_refptr<const extensions::Extension> extension,
SkBitmap* icon);
// Installation failed. This is declared virtual for testing.
virtual void OnInstallFailure(const extensions::CrxInstallError& error);
bool did_call_show_dialog() const { return did_call_show_dialog_; }
private:
// Sets the icon that will be used in any UI. If |icon| is NULL, or contains
// an empty bitmap, then a default icon will be used instead.
void SetIcon(const SkBitmap* icon);
// ImageLoader callback.
void OnImageLoaded(const gfx::Image& image);
// Starts the process of showing a confirmation UI, which is split into two.
// 1) Set off a 'load icon' task.
// 2) Handle the load icon response and show the UI (OnImageLoaded).
void LoadImageIfNeeded();
// Shows the actual UI (the icon should already be loaded).
void ShowConfirmation();
Profile* profile_;
base::ThreadChecker ui_thread_checker_;
// The extensions installation icon.
SkBitmap icon_;
// The extension we are showing the UI for.
scoped_refptr<const extensions::Extension> extension_;
// A custom set of permissions to show in the install prompt instead of the
// extension's active permissions.
std::unique_ptr<const extensions::PermissionSet> custom_permissions_;
// The object responsible for doing the UI specific actions.
std::unique_ptr<extensions::ExtensionInstallUI> install_ui_;
// Parameters to show the confirmation UI.
std::unique_ptr<ExtensionInstallPromptShowParams> show_params_;
// The callback to run with the result.
DoneCallback done_callback_;
// A pre-filled prompt.
std::unique_ptr<Prompt> prompt_;
// Used to show the confirm dialog.
ShowDialogCallback show_dialog_callback_;
// Whether or not the |show_dialog_callback_| was called.
bool did_call_show_dialog_;
base::WeakPtrFactory<ExtensionInstallPrompt> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ExtensionInstallPrompt);
};
#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_INSTALL_PROMPT_H_