• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
type()100     PromptType type() const { return type_; }
set_type(PromptType 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.
bundle()137     const extensions::BundleInstaller* bundle() const { return bundle_; }
set_bundle(const extensions::BundleInstaller * bundle)138     void set_bundle(const extensions::BundleInstaller* bundle) {
139       bundle_ = bundle;
140     }
141 
142     // Populated for all other types.
extension()143     const extensions::Extension* extension() const { return extension_; }
set_extension(const extensions::Extension * extension)144     void set_extension(const extensions::Extension* extension) {
145       extension_ = extension;
146     }
147 
148     // May be populated for POST_INSTALL_PERMISSIONS_PROMPT.
set_retained_files(const std::vector<base::FilePath> & retained_files)149     void set_retained_files(const std::vector<base::FilePath>& retained_files) {
150       retained_files_ = retained_files;
151     }
152 
icon()153     const gfx::Image& icon() const { return icon_; }
set_icon(const gfx::Image & icon)154     void set_icon(const gfx::Image& icon) { icon_ = icon; }
155 
has_webstore_data()156     bool has_webstore_data() const { return has_webstore_data_; }
157 
experiment()158     const ExtensionInstallPromptExperiment* experiment() const {
159       return experiment_;
160     }
set_experiment(ExtensionInstallPromptExperiment * experiment)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:
~Delegate()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 
install_ui()272   ExtensionInstallUI* install_ui() const { return install_ui_.get(); }
273 
parent_web_contents()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 
set_callback_for_test(const ShowDialogCallback & show_dialog_callback)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