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_UI_WEBUI_NTP_APP_LAUNCHER_HANDLER_H_
6 #define CHROME_BROWSER_UI_WEBUI_NTP_APP_LAUNCHER_HANDLER_H_
7 
8 #include <memory>
9 #include <set>
10 #include <string>
11 
12 #include "base/macros.h"
13 #include "base/optional.h"
14 #include "base/scoped_observer.h"
15 #include "base/task/cancelable_task_tracker.h"
16 #include "chrome/browser/extensions/extension_uninstall_dialog.h"
17 #include "chrome/browser/ui/extensions/extension_enable_flow_delegate.h"
18 #include "chrome/browser/web_applications/components/app_registrar.h"
19 #include "chrome/browser/web_applications/components/app_registrar_observer.h"
20 #include "chrome/browser/web_applications/components/os_integration_manager.h"
21 #include "chrome/browser/web_applications/components/web_app_id.h"
22 #include "chrome/common/extensions/extension_constants.h"
23 #include "components/favicon/core/favicon_service.h"
24 #include "components/prefs/pref_change_registrar.h"
25 #include "components/sync/model/string_ordinal.h"
26 #include "content/public/browser/notification_observer.h"
27 #include "content/public/browser/notification_registrar.h"
28 #include "content/public/browser/web_ui_message_handler.h"
29 #include "extensions/browser/extension_registry_observer.h"
30 #include "extensions/common/extension.h"
31 
32 class ExtensionEnableFlow;
33 class PrefChangeRegistrar;
34 class Profile;
35 
36 namespace extensions {
37 class ExtensionService;
38 }  // namespace extensions
39 
40 namespace favicon_base {
41 struct FaviconImageResult;
42 }
43 
44 namespace user_prefs {
45 class PrefRegistrySyncable;
46 }
47 
48 namespace web_app {
49 class WebAppProvider;
50 }  // namespace web_app
51 
52 // The handler for Javascript messages related to the "apps" view.
53 class AppLauncherHandler
54     : public content::WebUIMessageHandler,
55       public extensions::ExtensionUninstallDialog::Delegate,
56       public ExtensionEnableFlowDelegate,
57       public content::NotificationObserver,
58       public web_app::AppRegistrarObserver,
59       public extensions::ExtensionRegistryObserver {
60  public:
61   AppLauncherHandler(extensions::ExtensionService* extension_service,
62                      web_app::WebAppProvider* web_app_provider);
63   ~AppLauncherHandler() override;
64 
65   void CreateWebAppInfo(const web_app::AppId& app_id,
66                         base::DictionaryValue* value);
67 
68   void CreateExtensionInfo(const extensions::Extension* extension,
69                            base::DictionaryValue* value);
70 
71   // Registers values (strings etc.) for the page.
72   static void GetLocalizedValues(Profile* profile,
73                                  base::DictionaryValue* values);
74 
75   // Register per-profile preferences.
76   static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
77 
78   // WebUIMessageHandler:
79   void RegisterMessages() override;
80 
81   // content::NotificationObserver:
82   void Observe(int type,
83                const content::NotificationSource& source,
84                const content::NotificationDetails& details) override;
85 
86   // extensions::ExtensionRegistryObserver:
87   void OnExtensionLoaded(content::BrowserContext* browser_context,
88                          const extensions::Extension* extension) override;
89   void OnExtensionUnloaded(content::BrowserContext* browser_context,
90                            const extensions::Extension* extension,
91                            extensions::UnloadedExtensionReason reason) override;
92   void OnExtensionUninstalled(content::BrowserContext* browser_context,
93                               const extensions::Extension* extension,
94                               extensions::UninstallReason reason) override;
95 
96   // web_app::AppRegistrarObserver:
97   void OnWebAppInstalled(const web_app::AppId& app_id) override;
98   void OnWebAppUninstalled(const web_app::AppId& app_id) override;
99   void OnAppRegistrarDestroyed() override;
100 
101   // Populate the given dictionary with all installed app info.
102   void FillAppDictionary(base::DictionaryValue* value);
103 
104   // Create a dictionary value for the given extension.
105   std::unique_ptr<base::DictionaryValue> GetExtensionInfo(
106       const extensions::Extension* extension);
107 
108   // Create a dictionary value for the given web app.
109   std::unique_ptr<base::DictionaryValue> GetWebAppInfo(
110       const web_app::AppId& app_id);
111 
112   // Populate the given dictionary with the web store promo content.
113   void FillPromoDictionary(base::DictionaryValue* value);
114 
115   // Handles the "launchApp" message with unused |args|.
116   void HandleGetApps(const base::ListValue* args);
117 
118   // Handles the "launchApp" message with |args| containing [extension_id,
119   // source] with optional [url, disposition], |disposition| defaulting to
120   // CURRENT_TAB.
121   void HandleLaunchApp(const base::ListValue* args);
122 
123   // Handles the "setLaunchType" message with args containing [extension_id,
124   // launch_type].
125   void HandleSetLaunchType(const base::ListValue* args);
126 
127   // Handles the "uninstallApp" message with |args| containing [extension_id]
128   // and an optional bool to not confirm the uninstall when true, defaults to
129   // false.
130   void HandleUninstallApp(const base::ListValue* args);
131 
132   // Handles the "createAppShortcut" message with |args| containing
133   // [extension_id].
134   void HandleCreateAppShortcut(const base::ListValue* args);
135 
136   // Handles the "installAppLocally" message with |args| containing
137   // [extension_id].
138   void HandleInstallAppLocally(const base::ListValue* args);
139 
140   // Handles the "showAppInfo" message with |args| containing [extension_id].
141   void HandleShowAppInfo(const base::ListValue* args);
142 
143   // Handles the "reorderApps" message with |args| containing [dragged_app_id,
144   // app_order].
145   void HandleReorderApps(const base::ListValue* args);
146 
147   // Handles the "setPageIndex" message with |args| containing [extension_id,
148   // page_index].
149   void HandleSetPageIndex(const base::ListValue* args);
150 
151   // Handles "saveAppPageName" message with |args| containing [name,
152   // page_index].
153   void HandleSaveAppPageName(const base::ListValue* args);
154 
155   // Handles "generateAppForLink" message with |args| containing [url, title,
156   // page_index].
157   void HandleGenerateAppForLink(const base::ListValue* args);
158 
159   // Handles "pageSelected" message with |args| containing [page_index].
160   void HandlePageSelected(const base::ListValue* args);
161 
162   // Handles "runOnOsLogin" message with |args| containing [app_id, mode]
163   void HandleRunOnOsLogin(const base::ListValue* args);
164 
165  private:
166   struct AppInstallInfo {
167     AppInstallInfo();
168     ~AppInstallInfo();
169 
170     base::string16 title;
171     GURL app_url;
172     syncer::StringOrdinal page_ordinal;
173   };
174 
175   // Reset some instance flags we use to track the currently uninstalling app.
176   void CleanupAfterUninstall();
177 
178   // Prompts the user to re-enable the app for |extension_id|.
179   void PromptToEnableApp(const std::string& extension_id);
180 
181   // Records result to UMA after OS Hooks are installed.
182   void OnOsHooksInstalled(const web_app::AppId& app_id,
183                           const web_app::OsHooksResults os_hooks_results);
184 
185   // ExtensionUninstallDialog::Delegate:
186   void OnExtensionUninstallDialogClosed(bool did_start_uninstall,
187                                         const base::string16& error) override;
188 
189   // ExtensionEnableFlowDelegate:
190   void ExtensionEnableFlowFinished() override;
191   void ExtensionEnableFlowAborted(bool user_initiated) override;
192 
193   // Returns the ExtensionUninstallDialog object for this class, creating it if
194   // needed.
195   extensions::ExtensionUninstallDialog* CreateExtensionUninstallDialog();
196 
197   // Continuation for installing a bookmark app after favicon lookup.
198   void OnFaviconForAppInstallFromLink(
199       std::unique_ptr<AppInstallInfo> install_info,
200       const favicon_base::FaviconImageResult& image_result);
201 
202   // Sends |highlight_app_id_| to the js.
203   void SetAppToBeHighlighted();
204 
205   void OnExtensionPreferenceChanged();
206 
207   // Called when an extension is removed (unloaded or uninstalled). Updates the
208   // UI.
209   void ExtensionRemoved(const extensions::Extension* extension,
210                         bool is_uninstall);
211 
212   // True if the extension should be displayed.
213   bool ShouldShow(const extensions::Extension* extension) const;
214 
215   // Handle installing OS hooks for Web App installs from chrome://apps page.
216   void InstallOsHooks(const web_app::AppId& app_id);
217 
218   // The apps are represented in the extensions model, which
219   // outlives us since it's owned by our containing profile.
220   extensions::ExtensionService* const extension_service_;
221 
222   // The apps are represented in the web apps model, which outlives us since
223   // it's owned by our containing profile. Populated iff
224   // features::kDesktopPWAsWithoutExtensions is enabled.
225   web_app::WebAppProvider* const web_app_provider_;
226 
227   ScopedObserver<web_app::AppRegistrar, web_app::AppRegistrarObserver>
228       web_apps_observer_{this};
229 
230   // We monitor changes to the extension system so that we can reload the apps
231   // when necessary.
232   content::NotificationRegistrar registrar_;
233 
234   // Monitor extension preference changes so that the Web UI can be notified.
235   PrefChangeRegistrar extension_pref_change_registrar_;
236 
237   // Monitor the local state pref to control the app launcher promo.
238   PrefChangeRegistrar local_state_pref_change_registrar_;
239 
240   // Used to show confirmation UI for uninstalling extensions in incognito mode.
241   std::unique_ptr<extensions::ExtensionUninstallDialog>
242       extension_uninstall_dialog_;
243 
244   // Used to show confirmation UI for enabling extensions.
245   std::unique_ptr<ExtensionEnableFlow> extension_enable_flow_;
246 
247   // The ids of apps to show on the NTP.
248   std::set<std::string> visible_apps_;
249 
250   // The id of the extension we are prompting the user about (either enable or
251   // uninstall).
252   std::string extension_id_prompting_;
253 
254   // When true, we ignore changes to the underlying data rather than immediately
255   // refreshing. This is useful when making many batch updates to avoid flicker.
256   bool ignore_changes_;
257 
258   // When populated, we have attempted to install a bookmark app, and are still
259   // waiting to hear about success or failure from the extensions system.
260   base::Optional<syncer::StringOrdinal>
261       attempting_web_app_install_page_ordinal_;
262 
263   // True if we have executed HandleGetApps() at least once.
264   bool has_loaded_apps_;
265 
266   // The ID of the app to be highlighted on the NTP (i.e. shown on the page
267   // and pulsed). This is done for new installs. The actual higlighting occurs
268   // when the app is added to the page (via getAppsCallback or appAdded).
269   std::string highlight_app_id_;
270 
271   // Used for favicon loading tasks.
272   base::CancelableTaskTracker cancelable_task_tracker_;
273 
274   // Used for passing callbacks.
275   base::WeakPtrFactory<AppLauncherHandler> weak_ptr_factory_{this};
276 
277   DISALLOW_COPY_AND_ASSIGN(AppLauncherHandler);
278 };
279 
280 #endif  // CHROME_BROWSER_UI_WEBUI_NTP_APP_LAUNCHER_HANDLER_H_
281