1 // Copyright 2018 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 #include "chrome/browser/web_applications/web_app_registrar.h"
6 
7 #include <utility>
8 #include <vector>
9 
10 #include "base/bind.h"
11 #include "base/check_op.h"
12 #include "base/strings/string_util.h"
13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/profiles/profile_manager.h"
15 #include "chrome/browser/web_applications/components/os_integration_manager.h"
16 #include "chrome/browser/web_applications/web_app.h"
17 
18 namespace web_app {
19 
WebAppRegistrar(Profile * profile)20 WebAppRegistrar::WebAppRegistrar(Profile* profile) : AppRegistrar(profile) {}
21 
22 WebAppRegistrar::~WebAppRegistrar() = default;
23 
GetAppById(const AppId & app_id) const24 const WebApp* WebAppRegistrar::GetAppById(const AppId& app_id) const {
25   if (registry_profile_being_deleted_)
26     return nullptr;
27 
28   auto it = registry_.find(app_id);
29   return it == registry_.end() ? nullptr : it->second.get();
30 }
31 
Start()32 void WebAppRegistrar::Start() {
33   // Profile manager can be null in unit tests.
34   if (g_browser_process->profile_manager())
35     g_browser_process->profile_manager()->AddObserver(this);
36 }
37 
Shutdown()38 void WebAppRegistrar::Shutdown() {
39   if (g_browser_process->profile_manager())
40     g_browser_process->profile_manager()->RemoveObserver(this);
41 }
42 
IsInstalled(const AppId & app_id) const43 bool WebAppRegistrar::IsInstalled(const AppId& app_id) const {
44   const WebApp* web_app = GetAppById(app_id);
45   return web_app && !web_app->is_in_sync_install();
46 }
47 
IsLocallyInstalled(const AppId & app_id) const48 bool WebAppRegistrar::IsLocallyInstalled(const AppId& app_id) const {
49   auto* web_app = GetAppById(app_id);
50   return web_app ? web_app->is_locally_installed() : false;
51 }
52 
WasInstalledByUser(const AppId & app_id) const53 bool WebAppRegistrar::WasInstalledByUser(const AppId& app_id) const {
54   const WebApp* web_app = GetAppById(app_id);
55   return web_app && web_app->WasInstalledByUser();
56 }
57 
CountUserInstalledApps() const58 int WebAppRegistrar::CountUserInstalledApps() const {
59   int num_user_installed = 0;
60   for (const WebApp& app : GetAppsIncludingStubs()) {
61     if (app.is_locally_installed() && app.WasInstalledByUser())
62       ++num_user_installed;
63   }
64   return num_user_installed;
65 }
66 
GetAppShortName(const AppId & app_id) const67 std::string WebAppRegistrar::GetAppShortName(const AppId& app_id) const {
68   auto* web_app = GetAppById(app_id);
69   return web_app ? web_app->name() : std::string();
70 }
71 
GetAppDescription(const AppId & app_id) const72 std::string WebAppRegistrar::GetAppDescription(const AppId& app_id) const {
73   auto* web_app = GetAppById(app_id);
74   return web_app ? web_app->description() : std::string();
75 }
76 
GetAppThemeColor(const AppId & app_id) const77 base::Optional<SkColor> WebAppRegistrar::GetAppThemeColor(
78     const AppId& app_id) const {
79   auto* web_app = GetAppById(app_id);
80   return web_app ? web_app->theme_color() : base::nullopt;
81 }
82 
GetAppBackgroundColor(const AppId & app_id) const83 base::Optional<SkColor> WebAppRegistrar::GetAppBackgroundColor(
84     const AppId& app_id) const {
85   auto* web_app = GetAppById(app_id);
86   return web_app ? web_app->background_color() : base::nullopt;
87 }
88 
GetAppStartUrl(const AppId & app_id) const89 const GURL& WebAppRegistrar::GetAppStartUrl(const AppId& app_id) const {
90   auto* web_app = GetAppById(app_id);
91   return web_app ? web_app->start_url() : GURL::EmptyGURL();
92 }
93 
GetAppLaunchQueryParams(const AppId & app_id) const94 const std::string* WebAppRegistrar::GetAppLaunchQueryParams(
95     const AppId& app_id) const {
96   auto* web_app = GetAppById(app_id);
97   return web_app ? web_app->launch_query_params() : nullptr;
98 }
99 
GetAppShareTarget(const AppId & app_id) const100 const apps::ShareTarget* WebAppRegistrar::GetAppShareTarget(
101     const AppId& app_id) const {
102   auto* web_app = GetAppById(app_id);
103   return (web_app && web_app->share_target().has_value())
104              ? &web_app->share_target().value()
105              : nullptr;
106 }
107 
GetAppScopeInternal(const AppId & app_id) const108 base::Optional<GURL> WebAppRegistrar::GetAppScopeInternal(
109     const AppId& app_id) const {
110   auto* web_app = GetAppById(app_id);
111   if (!web_app)
112     return base::nullopt;
113 
114   // TODO(crbug.com/910016): Treat shortcuts as PWAs.
115   // Shortcuts on the WebApp system have empty scopes, while the implementation
116   // of IsShortcutApp just checks if the scope is |base::nullopt|, so make sure
117   // we return |base::nullopt| rather than an empty scope.
118   if (web_app->scope().is_empty())
119     return base::nullopt;
120 
121   return web_app->scope();
122 }
123 
GetAppDisplayMode(const AppId & app_id) const124 DisplayMode WebAppRegistrar::GetAppDisplayMode(const AppId& app_id) const {
125   auto* web_app = GetAppById(app_id);
126   return web_app ? web_app->display_mode() : DisplayMode::kUndefined;
127 }
128 
GetAppUserDisplayMode(const AppId & app_id) const129 DisplayMode WebAppRegistrar::GetAppUserDisplayMode(const AppId& app_id) const {
130   auto* web_app = GetAppById(app_id);
131   return web_app ? web_app->user_display_mode() : DisplayMode::kUndefined;
132 }
133 
GetAppDisplayModeOverride(const AppId & app_id) const134 std::vector<DisplayMode> WebAppRegistrar::GetAppDisplayModeOverride(
135     const AppId& app_id) const {
136   auto* web_app = GetAppById(app_id);
137   return web_app ? web_app->display_mode_override()
138                  : std::vector<DisplayMode>();
139 }
140 
GetAppLastLaunchTime(const AppId & app_id) const141 base::Time WebAppRegistrar::GetAppLastLaunchTime(const AppId& app_id) const {
142   auto* web_app = GetAppById(app_id);
143   return web_app ? web_app->last_launch_time() : base::Time();
144 }
145 
GetAppInstallTime(const AppId & app_id) const146 base::Time WebAppRegistrar::GetAppInstallTime(const AppId& app_id) const {
147   auto* web_app = GetAppById(app_id);
148   return web_app ? web_app->install_time() : base::Time();
149 }
150 
GetAppIconInfos(const AppId & app_id) const151 std::vector<WebApplicationIconInfo> WebAppRegistrar::GetAppIconInfos(
152     const AppId& app_id) const {
153   auto* web_app = GetAppById(app_id);
154   return web_app ? web_app->icon_infos()
155                  : std::vector<WebApplicationIconInfo>();
156 }
157 
GetAppDownloadedIconSizesAny(const AppId & app_id) const158 SortedSizesPx WebAppRegistrar::GetAppDownloadedIconSizesAny(
159     const AppId& app_id) const {
160   auto* web_app = GetAppById(app_id);
161   return web_app ? web_app->downloaded_icon_sizes(IconPurpose::ANY)
162                  : SortedSizesPx();
163 }
164 
165 std::vector<WebApplicationShortcutsMenuItemInfo>
GetAppShortcutsMenuItemInfos(const AppId & app_id) const166 WebAppRegistrar::GetAppShortcutsMenuItemInfos(const AppId& app_id) const {
167   auto* web_app = GetAppById(app_id);
168   return web_app ? web_app->shortcuts_menu_item_infos()
169                  : std::vector<WebApplicationShortcutsMenuItemInfo>();
170 }
171 
172 std::vector<std::vector<SquareSizePx>>
GetAppDownloadedShortcutsMenuIconsSizes(const AppId & app_id) const173 WebAppRegistrar::GetAppDownloadedShortcutsMenuIconsSizes(
174     const AppId& app_id) const {
175   auto* web_app = GetAppById(app_id);
176   return web_app ? web_app->downloaded_shortcuts_menu_icons_sizes()
177                  : std::vector<std::vector<SquareSizePx>>();
178 }
179 
GetAppIds() const180 std::vector<AppId> WebAppRegistrar::GetAppIds() const {
181   std::vector<AppId> app_ids;
182 
183   for (const WebApp& app : GetApps())
184     app_ids.push_back(app.app_id());
185 
186   return app_ids;
187 }
188 
GetAppRunOnOsLoginMode(const AppId & app_id) const189 RunOnOsLoginMode WebAppRegistrar::GetAppRunOnOsLoginMode(
190     const AppId& app_id) const {
191   auto* web_app = GetAppById(app_id);
192   return web_app ? web_app->run_on_os_login_mode()
193                  : RunOnOsLoginMode::kUndefined;
194 }
195 
AsWebAppRegistrar()196 WebAppRegistrar* WebAppRegistrar::AsWebAppRegistrar() {
197   return this;
198 }
199 
OnProfileMarkedForPermanentDeletion(Profile * profile_to_be_deleted)200 void WebAppRegistrar::OnProfileMarkedForPermanentDeletion(
201     Profile* profile_to_be_deleted) {
202   if (profile() != profile_to_be_deleted)
203     return;
204 
205   for (const auto& app : GetAppsIncludingStubs()) {
206     NotifyWebAppProfileWillBeDeleted(app.app_id());
207     os_integration_manager().UninstallAllOsHooks(app.app_id(),
208                                                   base::DoNothing());
209   }
210   // We can't do registry_.clear() here because it makes in-memory registry
211   // diverged from the sync server registry and from the on-disk registry
212   // (WebAppDatabase/LevelDB and "Web Applications" profile directory).
213   registry_profile_being_deleted_ = true;
214 }
215 
AppSet(const WebAppRegistrar * registrar,Filter filter)216 WebAppRegistrar::AppSet::AppSet(const WebAppRegistrar* registrar, Filter filter)
217     : registrar_(registrar),
218       filter_(filter)
219 #if DCHECK_IS_ON()
220       ,
221       mutations_count_(registrar->mutations_count_)
222 #endif
223 {
224 }
225 
~AppSet()226 WebAppRegistrar::AppSet::~AppSet() {
227 #if DCHECK_IS_ON()
228   DCHECK_EQ(mutations_count_, registrar_->mutations_count_);
229 #endif
230 }
231 
begin()232 WebAppRegistrar::AppSet::iterator WebAppRegistrar::AppSet::begin() {
233   return iterator(registrar_->registry_.begin(), registrar_->registry_.end(),
234                   filter_);
235 }
236 
end()237 WebAppRegistrar::AppSet::iterator WebAppRegistrar::AppSet::end() {
238   return iterator(registrar_->registry_.end(), registrar_->registry_.end(),
239                   filter_);
240 }
241 
begin() const242 WebAppRegistrar::AppSet::const_iterator WebAppRegistrar::AppSet::begin() const {
243   return const_iterator(registrar_->registry_.begin(),
244                         registrar_->registry_.end(), filter_);
245 }
246 
end() const247 WebAppRegistrar::AppSet::const_iterator WebAppRegistrar::AppSet::end() const {
248   return const_iterator(registrar_->registry_.end(),
249                         registrar_->registry_.end(), filter_);
250 }
251 
GetAppsIncludingStubs() const252 const WebAppRegistrar::AppSet WebAppRegistrar::GetAppsIncludingStubs() const {
253   return AppSet(this, nullptr);
254 }
255 
GetApps() const256 const WebAppRegistrar::AppSet WebAppRegistrar::GetApps() const {
257   return AppSet(this, [](const WebApp& web_app) {
258     return !web_app.is_in_sync_install();
259   });
260 }
261 
SetRegistry(Registry && registry)262 void WebAppRegistrar::SetRegistry(Registry&& registry) {
263   registry_ = std::move(registry);
264 }
265 
FilterApps(Filter filter) const266 const WebAppRegistrar::AppSet WebAppRegistrar::FilterApps(Filter filter) const {
267   return AppSet(this, filter);
268 }
269 
CountMutation()270 void WebAppRegistrar::CountMutation() {
271 #if DCHECK_IS_ON()
272   ++mutations_count_;
273 #endif
274 }
275 
WebAppRegistrarMutable(Profile * profile)276 WebAppRegistrarMutable::WebAppRegistrarMutable(Profile* profile)
277     : WebAppRegistrar(profile) {}
278 
279 WebAppRegistrarMutable::~WebAppRegistrarMutable() = default;
280 
InitRegistry(Registry && registry)281 void WebAppRegistrarMutable::InitRegistry(Registry&& registry) {
282   DCHECK(is_empty());
283   SetRegistry(std::move(registry));
284 }
285 
GetAppByIdMutable(const AppId & app_id)286 WebApp* WebAppRegistrarMutable::GetAppByIdMutable(const AppId& app_id) {
287   return const_cast<WebApp*>(GetAppById(app_id));
288 }
289 
FilterAppsMutable(Filter filter)290 WebAppRegistrar::AppSet WebAppRegistrarMutable::FilterAppsMutable(
291     Filter filter) {
292   return AppSet(this, filter);
293 }
294 
GetAppsIncludingStubsMutable()295 WebAppRegistrar::AppSet WebAppRegistrarMutable::GetAppsIncludingStubsMutable() {
296   return AppSet(this, nullptr);
297 }
298 
GetAppsMutable()299 WebAppRegistrar::AppSet WebAppRegistrarMutable::GetAppsMutable() {
300   return AppSet(this, [](const WebApp& web_app) {
301     return !web_app.is_in_sync_install();
302   });
303 }
304 
IsRegistryEqual(const Registry & registry,const Registry & registry2)305 bool IsRegistryEqual(const Registry& registry, const Registry& registry2) {
306   if (registry.size() != registry2.size())
307     return false;
308 
309   for (auto& kv : registry) {
310     const WebApp* web_app = kv.second.get();
311     const WebApp* web_app2 = registry2.at(web_app->app_id()).get();
312     if (*web_app != *web_app2)
313       return false;
314   }
315 
316   return true;
317 }
318 
319 }  // namespace web_app
320