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/apps/app_service/built_in_chromeos_apps.h"
6 
7 #include <utility>
8 #include <vector>
9 
10 #include "ash/public/cpp/app_list/app_list_metrics.h"
11 #include "ash/public/cpp/app_list/internal_app_id_constants.h"
12 #include "ash/public/cpp/app_menu_constants.h"
13 #include "ash/public/cpp/keyboard_shortcut_viewer.h"
14 #include "base/metrics/user_metrics.h"
15 #include "base/time/time.h"
16 #include "chrome/browser/apps/app_service/app_icon_factory.h"
17 #include "chrome/browser/apps/app_service/app_service_metrics.h"
18 #include "chrome/browser/apps/app_service/menu_util.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/ui/app_list/internal_app/internal_app_metadata.h"
21 #include "chrome/browser/ui/chrome_pages.h"
22 #include "chrome/browser/ui/settings_window_manager_chromeos.h"
23 #include "chrome/grit/generated_resources.h"
24 #include "components/services/app_service/public/mojom/types.mojom.h"
25 #include "ui/base/l10n/l10n_util.h"
26 
27 namespace {
28 
Convert(const app_list::InternalApp & internal_app)29 apps::mojom::AppPtr Convert(const app_list::InternalApp& internal_app) {
30   if ((internal_app.app_id == nullptr) ||
31       (internal_app.name_string_resource_id == 0) ||
32       (internal_app.icon_resource_id <= 0)) {
33     return apps::mojom::AppPtr();
34   }
35 
36   apps::mojom::AppPtr app = apps::PublisherBase::MakeApp(
37       apps::mojom::AppType::kBuiltIn, internal_app.app_id,
38       apps::mojom::Readiness::kReady,
39       l10n_util::GetStringUTF8(internal_app.name_string_resource_id),
40       apps::mojom::InstallSource::kSystem);
41 
42   if (internal_app.searchable_string_resource_id != 0) {
43     app->additional_search_terms.push_back(
44         l10n_util::GetStringUTF8(internal_app.searchable_string_resource_id));
45   }
46 
47   app->icon_key = apps::mojom::IconKey::New(
48       apps::mojom::IconKey::kDoesNotChangeOverTime,
49       internal_app.icon_resource_id, apps::IconEffects::kNone);
50 
51   app->recommendable = internal_app.recommendable
52                            ? apps::mojom::OptionalBool::kTrue
53                            : apps::mojom::OptionalBool::kFalse;
54   app->searchable = internal_app.searchable ? apps::mojom::OptionalBool::kTrue
55                                             : apps::mojom::OptionalBool::kFalse;
56   app->show_in_launcher = internal_app.show_in_launcher
57                               ? apps::mojom::OptionalBool::kTrue
58                               : apps::mojom::OptionalBool::kFalse;
59   app->show_in_shelf = app->show_in_search =
60       internal_app.searchable ? apps::mojom::OptionalBool::kTrue
61                               : apps::mojom::OptionalBool::kFalse;
62   app->show_in_management = apps::mojom::OptionalBool::kFalse;
63 
64   return app;
65 }
66 
67 }  // namespace
68 
69 namespace apps {
70 
BuiltInChromeOsApps(const mojo::Remote<apps::mojom::AppService> & app_service,Profile * profile)71 BuiltInChromeOsApps::BuiltInChromeOsApps(
72     const mojo::Remote<apps::mojom::AppService>& app_service,
73     Profile* profile)
74     : profile_(profile) {
75   PublisherBase::Initialize(app_service, apps::mojom::AppType::kBuiltIn);
76 }
77 
78 BuiltInChromeOsApps::~BuiltInChromeOsApps() = default;
79 
Connect(mojo::PendingRemote<apps::mojom::Subscriber> subscriber_remote,apps::mojom::ConnectOptionsPtr opts)80 void BuiltInChromeOsApps::Connect(
81     mojo::PendingRemote<apps::mojom::Subscriber> subscriber_remote,
82     apps::mojom::ConnectOptionsPtr opts) {
83   std::vector<apps::mojom::AppPtr> apps;
84   if (profile_) {
85     // TODO(crbug.com/826982): move source of truth for built-in apps from
86     // ui/app_list to here when the AppService feature is enabled by default.
87     for (const auto& internal_app : app_list::GetInternalAppList(profile_)) {
88       apps::mojom::AppPtr app = Convert(internal_app);
89       if (!app.is_null()) {
90         apps.push_back(std::move(app));
91       }
92     }
93   }
94   mojo::Remote<apps::mojom::Subscriber> subscriber(
95       std::move(subscriber_remote));
96   subscriber->OnApps(std::move(apps));
97 
98   // Unlike other apps::mojom::Publisher implementations, we don't need to
99   // retain the subscriber (e.g. add it to a
100   // mojo::RemoteSet<apps::mojom::Subscriber> subscribers_) after this
101   // function returns. The list of built-in Chrome OS apps is fixed for the
102   // lifetime of the Chrome OS session. There won't be any further updates.
103 }
104 
LoadIcon(const std::string & app_id,apps::mojom::IconKeyPtr icon_key,apps::mojom::IconType icon_type,int32_t size_hint_in_dip,bool allow_placeholder_icon,LoadIconCallback callback)105 void BuiltInChromeOsApps::LoadIcon(const std::string& app_id,
106                                    apps::mojom::IconKeyPtr icon_key,
107                                    apps::mojom::IconType icon_type,
108                                    int32_t size_hint_in_dip,
109                                    bool allow_placeholder_icon,
110                                    LoadIconCallback callback) {
111   constexpr bool is_placeholder_icon = false;
112   if (icon_key &&
113       (icon_key->resource_id != apps::mojom::IconKey::kInvalidResourceId)) {
114     LoadIconFromResource(
115         icon_type, size_hint_in_dip, icon_key->resource_id, is_placeholder_icon,
116         static_cast<IconEffects>(icon_key->icon_effects), std::move(callback));
117     return;
118   }
119   // On failure, we still run the callback, with the zero IconValue.
120   std::move(callback).Run(apps::mojom::IconValue::New());
121 }
122 
Launch(const std::string & app_id,int32_t event_flags,apps::mojom::LaunchSource launch_source,int64_t display_id)123 void BuiltInChromeOsApps::Launch(const std::string& app_id,
124                                  int32_t event_flags,
125                                  apps::mojom::LaunchSource launch_source,
126                                  int64_t display_id) {
127   if (app_id == ash::kInternalAppIdKeyboardShortcutViewer) {
128     ash::ToggleKeyboardShortcutViewer();
129   } else if (app_id == ash::kReleaseNotesAppId) {
130     base::RecordAction(
131         base::UserMetricsAction("ReleaseNotes.SuggestionChipLaunched"));
132     chrome::LaunchReleaseNotes(profile_, launch_source);
133   }
134 }
135 
GetMenuModel(const std::string & app_id,apps::mojom::MenuType menu_type,int64_t display_id,GetMenuModelCallback callback)136 void BuiltInChromeOsApps::GetMenuModel(const std::string& app_id,
137                                        apps::mojom::MenuType menu_type,
138                                        int64_t display_id,
139                                        GetMenuModelCallback callback) {
140   apps::mojom::MenuItemsPtr menu_items = apps::mojom::MenuItems::New();
141 
142   if (ShouldAddOpenItem(app_id, menu_type, profile_)) {
143     AddCommandItem(ash::MENU_OPEN_NEW, IDS_APP_CONTEXT_MENU_ACTIVATE_ARC,
144                    &menu_items);
145   }
146 
147   if (ShouldAddCloseItem(app_id, menu_type, profile_)) {
148     AddCommandItem(ash::MENU_CLOSE, IDS_SHELF_CONTEXT_MENU_CLOSE, &menu_items);
149   }
150 
151   std::move(callback).Run(std::move(menu_items));
152 }
153 
154 }  // namespace apps
155