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