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