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.
5 #ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_INSTALL_PROMPT_H_
6 #define CHROME_BROWSER_EXTENSIONS_EXTENSION_INSTALL_PROMPT_H_
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"
27 class ExtensionInstallUI;
31 class DictionaryValue;
40 namespace extensions {
41 class BundleInstaller;
43 class ExtensionWebstorePrivateApiTest;
44 class MockGetAuthTokenFunction;
46 } // namespace extensions
49 class InfoBarDelegate;
52 // Displays all the UI around extension installation.
53 class ExtensionInstallPrompt
54 : public base::SupportsWeakPtr<ExtensionInstallPrompt> {
56 // A setting to cause extension/app installs from the webstore skip the normal
57 // confirmation dialog. This should only be used in tests.
58 enum AutoConfirmForTests {
59 NONE, // The prompt will show normally.
60 ACCEPT, // The prompt will always accept.
61 CANCEL, // The prompt will always cancel.
63 static AutoConfirmForTests g_auto_confirm_for_tests;
65 // This enum is associated with Extensions.InstallPrompt_Type UMA histogram.
66 // Do not modify existing values and add new values only to the end.
68 UNSET_PROMPT_TYPE = -1,
70 INLINE_INSTALL_PROMPT,
71 BUNDLE_INSTALL_PROMPT,
74 EXTERNAL_INSTALL_PROMPT,
75 POST_INSTALL_PERMISSIONS_PROMPT,
77 REMOTE_INSTALL_PROMPT,
82 PERMISSIONS_DETAILS = 0,
83 RETAINED_FILES_DETAILS,
86 static std::string PromptTypeToString(PromptType type);
88 // Extra information needed to display an installation or uninstallation
89 // prompt. Gets populated with raw data and exposes getters for formatted
90 // strings so that the GTK/views/Cocoa install dialogs don't have to repeat
92 // Ref-counted because we pass around the prompt independent of the full
93 // ExtensionInstallPrompt.
94 class Prompt : public base::RefCountedThreadSafe<Prompt> {
96 explicit Prompt(PromptType type);
98 // Sets the permission list for this prompt.
99 void SetPermissions(const std::vector<base::string16>& permissions);
100 // Sets the permission list details for this prompt.
101 void SetPermissionsDetails(const std::vector<base::string16>& details);
102 void SetIsShowingDetails(DetailsType type,
104 bool is_showing_details);
105 void SetWebstoreData(const std::string& localized_user_count,
106 bool show_user_count,
107 double average_rating,
109 void SetUserNameFromProfile(Profile* profile);
111 PromptType type() const { return type_; }
112 void set_type(PromptType type) { type_ = type; }
114 // Getters for UI element labels.
115 base::string16 GetDialogTitle() const;
116 base::string16 GetHeading() const;
117 int GetDialogButtons() const;
118 bool HasAcceptButtonLabel() const;
119 base::string16 GetAcceptButtonLabel() const;
120 bool HasAbortButtonLabel() const;
121 base::string16 GetAbortButtonLabel() const;
122 base::string16 GetPermissionsHeading() const;
123 base::string16 GetRetainedFilesHeading() const;
125 bool ShouldShowPermissions() const;
126 bool ShouldShowExplanationText() const;
128 // Getters for webstore metadata. Only populated when the type is
129 // INLINE_INSTALL_PROMPT.
131 // The star display logic replicates the one used by the webstore (from
132 // components.ratingutils.setFractionalYellowStars). Callers pass in an
133 // "appender", which will be repeatedly called back with the star images
134 // that they append to the star display area.
135 typedef void(*StarAppender)(const gfx::ImageSkia*, void*);
136 void AppendRatingStars(StarAppender appender, void* data) const;
137 base::string16 GetRatingCount() const;
138 base::string16 GetUserCount() const;
139 size_t GetPermissionCount() const;
140 size_t GetPermissionsDetailsCount() const;
141 base::string16 GetPermission(size_t index) const;
142 base::string16 GetPermissionsDetails(size_t index) const;
143 bool GetIsShowingDetails(DetailsType type, size_t index) const;
144 size_t GetRetainedFileCount() const;
145 base::string16 GetRetainedFile(size_t index) const;
147 // Populated for BUNDLE_INSTALL_PROMPT.
148 const extensions::BundleInstaller* bundle() const { return bundle_; }
149 void set_bundle(const extensions::BundleInstaller* bundle) {
153 // Populated for all other types.
154 const extensions::Extension* extension() const { return extension_; }
155 void set_extension(const extensions::Extension* extension) {
156 extension_ = extension;
159 // May be populated for POST_INSTALL_PERMISSIONS_PROMPT.
160 void set_retained_files(const std::vector<base::FilePath>& retained_files) {
161 retained_files_ = retained_files;
164 const gfx::Image& icon() const { return icon_; }
165 void set_icon(const gfx::Image& icon) { icon_ = icon; }
167 bool has_webstore_data() const { return has_webstore_data_; }
169 const ExtensionInstallPromptExperiment* experiment() const {
172 void set_experiment(ExtensionInstallPromptExperiment* experiment) {
173 experiment_ = experiment;
177 friend class base::RefCountedThreadSafe<Prompt>;
181 bool ShouldDisplayRevokeFilesButton() const;
185 // Permissions that are being requested (may not be all of an extension's
186 // permissions if only additional ones are being requested)
187 std::vector<base::string16> permissions_;
188 std::vector<base::string16> details_;
189 std::vector<bool> is_showing_details_for_permissions_;
190 bool is_showing_details_for_retained_files_;
192 // The extension or bundle being installed.
193 const extensions::Extension* extension_;
194 const extensions::BundleInstaller* bundle_;
196 // The icon to be displayed.
199 // These fields are populated only when the prompt type is
200 // INLINE_INSTALL_PROMPT
201 // Already formatted to be locale-specific.
202 std::string localized_user_count_;
203 // Range is kMinExtensionRating to kMaxExtensionRating
204 double average_rating_;
207 // Whether we should display the user count (we anticipate this will be
208 // false if localized_user_count_ represents the number zero).
209 bool show_user_count_;
211 // Whether or not this prompt has been populated with data from the
213 bool has_webstore_data_;
215 std::vector<base::FilePath> retained_files_;
217 scoped_refptr<ExtensionInstallPromptExperiment> experiment_;
219 DISALLOW_COPY_AND_ASSIGN(Prompt);
222 static const int kMinExtensionRating = 0;
223 static const int kMaxExtensionRating = 5;
227 // We call this method to signal that the installation should continue.
228 virtual void InstallUIProceed() = 0;
230 // We call this method to signal that the installation should stop, with
231 // |user_initiated| true if the installation was stopped by the user.
232 virtual void InstallUIAbort(bool user_initiated) = 0;
235 virtual ~Delegate() {}
238 // Parameters to show a prompt dialog. Two sets of the
239 // parameters are supported: either use a parent WebContents or use a
240 // parent NativeWindow + a PageNavigator.
242 explicit ShowParams(content::WebContents* contents);
243 ShowParams(gfx::NativeWindow window, content::PageNavigator* navigator);
245 // Parent web contents of the install UI dialog. This can be NULL.
246 content::WebContents* parent_web_contents;
248 // NativeWindow parent and navigator. If initialized using a parent web
249 // contents, these are derived from it.
250 gfx::NativeWindow parent_window;
251 content::PageNavigator* navigator;
254 typedef base::Callback<void(const ExtensionInstallPrompt::ShowParams&,
255 ExtensionInstallPrompt::Delegate*,
256 scoped_refptr<ExtensionInstallPrompt::Prompt>)>
259 // Callback to show the default extension install dialog.
260 // The implementations of this function are platform-specific.
261 static ShowDialogCallback GetDefaultShowDialogCallback();
263 // Creates a dummy extension from the |manifest|, replacing the name and
264 // description with the localizations if provided.
265 static scoped_refptr<extensions::Extension> GetLocalizedExtensionForDisplay(
266 const base::DictionaryValue* manifest,
267 int flags, // Extension::InitFromValueFlags
268 const std::string& id,
269 const std::string& localized_name,
270 const std::string& localized_description,
273 // Creates a prompt with a parent web content.
274 explicit ExtensionInstallPrompt(content::WebContents* contents);
276 // Creates a prompt with a profile, a native window and a page navigator.
277 ExtensionInstallPrompt(Profile* profile,
278 gfx::NativeWindow native_window,
279 content::PageNavigator* navigator);
281 virtual ~ExtensionInstallPrompt();
283 ExtensionInstallUI* install_ui() const { return install_ui_.get(); }
285 content::WebContents* parent_web_contents() const {
286 return show_params_.parent_web_contents;
289 // This is called by the bundle installer to verify whether the bundle
290 // should be installed.
292 // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
293 virtual void ConfirmBundleInstall(
294 extensions::BundleInstaller* bundle,
295 const extensions::PermissionSet* permissions);
297 // This is called by the standalone installer to verify whether the install
298 // from the webstore should proceed.
300 // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
301 virtual void ConfirmStandaloneInstall(Delegate* delegate,
302 const extensions::Extension* extension,
304 scoped_refptr<Prompt> prompt);
306 // This is called by the installer to verify whether the installation from
307 // the webstore should proceed. |show_dialog_callback| is optional and can be
310 // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
311 virtual void ConfirmWebstoreInstall(
313 const extensions::Extension* extension,
314 const SkBitmap* icon,
315 const ShowDialogCallback& show_dialog_callback);
317 // This is called by the installer to verify whether the installation should
318 // proceed. This is declared virtual for testing. |show_dialog_callback| is
319 // optional and can be NULL.
321 // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
322 virtual void ConfirmInstall(Delegate* delegate,
323 const extensions::Extension* extension,
324 const ShowDialogCallback& show_dialog_callback);
326 // This is called by the app handler launcher to verify whether the app
327 // should be re-enabled. This is declared virtual for testing.
329 // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
330 virtual void ConfirmReEnable(Delegate* delegate,
331 const extensions::Extension* extension);
333 // This is called by the external install alert UI to verify whether the
334 // extension should be enabled (external extensions are installed disabled).
336 // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
337 virtual void ConfirmExternalInstall(
339 const extensions::Extension* extension,
340 const ShowDialogCallback& show_dialog_callback,
341 scoped_refptr<Prompt> prompt);
343 // This is called by the extension permissions API to verify whether an
344 // extension may be granted additional permissions.
346 // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
347 virtual void ConfirmPermissions(Delegate* delegate,
348 const extensions::Extension* extension,
349 const extensions::PermissionSet* permissions);
351 // This is called by the app handler launcher to review what permissions the
352 // extension or app currently has.
354 // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
355 virtual void ReviewPermissions(
357 const extensions::Extension* extension,
358 const std::vector<base::FilePath>& retained_file_paths);
360 // Installation was successful. This is declared virtual for testing.
361 virtual void OnInstallSuccess(const extensions::Extension* extension,
364 // Installation failed. This is declared virtual for testing.
365 virtual void OnInstallFailure(const extensions::CrxInstallerError& error);
367 void set_callback_for_test(const ShowDialogCallback& show_dialog_callback) {
368 show_dialog_callback_ = show_dialog_callback;
372 friend class extensions::ExtensionWebstorePrivateApiTest;
373 friend class WebstoreStartupInstallUnpackFailureTest;
375 // Whether or not we should record the oauth2 grant upon successful install.
376 bool record_oauth2_grant_;
379 friend class GalleryInstallApiTestObserver;
381 // Sets the icon that will be used in any UI. If |icon| is NULL, or contains
382 // an empty bitmap, then a default icon will be used instead.
383 void SetIcon(const SkBitmap* icon);
385 // ImageLoader callback.
386 void OnImageLoaded(const gfx::Image& image);
388 // Starts the process of showing a confirmation UI, which is split into two.
389 // 1) Set off a 'load icon' task.
390 // 2) Handle the load icon response and show the UI (OnImageLoaded).
391 void LoadImageIfNeeded();
393 // Shows the actual UI (the icon should already be loaded).
394 void ShowConfirmation();
396 base::MessageLoop* ui_loop_;
398 // The extensions installation icon.
401 // The extension we are showing the UI for, if type is not
402 // BUNDLE_INSTALL_PROMPT.
403 const extensions::Extension* extension_;
405 // The bundle we are showing the UI for, if type BUNDLE_INSTALL_PROMPT.
406 const extensions::BundleInstaller* bundle_;
408 // The permissions being prompted for.
409 scoped_refptr<const extensions::PermissionSet> permissions_;
411 // The object responsible for doing the UI specific actions.
412 scoped_ptr<ExtensionInstallUI> install_ui_;
414 // Parameters to show the confirmation UI.
415 ShowParams show_params_;
417 // The delegate we will call Proceed/Abort on after confirmation UI.
420 // A pre-filled prompt.
421 scoped_refptr<Prompt> prompt_;
423 // Used to show the confirm dialog.
424 ShowDialogCallback show_dialog_callback_;
427 #endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_INSTALL_PROMPT_H_