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 "components/services/app_service/public/cpp/app_update.h"
6 
7 #include "base/logging.h"
8 #include "base/strings/string_util.h"
9 #include "base/time/time.h"
10 
11 namespace {
12 
ClonePermissions(const std::vector<apps::mojom::PermissionPtr> & clone_from,std::vector<apps::mojom::PermissionPtr> * clone_to)13 void ClonePermissions(const std::vector<apps::mojom::PermissionPtr>& clone_from,
14                       std::vector<apps::mojom::PermissionPtr>* clone_to) {
15   for (const auto& permission : clone_from) {
16     clone_to->push_back(permission->Clone());
17   }
18 }
19 
CloneStrings(const std::vector<std::string> & clone_from,std::vector<std::string> * clone_to)20 void CloneStrings(const std::vector<std::string>& clone_from,
21                   std::vector<std::string>* clone_to) {
22   for (const auto& s : clone_from) {
23     clone_to->push_back(s);
24   }
25 }
26 
CloneIntentFilters(const std::vector<apps::mojom::IntentFilterPtr> & clone_from,std::vector<apps::mojom::IntentFilterPtr> * clone_to)27 void CloneIntentFilters(
28     const std::vector<apps::mojom::IntentFilterPtr>& clone_from,
29     std::vector<apps::mojom::IntentFilterPtr>* clone_to) {
30   for (const auto& intent_filter : clone_from) {
31     clone_to->push_back(intent_filter->Clone());
32   }
33 }
34 
35 }  // namespace
36 
37 namespace apps {
38 
39 // static
Merge(apps::mojom::App * state,const apps::mojom::App * delta)40 void AppUpdate::Merge(apps::mojom::App* state, const apps::mojom::App* delta) {
41   DCHECK(state);
42   if (!delta) {
43     return;
44   }
45 
46   if ((delta->app_type != state->app_type) ||
47       (delta->app_id != state->app_id)) {
48     LOG(ERROR) << "inconsistent (app_type, app_id): (" << delta->app_type
49                << ", " << delta->app_id << ") vs (" << state->app_type << ", "
50                << state->app_id << ") ";
51     DCHECK(false);
52     return;
53   }
54 
55   if (delta->readiness != apps::mojom::Readiness::kUnknown) {
56     state->readiness = delta->readiness;
57   }
58   if (delta->name.has_value()) {
59     state->name = delta->name;
60   }
61   if (delta->short_name.has_value()) {
62     state->short_name = delta->short_name;
63   }
64   if (delta->publisher_id.has_value()) {
65     state->publisher_id = delta->publisher_id;
66   }
67   if (delta->description.has_value()) {
68     state->description = delta->description;
69   }
70   if (delta->version.has_value()) {
71     state->version = delta->version;
72   }
73   if (!delta->additional_search_terms.empty()) {
74     state->additional_search_terms.clear();
75     CloneStrings(delta->additional_search_terms,
76                  &state->additional_search_terms);
77   }
78   if (!delta->icon_key.is_null()) {
79     state->icon_key = delta->icon_key.Clone();
80   }
81   if (delta->last_launch_time.has_value()) {
82     state->last_launch_time = delta->last_launch_time;
83   }
84   if (delta->install_time.has_value()) {
85     state->install_time = delta->install_time;
86   }
87   if (!delta->permissions.empty()) {
88     DCHECK(state->permissions.empty() ||
89            (delta->permissions.size() == state->permissions.size()));
90     state->permissions.clear();
91     ClonePermissions(delta->permissions, &state->permissions);
92   }
93   if (delta->install_source != apps::mojom::InstallSource::kUnknown) {
94     state->install_source = delta->install_source;
95   }
96   if (delta->is_platform_app != apps::mojom::OptionalBool::kUnknown) {
97     state->is_platform_app = delta->is_platform_app;
98   }
99   if (delta->recommendable != apps::mojom::OptionalBool::kUnknown) {
100     state->recommendable = delta->recommendable;
101   }
102   if (delta->searchable != apps::mojom::OptionalBool::kUnknown) {
103     state->searchable = delta->searchable;
104   }
105   if (delta->show_in_launcher != apps::mojom::OptionalBool::kUnknown) {
106     state->show_in_launcher = delta->show_in_launcher;
107   }
108   if (delta->show_in_shelf != apps::mojom::OptionalBool::kUnknown) {
109     state->show_in_shelf = delta->show_in_shelf;
110   }
111   if (delta->show_in_search != apps::mojom::OptionalBool::kUnknown) {
112     state->show_in_search = delta->show_in_search;
113   }
114   if (delta->show_in_management != apps::mojom::OptionalBool::kUnknown) {
115     state->show_in_management = delta->show_in_management;
116   }
117   if (delta->has_badge != apps::mojom::OptionalBool::kUnknown) {
118     state->has_badge = delta->has_badge;
119   }
120   if (delta->paused != apps::mojom::OptionalBool::kUnknown) {
121     state->paused = delta->paused;
122   }
123 
124   if (!delta->intent_filters.empty()) {
125     state->intent_filters.clear();
126     CloneIntentFilters(delta->intent_filters, &state->intent_filters);
127   }
128 
129   // When adding new fields to the App Mojo type, this function should also be
130   // updated.
131 }
132 
AppUpdate(const apps::mojom::App * state,const apps::mojom::App * delta,const::AccountId & account_id)133 AppUpdate::AppUpdate(const apps::mojom::App* state,
134                      const apps::mojom::App* delta,
135                      const ::AccountId& account_id)
136     : state_(state), delta_(delta), account_id_(account_id) {
137   DCHECK(state_ || delta_);
138   if (state_ && delta_) {
139     DCHECK(state_->app_type == delta->app_type);
140     DCHECK(state_->app_id == delta->app_id);
141   }
142 }
143 
StateIsNull() const144 bool AppUpdate::StateIsNull() const {
145   return state_ == nullptr;
146 }
147 
AppType() const148 apps::mojom::AppType AppUpdate::AppType() const {
149   return delta_ ? delta_->app_type : state_->app_type;
150 }
151 
AppId() const152 const std::string& AppUpdate::AppId() const {
153   return delta_ ? delta_->app_id : state_->app_id;
154 }
155 
Readiness() const156 apps::mojom::Readiness AppUpdate::Readiness() const {
157   if (delta_ && (delta_->readiness != apps::mojom::Readiness::kUnknown)) {
158     return delta_->readiness;
159   }
160   if (state_) {
161     return state_->readiness;
162   }
163   return apps::mojom::Readiness::kUnknown;
164 }
165 
ReadinessChanged() const166 bool AppUpdate::ReadinessChanged() const {
167   return delta_ && (delta_->readiness != apps::mojom::Readiness::kUnknown) &&
168          (!state_ || (delta_->readiness != state_->readiness));
169 }
170 
Name() const171 const std::string& AppUpdate::Name() const {
172   if (delta_ && delta_->name.has_value()) {
173     return delta_->name.value();
174   }
175   if (state_ && state_->name.has_value()) {
176     return state_->name.value();
177   }
178   return base::EmptyString();
179 }
180 
NameChanged() const181 bool AppUpdate::NameChanged() const {
182   return delta_ && delta_->name.has_value() &&
183          (!state_ || (delta_->name != state_->name));
184 }
185 
ShortName() const186 const std::string& AppUpdate::ShortName() const {
187   if (delta_ && delta_->short_name.has_value()) {
188     return delta_->short_name.value();
189   }
190   if (state_ && state_->short_name.has_value()) {
191     return state_->short_name.value();
192   }
193   return base::EmptyString();
194 }
195 
ShortNameChanged() const196 bool AppUpdate::ShortNameChanged() const {
197   return delta_ && delta_->short_name.has_value() &&
198          (!state_ || (delta_->short_name != state_->short_name));
199 }
200 
PublisherId() const201 const std::string& AppUpdate::PublisherId() const {
202   if (delta_ && delta_->publisher_id.has_value()) {
203     return delta_->publisher_id.value();
204   }
205   if (state_ && state_->publisher_id.has_value()) {
206     return state_->publisher_id.value();
207   }
208   return base::EmptyString();
209 }
210 
PublisherIdChanged() const211 bool AppUpdate::PublisherIdChanged() const {
212   return delta_ && delta_->publisher_id.has_value() &&
213          (!state_ || (delta_->publisher_id != state_->publisher_id));
214 }
215 
Description() const216 const std::string& AppUpdate::Description() const {
217   if (delta_ && delta_->description.has_value()) {
218     return delta_->description.value();
219   }
220   if (state_ && state_->description.has_value()) {
221     return state_->description.value();
222   }
223   return base::EmptyString();
224 }
225 
DescriptionChanged() const226 bool AppUpdate::DescriptionChanged() const {
227   return delta_ && delta_->description.has_value() &&
228          (!state_ || (delta_->description != state_->description));
229 }
230 
Version() const231 const std::string& AppUpdate::Version() const {
232   if (delta_ && delta_->version.has_value()) {
233     return delta_->version.value();
234   }
235   if (state_ && state_->version.has_value()) {
236     return state_->version.value();
237   }
238   return base::EmptyString();
239 }
240 
VersionChanged() const241 bool AppUpdate::VersionChanged() const {
242   return delta_ && delta_->version.has_value() &&
243          (!state_ || (delta_->version != state_->version));
244 }
245 
AdditionalSearchTerms() const246 std::vector<std::string> AppUpdate::AdditionalSearchTerms() const {
247   std::vector<std::string> additional_search_terms;
248 
249   if (delta_ && !delta_->additional_search_terms.empty()) {
250     CloneStrings(delta_->additional_search_terms, &additional_search_terms);
251   } else if (state_ && !state_->additional_search_terms.empty()) {
252     CloneStrings(state_->additional_search_terms, &additional_search_terms);
253   }
254 
255   return additional_search_terms;
256 }
257 
AdditionalSearchTermsChanged() const258 bool AppUpdate::AdditionalSearchTermsChanged() const {
259   return delta_ && !delta_->additional_search_terms.empty() &&
260          (!state_ ||
261           (delta_->additional_search_terms != state_->additional_search_terms));
262 }
263 
IconKey() const264 apps::mojom::IconKeyPtr AppUpdate::IconKey() const {
265   if (delta_ && !delta_->icon_key.is_null()) {
266     return delta_->icon_key.Clone();
267   }
268   if (state_ && !state_->icon_key.is_null()) {
269     return state_->icon_key.Clone();
270   }
271   return apps::mojom::IconKeyPtr();
272 }
273 
IconKeyChanged() const274 bool AppUpdate::IconKeyChanged() const {
275   return delta_ && !delta_->icon_key.is_null() &&
276          (!state_ || !delta_->icon_key.Equals(state_->icon_key));
277 }
278 
LastLaunchTime() const279 base::Time AppUpdate::LastLaunchTime() const {
280   if (delta_ && delta_->last_launch_time.has_value()) {
281     return delta_->last_launch_time.value();
282   }
283   if (state_ && state_->last_launch_time.has_value()) {
284     return state_->last_launch_time.value();
285   }
286   return base::Time();
287 }
288 
LastLaunchTimeChanged() const289 bool AppUpdate::LastLaunchTimeChanged() const {
290   return delta_ && delta_->last_launch_time.has_value() &&
291          (!state_ || (delta_->last_launch_time != state_->last_launch_time));
292 }
293 
InstallTime() const294 base::Time AppUpdate::InstallTime() const {
295   if (delta_ && delta_->install_time.has_value()) {
296     return delta_->install_time.value();
297   }
298   if (state_ && state_->install_time.has_value()) {
299     return state_->install_time.value();
300   }
301   return base::Time();
302 }
303 
InstallTimeChanged() const304 bool AppUpdate::InstallTimeChanged() const {
305   return delta_ && delta_->install_time.has_value() &&
306          (!state_ || (delta_->install_time != state_->install_time));
307 }
308 
Permissions() const309 std::vector<apps::mojom::PermissionPtr> AppUpdate::Permissions() const {
310   std::vector<apps::mojom::PermissionPtr> permissions;
311 
312   if (delta_ && !delta_->permissions.empty()) {
313     ClonePermissions(delta_->permissions, &permissions);
314   } else if (state_ && !state_->permissions.empty()) {
315     ClonePermissions(state_->permissions, &permissions);
316   }
317 
318   return permissions;
319 }
320 
PermissionsChanged() const321 bool AppUpdate::PermissionsChanged() const {
322   return delta_ && !delta_->permissions.empty() &&
323          (!state_ || (delta_->permissions != state_->permissions));
324 }
325 
InstallSource() const326 apps::mojom::InstallSource AppUpdate::InstallSource() const {
327   if (delta_ &&
328       (delta_->install_source != apps::mojom::InstallSource::kUnknown)) {
329     return delta_->install_source;
330   }
331   if (state_) {
332     return state_->install_source;
333   }
334   return apps::mojom::InstallSource::kUnknown;
335 }
336 
InstallSourceChanged() const337 bool AppUpdate::InstallSourceChanged() const {
338   return delta_ &&
339          (delta_->install_source != apps::mojom::InstallSource::kUnknown) &&
340          (!state_ || (delta_->install_source != state_->install_source));
341 }
342 
InstalledInternally() const343 apps::mojom::OptionalBool AppUpdate::InstalledInternally() const {
344   switch (InstallSource()) {
345     case apps::mojom::InstallSource::kUnknown:
346       return apps::mojom::OptionalBool::kUnknown;
347     case apps::mojom::InstallSource::kSystem:
348     case apps::mojom::InstallSource::kPolicy:
349     case apps::mojom::InstallSource::kOem:
350     case apps::mojom::InstallSource::kDefault:
351       return apps::mojom::OptionalBool::kTrue;
352     default:
353       return apps::mojom::OptionalBool::kFalse;
354   }
355 }
356 
IsPlatformApp() const357 apps::mojom::OptionalBool AppUpdate::IsPlatformApp() const {
358   if (delta_ &&
359       (delta_->is_platform_app != apps::mojom::OptionalBool::kUnknown)) {
360     return delta_->is_platform_app;
361   }
362   if (state_) {
363     return state_->is_platform_app;
364   }
365   return apps::mojom::OptionalBool::kUnknown;
366 }
367 
IsPlatformAppChanged() const368 bool AppUpdate::IsPlatformAppChanged() const {
369   return delta_ &&
370          (delta_->is_platform_app != apps::mojom::OptionalBool::kUnknown) &&
371          (!state_ || (delta_->is_platform_app != state_->is_platform_app));
372 }
373 
Recommendable() const374 apps::mojom::OptionalBool AppUpdate::Recommendable() const {
375   if (delta_ &&
376       (delta_->recommendable != apps::mojom::OptionalBool::kUnknown)) {
377     return delta_->recommendable;
378   }
379   if (state_) {
380     return state_->recommendable;
381   }
382   return apps::mojom::OptionalBool::kUnknown;
383 }
384 
RecommendableChanged() const385 bool AppUpdate::RecommendableChanged() const {
386   return delta_ &&
387          (delta_->recommendable != apps::mojom::OptionalBool::kUnknown) &&
388          (!state_ || (delta_->recommendable != state_->recommendable));
389 }
390 
Searchable() const391 apps::mojom::OptionalBool AppUpdate::Searchable() const {
392   if (delta_ && (delta_->searchable != apps::mojom::OptionalBool::kUnknown)) {
393     return delta_->searchable;
394   }
395   if (state_) {
396     return state_->searchable;
397   }
398   return apps::mojom::OptionalBool::kUnknown;
399 }
400 
SearchableChanged() const401 bool AppUpdate::SearchableChanged() const {
402   return delta_ &&
403          (delta_->searchable != apps::mojom::OptionalBool::kUnknown) &&
404          (!state_ || (delta_->searchable != state_->searchable));
405 }
406 
ShowInLauncher() const407 apps::mojom::OptionalBool AppUpdate::ShowInLauncher() const {
408   if (delta_ &&
409       (delta_->show_in_launcher != apps::mojom::OptionalBool::kUnknown)) {
410     return delta_->show_in_launcher;
411   }
412   if (state_) {
413     return state_->show_in_launcher;
414   }
415   return apps::mojom::OptionalBool::kUnknown;
416 }
417 
ShowInLauncherChanged() const418 bool AppUpdate::ShowInLauncherChanged() const {
419   return delta_ &&
420          (delta_->show_in_launcher != apps::mojom::OptionalBool::kUnknown) &&
421          (!state_ || (delta_->show_in_launcher != state_->show_in_launcher));
422 }
423 
ShowInShelf() const424 apps::mojom::OptionalBool AppUpdate::ShowInShelf() const {
425   if (delta_ &&
426       (delta_->show_in_shelf != apps::mojom::OptionalBool::kUnknown)) {
427     return delta_->show_in_shelf;
428   }
429   if (state_) {
430     return state_->show_in_shelf;
431   }
432   return apps::mojom::OptionalBool::kUnknown;
433 }
434 
ShowInShelfChanged() const435 bool AppUpdate::ShowInShelfChanged() const {
436   return delta_ &&
437          (delta_->show_in_shelf != apps::mojom::OptionalBool::kUnknown) &&
438          (!state_ || (delta_->show_in_shelf != state_->show_in_shelf));
439 }
440 
ShowInSearch() const441 apps::mojom::OptionalBool AppUpdate::ShowInSearch() const {
442   if (delta_ &&
443       (delta_->show_in_search != apps::mojom::OptionalBool::kUnknown)) {
444     return delta_->show_in_search;
445   }
446   if (state_) {
447     return state_->show_in_search;
448   }
449   return apps::mojom::OptionalBool::kUnknown;
450 }
451 
ShowInSearchChanged() const452 bool AppUpdate::ShowInSearchChanged() const {
453   return delta_ &&
454          (delta_->show_in_search != apps::mojom::OptionalBool::kUnknown) &&
455          (!state_ || (delta_->show_in_search != state_->show_in_search));
456 }
457 
ShowInManagement() const458 apps::mojom::OptionalBool AppUpdate::ShowInManagement() const {
459   if (delta_ &&
460       (delta_->show_in_management != apps::mojom::OptionalBool::kUnknown)) {
461     return delta_->show_in_management;
462   }
463   if (state_) {
464     return state_->show_in_management;
465   }
466   return apps::mojom::OptionalBool::kUnknown;
467 }
468 
ShowInManagementChanged() const469 bool AppUpdate::ShowInManagementChanged() const {
470   return delta_ &&
471          (delta_->show_in_management != apps::mojom::OptionalBool::kUnknown) &&
472          (!state_ ||
473           (delta_->show_in_management != state_->show_in_management));
474 }
475 
HasBadge() const476 apps::mojom::OptionalBool AppUpdate::HasBadge() const {
477   if (delta_ && (delta_->has_badge != apps::mojom::OptionalBool::kUnknown)) {
478     return delta_->has_badge;
479   }
480   if (state_) {
481     return state_->has_badge;
482   }
483   return apps::mojom::OptionalBool::kUnknown;
484 }
485 
HasBadgeChanged() const486 bool AppUpdate::HasBadgeChanged() const {
487   return delta_ && (delta_->has_badge != apps::mojom::OptionalBool::kUnknown) &&
488          (!state_ || (delta_->has_badge != state_->has_badge));
489 }
490 
Paused() const491 apps::mojom::OptionalBool AppUpdate::Paused() const {
492   if (delta_ && (delta_->paused != apps::mojom::OptionalBool::kUnknown)) {
493     return delta_->paused;
494   }
495   if (state_) {
496     return state_->paused;
497   }
498   return apps::mojom::OptionalBool::kUnknown;
499 }
500 
PausedChanged() const501 bool AppUpdate::PausedChanged() const {
502   return delta_ && (delta_->paused != apps::mojom::OptionalBool::kUnknown) &&
503          (!state_ || (delta_->paused != state_->paused));
504 }
505 
IntentFilters() const506 std::vector<apps::mojom::IntentFilterPtr> AppUpdate::IntentFilters() const {
507   std::vector<apps::mojom::IntentFilterPtr> intent_filters;
508 
509   if (delta_ && !delta_->intent_filters.empty()) {
510     CloneIntentFilters(delta_->intent_filters, &intent_filters);
511   } else if (state_ && !state_->intent_filters.empty()) {
512     CloneIntentFilters(state_->intent_filters, &intent_filters);
513   }
514 
515   return intent_filters;
516 }
517 
IntentFiltersChanged() const518 bool AppUpdate::IntentFiltersChanged() const {
519   return delta_ && !delta_->intent_filters.empty() &&
520          (!state_ || (delta_->intent_filters != state_->intent_filters));
521 }
522 
AccountId() const523 const ::AccountId& AppUpdate::AccountId() const {
524   return account_id_;
525 }
526 
527 }  // namespace apps
528