C++程序  |  424行  |  15.69 KB

// 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 <string>
#include <vector>

#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/files/file_path.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string16.h"
#include "chrome/browser/extensions/crx_installer_error.h"
#include "extensions/common/url_pattern.h"
#include "google_apis/gaia/oauth2_mint_token_flow.h"
#include "google_apis/gaia/oauth2_token_service.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/native_widget_types.h"

class Browser;
class ExtensionInstallUI;
class InfoBarDelegate;
class Profile;

namespace base {
class DictionaryValue;
class MessageLoop;
}  // namespace base

namespace content {
class PageNavigator;
class WebContents;
}

namespace extensions {
class BundleInstaller;
class Extension;
class ExtensionWebstorePrivateApiTest;
class MockGetAuthTokenFunction;
class PermissionSet;
}  // namespace extensions

// Displays all the UI around extension installation.
class ExtensionInstallPrompt
    : public OAuth2MintTokenFlow::Delegate,
      public OAuth2TokenService::Consumer,
      public base::SupportsWeakPtr<ExtensionInstallPrompt> {
 public:
  enum PromptType {
    UNSET_PROMPT_TYPE = -1,
    INSTALL_PROMPT = 0,
    INLINE_INSTALL_PROMPT,
    BUNDLE_INSTALL_PROMPT,
    RE_ENABLE_PROMPT,
    PERMISSIONS_PROMPT,
    EXTERNAL_INSTALL_PROMPT,
    POST_INSTALL_PERMISSIONS_PROMPT,
    LAUNCH_PROMPT,
    NUM_PROMPT_TYPES
  };

  enum DetailsType {
    PERMISSIONS_DETAILS = 0,
    OAUTH_DETAILS,
    RETAINED_FILES_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();

    // Sets the permission list for this prompt.
    void SetPermissions(const std::vector<base::string16>& permissions);
    // Sets the permission list details for this prompt.
    void SetPermissionsDetails(const std::vector<base::string16>& details);
    void SetIsShowingDetails(DetailsType type,
                             size_t index,
                             bool is_showing_details);
    void SetInlineInstallWebstoreData(const std::string& localized_user_count,
                                      bool show_user_count,
                                      double average_rating,
                                      int rating_count);
    void SetOAuthIssueAdvice(const IssueAdviceInfo& issue_advice);
    void SetUserNameFromProfile(Profile* profile);

    PromptType type() const { return type_; }
    void set_type(PromptType type) { type_ = type; }

    // Getters for UI element labels.
    base::string16 GetDialogTitle() const;
    base::string16 GetHeading() const;
    int GetDialogButtons() const;
    bool HasAcceptButtonLabel() const;
    base::string16 GetAcceptButtonLabel() const;
    bool HasAbortButtonLabel() const;
    base::string16 GetAbortButtonLabel() const;
    base::string16 GetPermissionsHeading() const;
    base::string16 GetOAuthHeading() const;
    base::string16 GetRetainedFilesHeading() const;

    bool ShouldShowPermissions() const;

    // Getters for webstore metadata. Only populated when the type is
    // INLINE_INSTALL_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 GetOAuthIssueCount() const;
    const IssueAdviceInfoEntry& GetOAuthIssue(size_t index) const;
    size_t GetRetainedFileCount() const;
    base::string16 GetRetainedFile(size_t index) const;

    // Populated for BUNDLE_INSTALL_PROMPT.
    const extensions::BundleInstaller* bundle() const { return bundle_; }
    void set_bundle(const extensions::BundleInstaller* bundle) {
      bundle_ = bundle;
    }

    // Populated for all other types.
    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;
    }

    const gfx::Image& icon() const { return icon_; }
    void set_icon(const gfx::Image& icon) { icon_ = icon; }

   private:
    bool ShouldDisplayRevokeFilesButton() const;

    PromptType type_;

    // Permissions that are being requested (may not be all of an extension's
    // permissions if only additional ones are being requested)
    std::vector<base::string16> permissions_;
    std::vector<base::string16> details_;
    std::vector<bool> is_showing_details_for_permissions_;
    std::vector<bool> is_showing_details_for_oauth_;
    bool is_showing_details_for_retained_files_;

    // Descriptions and details for OAuth2 permissions to display to the user.
    // These correspond to permission scopes.
    IssueAdviceInfo oauth_issue_advice_;

    // User name to be used in Oauth heading label.
    base::string16 oauth_user_name_;

    // The extension or bundle being installed.
    const extensions::Extension* extension_;
    const extensions::BundleInstaller* bundle_;

    // 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_;

    std::vector<base::FilePath> retained_files_;
  };

  static const int kMinExtensionRating = 0;
  static const int kMaxExtensionRating = 5;

  class Delegate {
   public:
    // We call this method to signal that the installation should continue.
    virtual void InstallUIProceed() = 0;

    // We call this method to signal that the installation should stop, with
    // |user_initiated| true if the installation was stopped by the user.
    virtual void InstallUIAbort(bool user_initiated) = 0;

   protected:
    virtual ~Delegate() {}
  };

  // Parameters to show a prompt dialog. Two sets of the
  // parameters are supported: either use a parent WebContents or use a
  // parent NativeWindow + a PageNavigator.
  struct ShowParams {
    explicit ShowParams(content::WebContents* contents);
    ShowParams(gfx::NativeWindow window, content::PageNavigator* navigator);

    // Parent web contents of the install UI dialog. This can be NULL.
    content::WebContents* parent_web_contents;

    // NativeWindow parent and navigator. If initialized using a parent web
    // contents, these are derived from it.
    gfx::NativeWindow parent_window;
    content::PageNavigator* navigator;
  };

  typedef base::Callback<void(const ExtensionInstallPrompt::ShowParams&,
                              ExtensionInstallPrompt::Delegate*,
                              const ExtensionInstallPrompt::Prompt&)>
      ShowDialogCallback;

  // Callback to show the default extension install dialog.
  // The implementations of this function are platform-specific.
  static ShowDialogCallback GetDefaultShowDialogCallback();

  // 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, a native window and a page navigator.
  ExtensionInstallPrompt(Profile* profile,
                         gfx::NativeWindow native_window,
                         content::PageNavigator* navigator);

  virtual ~ExtensionInstallPrompt();

  ExtensionInstallUI* install_ui() const { return install_ui_.get(); }

  bool record_oauth2_grant() const { return record_oauth2_grant_; }

  content::WebContents* parent_web_contents() const {
    return show_params_.parent_web_contents;
  }

  // This is called by the bundle installer to verify whether the bundle
  // should be installed.
  //
  // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
  virtual void ConfirmBundleInstall(
      extensions::BundleInstaller* bundle,
      const extensions::PermissionSet* permissions);

  // This is called by the standalone installer to verify whether the install
  // from the webstore should proceed.
  //
  // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
  virtual void ConfirmStandaloneInstall(Delegate* delegate,
                                        const extensions::Extension* extension,
                                        SkBitmap* icon,
                                        const Prompt& prompt);

  // This is called by the installer to verify whether the installation from
  // the webstore should proceed. |show_dialog_callback| is optional and can be
  // NULL.
  //
  // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
  virtual void ConfirmWebstoreInstall(
      Delegate* delegate,
      const extensions::Extension* extension,
      const SkBitmap* icon,
      const ShowDialogCallback& show_dialog_callback);

  // This is called by the installer to verify whether the installation should
  // proceed. This is declared virtual for testing. |show_dialog_callback| is
  // optional and can be NULL.
  //
  // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
  virtual void ConfirmInstall(Delegate* delegate,
                              const extensions::Extension* extension,
                              const ShowDialogCallback& show_dialog_callback);

  // This is called by the app handler launcher to verify whether the app
  // should be re-enabled. This is declared virtual for testing.
  //
  // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
  virtual void ConfirmReEnable(Delegate* delegate,
                               const extensions::Extension* extension);

  // This is called by the external install alert UI to verify whether the
  // extension should be enabled (external extensions are installed disabled).
  //
  // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
  virtual void ConfirmExternalInstall(
      Delegate* delegate,
      const extensions::Extension* extension,
      const ShowDialogCallback& show_dialog_callback);

  // This is called by the extension permissions API to verify whether an
  // extension may be granted additional permissions.
  //
  // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
  virtual void ConfirmPermissions(Delegate* delegate,
                                  const extensions::Extension* extension,
                                  const extensions::PermissionSet* permissions);

  // This is called by the extension identity API to verify whether an
  // extension can be granted an OAuth2 token.
  //
  // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
  virtual void ConfirmIssueAdvice(Delegate* delegate,
                                  const extensions::Extension* extension,
                                  const IssueAdviceInfo& issue_advice);

  // This is called by the app handler launcher to review what permissions the
  // extension or app currently has.
  //
  // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
  virtual void ReviewPermissions(
      Delegate* delegate,
      const extensions::Extension* extension,
      const std::vector<base::FilePath>& retained_file_paths);

  // Installation was successful. This is declared virtual for testing.
  virtual void OnInstallSuccess(const extensions::Extension* extension,
                                SkBitmap* icon);

  // Installation failed. This is declared virtual for testing.
  virtual void OnInstallFailure(const extensions::CrxInstallerError& error);

 protected:
  friend class extensions::ExtensionWebstorePrivateApiTest;
  friend class extensions::MockGetAuthTokenFunction;
  friend class WebstoreStartupInstallUnpackFailureTest;

  // Whether or not we should record the oauth2 grant upon successful install.
  bool record_oauth2_grant_;

 private:
  friend class GalleryInstallApiTestObserver;

  // 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();

  // OAuth2TokenService::Consumer implementation:
  virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
                                 const std::string& access_token,
                                 const base::Time& expiration_time) OVERRIDE;
  virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
                                 const GoogleServiceAuthError& error) OVERRIDE;

  // OAuth2MintTokenFlow::Delegate implementation:
  virtual void OnIssueAdviceSuccess(
      const IssueAdviceInfo& issue_advice) OVERRIDE;
  virtual void OnMintTokenFailure(
      const GoogleServiceAuthError& error) OVERRIDE;

  // Shows the actual UI (the icon should already be loaded).
  void ShowConfirmation();

  base::MessageLoop* ui_loop_;

  // The extensions installation icon.
  SkBitmap icon_;

  // The extension we are showing the UI for, if type is not
  // BUNDLE_INSTALL_PROMPT.
  const extensions::Extension* extension_;

  // The bundle we are showing the UI for, if type BUNDLE_INSTALL_PROMPT.
  const extensions::BundleInstaller* bundle_;

  // The permissions being prompted for.
  scoped_refptr<const extensions::PermissionSet> permissions_;

  // The object responsible for doing the UI specific actions.
  scoped_ptr<ExtensionInstallUI> install_ui_;

  // Parameters to show the confirmation UI.
  ShowParams show_params_;

  // The delegate we will call Proceed/Abort on after confirmation UI.
  Delegate* delegate_;

  // A pre-filled prompt.
  Prompt prompt_;

  scoped_ptr<OAuth2TokenService::Request> login_token_request_;
  scoped_ptr<OAuth2MintTokenFlow> token_flow_;

  // Used to show the confirm dialog.
  ShowDialogCallback show_dialog_callback_;
};

#endif  // CHROME_BROWSER_EXTENSIONS_EXTENSION_INSTALL_PROMPT_H_