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 #ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_INSTALL_PROMPT_H_
      6 #define CHROME_BROWSER_EXTENSIONS_EXTENSION_INSTALL_PROMPT_H_
      7 
      8 #include <string>
      9 #include <vector>
     10 
     11 #include "base/callback.h"
     12 #include "base/compiler_specific.h"
     13 #include "base/files/file_path.h"
     14 #include "base/memory/ref_counted.h"
     15 #include "base/memory/scoped_ptr.h"
     16 #include "base/memory/weak_ptr.h"
     17 #include "base/strings/string16.h"
     18 #include "chrome/browser/extensions/crx_installer_error.h"
     19 #include "chrome/browser/extensions/extension_install_prompt_experiment.h"
     20 #include "extensions/common/url_pattern.h"
     21 #include "third_party/skia/include/core/SkBitmap.h"
     22 #include "ui/gfx/image/image.h"
     23 #include "ui/gfx/image/image_skia.h"
     24 #include "ui/gfx/native_widget_types.h"
     25 
     26 class Browser;
     27 class ExtensionInstallUI;
     28 class Profile;
     29 
     30 namespace base {
     31 class DictionaryValue;
     32 class MessageLoop;
     33 }  // namespace base
     34 
     35 namespace content {
     36 class PageNavigator;
     37 class WebContents;
     38 }
     39 
     40 namespace extensions {
     41 class BundleInstaller;
     42 class Extension;
     43 class ExtensionWebstorePrivateApiTest;
     44 class MockGetAuthTokenFunction;
     45 class PermissionSet;
     46 }  // namespace extensions
     47 
     48 namespace infobars {
     49 class InfoBarDelegate;
     50 }
     51 
     52 // Displays all the UI around extension installation.
     53 class ExtensionInstallPrompt
     54     : public base::SupportsWeakPtr<ExtensionInstallPrompt> {
     55  public:
     56   // This enum is associated with Extensions.InstallPrompt_Type UMA histogram.
     57   // Do not modify existing values and add new values only to the end.
     58   enum PromptType {
     59     UNSET_PROMPT_TYPE = -1,
     60     INSTALL_PROMPT = 0,
     61     INLINE_INSTALL_PROMPT,
     62     BUNDLE_INSTALL_PROMPT,
     63     RE_ENABLE_PROMPT,
     64     PERMISSIONS_PROMPT,
     65     EXTERNAL_INSTALL_PROMPT,
     66     POST_INSTALL_PERMISSIONS_PROMPT,
     67     LAUNCH_PROMPT,
     68     REMOTE_INSTALL_PROMPT,
     69     NUM_PROMPT_TYPES
     70   };
     71 
     72   enum DetailsType {
     73     PERMISSIONS_DETAILS = 0,
     74     RETAINED_FILES_DETAILS,
     75   };
     76 
     77   // Extra information needed to display an installation or uninstallation
     78   // prompt. Gets populated with raw data and exposes getters for formatted
     79   // strings so that the GTK/views/Cocoa install dialogs don't have to repeat
     80   // that logic.
     81   // Ref-counted because we pass around the prompt independent of the full
     82   // ExtensionInstallPrompt.
     83   class Prompt : public base::RefCountedThreadSafe<Prompt> {
     84    public:
     85     explicit Prompt(PromptType type);
     86 
     87     // Sets the permission list for this prompt.
     88     void SetPermissions(const std::vector<base::string16>& permissions);
     89     // Sets the permission list details for this prompt.
     90     void SetPermissionsDetails(const std::vector<base::string16>& details);
     91     void SetIsShowingDetails(DetailsType type,
     92                              size_t index,
     93                              bool is_showing_details);
     94     void SetWebstoreData(const std::string& localized_user_count,
     95                          bool show_user_count,
     96                          double average_rating,
     97                          int rating_count);
     98     void SetUserNameFromProfile(Profile* profile);
     99 
    100     PromptType type() const { return type_; }
    101     void set_type(PromptType type) { type_ = type; }
    102 
    103     // Getters for UI element labels.
    104     base::string16 GetDialogTitle() const;
    105     base::string16 GetHeading() const;
    106     int GetDialogButtons() const;
    107     bool HasAcceptButtonLabel() const;
    108     base::string16 GetAcceptButtonLabel() const;
    109     bool HasAbortButtonLabel() const;
    110     base::string16 GetAbortButtonLabel() const;
    111     base::string16 GetPermissionsHeading() const;
    112     base::string16 GetRetainedFilesHeading() const;
    113 
    114     bool ShouldShowPermissions() const;
    115     bool ShouldShowExplanationText() const;
    116 
    117     // Getters for webstore metadata. Only populated when the type is
    118     // INLINE_INSTALL_PROMPT.
    119 
    120     // The star display logic replicates the one used by the webstore (from
    121     // components.ratingutils.setFractionalYellowStars). Callers pass in an
    122     // "appender", which will be repeatedly called back with the star images
    123     // that they append to the star display area.
    124     typedef void(*StarAppender)(const gfx::ImageSkia*, void*);
    125     void AppendRatingStars(StarAppender appender, void* data) const;
    126     base::string16 GetRatingCount() const;
    127     base::string16 GetUserCount() const;
    128     size_t GetPermissionCount() const;
    129     size_t GetPermissionsDetailsCount() const;
    130     base::string16 GetPermission(size_t index) const;
    131     base::string16 GetPermissionsDetails(size_t index) const;
    132     bool GetIsShowingDetails(DetailsType type, size_t index) const;
    133     size_t GetRetainedFileCount() const;
    134     base::string16 GetRetainedFile(size_t index) const;
    135 
    136     // Populated for BUNDLE_INSTALL_PROMPT.
    137     const extensions::BundleInstaller* bundle() const { return bundle_; }
    138     void set_bundle(const extensions::BundleInstaller* bundle) {
    139       bundle_ = bundle;
    140     }
    141 
    142     // Populated for all other types.
    143     const extensions::Extension* extension() const { return extension_; }
    144     void set_extension(const extensions::Extension* extension) {
    145       extension_ = extension;
    146     }
    147 
    148     // May be populated for POST_INSTALL_PERMISSIONS_PROMPT.
    149     void set_retained_files(const std::vector<base::FilePath>& retained_files) {
    150       retained_files_ = retained_files;
    151     }
    152 
    153     const gfx::Image& icon() const { return icon_; }
    154     void set_icon(const gfx::Image& icon) { icon_ = icon; }
    155 
    156     bool has_webstore_data() const { return has_webstore_data_; }
    157 
    158     const ExtensionInstallPromptExperiment* experiment() const {
    159       return experiment_;
    160     }
    161     void set_experiment(ExtensionInstallPromptExperiment* experiment) {
    162       experiment_ = experiment;
    163     }
    164 
    165    private:
    166     friend class base::RefCountedThreadSafe<Prompt>;
    167 
    168     virtual ~Prompt();
    169 
    170     bool ShouldDisplayRevokeFilesButton() const;
    171 
    172     PromptType type_;
    173 
    174     // Permissions that are being requested (may not be all of an extension's
    175     // permissions if only additional ones are being requested)
    176     std::vector<base::string16> permissions_;
    177     std::vector<base::string16> details_;
    178     std::vector<bool> is_showing_details_for_permissions_;
    179     bool is_showing_details_for_retained_files_;
    180 
    181     // The extension or bundle being installed.
    182     const extensions::Extension* extension_;
    183     const extensions::BundleInstaller* bundle_;
    184 
    185     // The icon to be displayed.
    186     gfx::Image icon_;
    187 
    188     // These fields are populated only when the prompt type is
    189     // INLINE_INSTALL_PROMPT
    190     // Already formatted to be locale-specific.
    191     std::string localized_user_count_;
    192     // Range is kMinExtensionRating to kMaxExtensionRating
    193     double average_rating_;
    194     int rating_count_;
    195 
    196     // Whether we should display the user count (we anticipate this will be
    197     // false if localized_user_count_ represents the number zero).
    198     bool show_user_count_;
    199 
    200     // Whether or not this prompt has been populated with data from the
    201     // webstore.
    202     bool has_webstore_data_;
    203 
    204     std::vector<base::FilePath> retained_files_;
    205 
    206     scoped_refptr<ExtensionInstallPromptExperiment> experiment_;
    207 
    208     DISALLOW_COPY_AND_ASSIGN(Prompt);
    209   };
    210 
    211   static const int kMinExtensionRating = 0;
    212   static const int kMaxExtensionRating = 5;
    213 
    214   class Delegate {
    215    public:
    216     // We call this method to signal that the installation should continue.
    217     virtual void InstallUIProceed() = 0;
    218 
    219     // We call this method to signal that the installation should stop, with
    220     // |user_initiated| true if the installation was stopped by the user.
    221     virtual void InstallUIAbort(bool user_initiated) = 0;
    222 
    223    protected:
    224     virtual ~Delegate() {}
    225   };
    226 
    227   // Parameters to show a prompt dialog. Two sets of the
    228   // parameters are supported: either use a parent WebContents or use a
    229   // parent NativeWindow + a PageNavigator.
    230   struct ShowParams {
    231     explicit ShowParams(content::WebContents* contents);
    232     ShowParams(gfx::NativeWindow window, content::PageNavigator* navigator);
    233 
    234     // Parent web contents of the install UI dialog. This can be NULL.
    235     content::WebContents* parent_web_contents;
    236 
    237     // NativeWindow parent and navigator. If initialized using a parent web
    238     // contents, these are derived from it.
    239     gfx::NativeWindow parent_window;
    240     content::PageNavigator* navigator;
    241   };
    242 
    243   typedef base::Callback<void(const ExtensionInstallPrompt::ShowParams&,
    244                               ExtensionInstallPrompt::Delegate*,
    245                               scoped_refptr<ExtensionInstallPrompt::Prompt>)>
    246       ShowDialogCallback;
    247 
    248   // Callback to show the default extension install dialog.
    249   // The implementations of this function are platform-specific.
    250   static ShowDialogCallback GetDefaultShowDialogCallback();
    251 
    252   // Creates a dummy extension from the |manifest|, replacing the name and
    253   // description with the localizations if provided.
    254   static scoped_refptr<extensions::Extension> GetLocalizedExtensionForDisplay(
    255       const base::DictionaryValue* manifest,
    256       int flags,  // Extension::InitFromValueFlags
    257       const std::string& id,
    258       const std::string& localized_name,
    259       const std::string& localized_description,
    260       std::string* error);
    261 
    262   // Creates a prompt with a parent web content.
    263   explicit ExtensionInstallPrompt(content::WebContents* contents);
    264 
    265   // Creates a prompt with a profile, a native window and a page navigator.
    266   ExtensionInstallPrompt(Profile* profile,
    267                          gfx::NativeWindow native_window,
    268                          content::PageNavigator* navigator);
    269 
    270   virtual ~ExtensionInstallPrompt();
    271 
    272   ExtensionInstallUI* install_ui() const { return install_ui_.get(); }
    273 
    274   content::WebContents* parent_web_contents() const {
    275     return show_params_.parent_web_contents;
    276   }
    277 
    278   // This is called by the bundle installer to verify whether the bundle
    279   // should be installed.
    280   //
    281   // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
    282   virtual void ConfirmBundleInstall(
    283       extensions::BundleInstaller* bundle,
    284       const extensions::PermissionSet* permissions);
    285 
    286   // This is called by the standalone installer to verify whether the install
    287   // from the webstore should proceed.
    288   //
    289   // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
    290   virtual void ConfirmStandaloneInstall(Delegate* delegate,
    291                                         const extensions::Extension* extension,
    292                                         SkBitmap* icon,
    293                                         scoped_refptr<Prompt> prompt);
    294 
    295   // This is called by the installer to verify whether the installation from
    296   // the webstore should proceed. |show_dialog_callback| is optional and can be
    297   // NULL.
    298   //
    299   // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
    300   virtual void ConfirmWebstoreInstall(
    301       Delegate* delegate,
    302       const extensions::Extension* extension,
    303       const SkBitmap* icon,
    304       const ShowDialogCallback& show_dialog_callback);
    305 
    306   // This is called by the installer to verify whether the installation should
    307   // proceed. This is declared virtual for testing. |show_dialog_callback| is
    308   // optional and can be NULL.
    309   //
    310   // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
    311   virtual void ConfirmInstall(Delegate* delegate,
    312                               const extensions::Extension* extension,
    313                               const ShowDialogCallback& show_dialog_callback);
    314 
    315   // This is called by the app handler launcher to verify whether the app
    316   // should be re-enabled. This is declared virtual for testing.
    317   //
    318   // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
    319   virtual void ConfirmReEnable(Delegate* delegate,
    320                                const extensions::Extension* extension);
    321 
    322   // This is called by the external install alert UI to verify whether the
    323   // extension should be enabled (external extensions are installed disabled).
    324   //
    325   // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
    326   virtual void ConfirmExternalInstall(
    327       Delegate* delegate,
    328       const extensions::Extension* extension,
    329       const ShowDialogCallback& show_dialog_callback,
    330       scoped_refptr<Prompt> prompt);
    331 
    332   // This is called by the extension permissions API to verify whether an
    333   // extension may be granted additional permissions.
    334   //
    335   // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
    336   virtual void ConfirmPermissions(Delegate* delegate,
    337                                   const extensions::Extension* extension,
    338                                   const extensions::PermissionSet* permissions);
    339 
    340   // This is called by the app handler launcher to review what permissions the
    341   // extension or app currently has.
    342   //
    343   // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
    344   virtual void ReviewPermissions(
    345       Delegate* delegate,
    346       const extensions::Extension* extension,
    347       const std::vector<base::FilePath>& retained_file_paths);
    348 
    349   // Installation was successful. This is declared virtual for testing.
    350   virtual void OnInstallSuccess(const extensions::Extension* extension,
    351                                 SkBitmap* icon);
    352 
    353   // Installation failed. This is declared virtual for testing.
    354   virtual void OnInstallFailure(const extensions::CrxInstallerError& error);
    355 
    356   void set_callback_for_test(const ShowDialogCallback& show_dialog_callback) {
    357     show_dialog_callback_ = show_dialog_callback;
    358   }
    359 
    360  protected:
    361   friend class extensions::ExtensionWebstorePrivateApiTest;
    362   friend class WebstoreStartupInstallUnpackFailureTest;
    363 
    364   // Whether or not we should record the oauth2 grant upon successful install.
    365   bool record_oauth2_grant_;
    366 
    367  private:
    368   friend class GalleryInstallApiTestObserver;
    369 
    370   // Sets the icon that will be used in any UI. If |icon| is NULL, or contains
    371   // an empty bitmap, then a default icon will be used instead.
    372   void SetIcon(const SkBitmap* icon);
    373 
    374   // ImageLoader callback.
    375   void OnImageLoaded(const gfx::Image& image);
    376 
    377   // Starts the process of showing a confirmation UI, which is split into two.
    378   // 1) Set off a 'load icon' task.
    379   // 2) Handle the load icon response and show the UI (OnImageLoaded).
    380   void LoadImageIfNeeded();
    381 
    382   // Shows the actual UI (the icon should already be loaded).
    383   void ShowConfirmation();
    384 
    385   base::MessageLoop* ui_loop_;
    386 
    387   // The extensions installation icon.
    388   SkBitmap icon_;
    389 
    390   // The extension we are showing the UI for, if type is not
    391   // BUNDLE_INSTALL_PROMPT.
    392   const extensions::Extension* extension_;
    393 
    394   // The bundle we are showing the UI for, if type BUNDLE_INSTALL_PROMPT.
    395   const extensions::BundleInstaller* bundle_;
    396 
    397   // The permissions being prompted for.
    398   scoped_refptr<const extensions::PermissionSet> permissions_;
    399 
    400   // The object responsible for doing the UI specific actions.
    401   scoped_ptr<ExtensionInstallUI> install_ui_;
    402 
    403   // Parameters to show the confirmation UI.
    404   ShowParams show_params_;
    405 
    406   // The delegate we will call Proceed/Abort on after confirmation UI.
    407   Delegate* delegate_;
    408 
    409   // A pre-filled prompt.
    410   scoped_refptr<Prompt> prompt_;
    411 
    412   // Used to show the confirm dialog.
    413   ShowDialogCallback show_dialog_callback_;
    414 };
    415 
    416 #endif  // CHROME_BROWSER_EXTENSIONS_EXTENSION_INSTALL_PROMPT_H_
    417