1 // Copyright 2019 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/chromeos/app_mode/web_app/web_kiosk_app_manager.h>
6 
7 #include <map>
8 
9 #include "base/bind.h"
10 #include "chrome/browser/chromeos/app_mode/app_session.h"
11 #include "chrome/browser/chromeos/app_mode/kiosk_cryptohome_remover.h"
12 #include "chrome/browser/chromeos/policy/device_local_account.h"
13 #include "chrome/browser/ui/browser.h"
14 #include "chrome/browser/web_applications/components/web_app_helpers.h"
15 #include "chrome/browser/web_applications/components/web_application_info.h"
16 #include "chromeos/settings/cros_settings_names.h"
17 #include "components/prefs/pref_registry_simple.h"
18 
19 namespace chromeos {
20 
21 namespace {
22 // This class is owned by ChromeBrowserMainPartsChromeos.
23 static WebKioskAppManager* g_web_kiosk_app_manager = nullptr;
24 }  // namespace
25 
26 // static
27 const char WebKioskAppManager::kWebKioskDictionaryName[] = "web-kiosk";
28 
29 // static
RegisterPrefs(PrefRegistrySimple * registry)30 void WebKioskAppManager::RegisterPrefs(PrefRegistrySimple* registry) {
31   registry->RegisterDictionaryPref(kWebKioskDictionaryName);
32 }
33 
34 // static
IsInitialized()35 bool WebKioskAppManager::IsInitialized() {
36   return g_web_kiosk_app_manager;
37 }
38 
39 // static
Get()40 WebKioskAppManager* WebKioskAppManager::Get() {
41   CHECK(g_web_kiosk_app_manager);
42   return g_web_kiosk_app_manager;
43 }
44 
WebKioskAppManager()45 WebKioskAppManager::WebKioskAppManager()
46     : auto_launch_account_id_(EmptyAccountId()) {
47   CHECK(!g_web_kiosk_app_manager);  // Only one instance is allowed.
48   g_web_kiosk_app_manager = this;
49   UpdateAppsFromPolicy();
50 }
51 
~WebKioskAppManager()52 WebKioskAppManager::~WebKioskAppManager() {
53   g_web_kiosk_app_manager = nullptr;
54 }
55 
GetApps(std::vector<App> * apps) const56 void WebKioskAppManager::GetApps(std::vector<App>* apps) const {
57   apps->clear();
58   apps->reserve(apps_.size());
59   for (auto& web_app : apps_) {
60     App app(*web_app);
61     app.url = web_app->install_url();
62     apps->push_back(std::move(app));
63   }
64 }
65 
LoadIcons()66 void WebKioskAppManager::LoadIcons() {
67   for (auto& web_app : apps_)
68     web_app->LoadIcon();
69 }
70 
GetAutoLaunchAccountId() const71 const AccountId& WebKioskAppManager::GetAutoLaunchAccountId() const {
72   return auto_launch_account_id_;
73 }
74 
GetAppByAccountId(const AccountId & account_id) const75 const WebKioskAppData* WebKioskAppManager::GetAppByAccountId(
76     const AccountId& account_id) const {
77   for (const auto& web_app : apps_) {
78     if (web_app->account_id() == account_id) {
79       return web_app.get();
80     }
81   }
82   return nullptr;
83 }
84 
UpdateAppByAccountId(const AccountId & account_id,std::unique_ptr<WebApplicationInfo> app_info)85 void WebKioskAppManager::UpdateAppByAccountId(
86     const AccountId& account_id,
87     std::unique_ptr<WebApplicationInfo> app_info) {
88   for (auto& web_app : apps_) {
89     if (web_app->account_id() == account_id) {
90       web_app->UpdateFromWebAppInfo(std::move(app_info));
91       return;
92     }
93   }
94   NOTREACHED();
95 }
96 
AddAppForTesting(const AccountId & account_id,const GURL & install_url)97 void WebKioskAppManager::AddAppForTesting(const AccountId& account_id,
98                                           const GURL& install_url) {
99   const std::string app_id = web_app::GenerateAppIdFromURL(install_url);
100   apps_.push_back(std::make_unique<WebKioskAppData>(
101       this, app_id, account_id, install_url, /*title*/ std::string(),
102       /*icon_url*/ GURL()));
103   NotifyKioskAppsChanged();
104 }
105 
InitSession(Browser * browser)106 void WebKioskAppManager::InitSession(Browser* browser) {
107   LOG_IF(FATAL, app_session_) << "Kiosk session is already initialized.";
108 
109   app_session_ = std::make_unique<AppSession>();
110   app_session_->InitForWebKiosk(browser);
111   NotifySessionInitialized();
112 }
113 
UpdateAppsFromPolicy()114 void WebKioskAppManager::UpdateAppsFromPolicy() {
115   // Store current apps. We will compare old and new apps to determine which
116   // apps are new, and which were deleted.
117   std::map<std::string, std::unique_ptr<WebKioskAppData>> old_apps;
118   for (auto& app : apps_)
119     old_apps[app->app_id()] = std::move(app);
120   apps_.clear();
121   auto_launch_account_id_.clear();
122   auto_launched_with_zero_delay_ = false;
123   std::string auto_login_account_id_from_settings;
124   CrosSettings::Get()->GetString(kAccountsPrefDeviceLocalAccountAutoLoginId,
125                                  &auto_login_account_id_from_settings);
126 
127   // Re-populates |apps_| and reuses existing apps when possible.
128   const std::vector<policy::DeviceLocalAccount> device_local_accounts =
129       policy::GetDeviceLocalAccounts(CrosSettings::Get());
130   for (auto account : device_local_accounts) {
131     if (account.type != policy::DeviceLocalAccount::TYPE_WEB_KIOSK_APP)
132       continue;
133     const AccountId account_id(AccountId::FromUserEmail(account.user_id));
134 
135     if (account.account_id == auto_login_account_id_from_settings) {
136       auto_launch_account_id_ = account_id;
137       int auto_launch_delay = 0;
138       CrosSettings::Get()->GetInteger(
139           kAccountsPrefDeviceLocalAccountAutoLoginDelay, &auto_launch_delay);
140       auto_launched_with_zero_delay_ = auto_launch_delay == 0;
141     }
142 
143     GURL url(account.web_kiosk_app_info.url());
144     std::string title = account.web_kiosk_app_info.title();
145     GURL icon_url = GURL(account.web_kiosk_app_info.icon_url());
146 
147     std::string app_id = web_app::GenerateAppIdFromURL(url);
148 
149     auto old_it = old_apps.find(app_id);
150     if (old_it != old_apps.end()) {
151       apps_.push_back(std::move(old_it->second));
152       old_apps.erase(old_it);
153     } else {
154       apps_.push_back(std::make_unique<WebKioskAppData>(
155           this, app_id, account_id, std::move(url), title,
156           std::move(icon_url)));
157       apps_.back()->LoadFromCache();
158     }
159 
160     KioskCryptohomeRemover::CancelDelayedCryptohomeRemoval(account_id);
161   }
162 
163   std::vector<KioskAppDataBase*> old_apps_to_remove;
164   for (auto& entry : old_apps)
165     old_apps_to_remove.emplace_back(entry.second.get());
166   ClearRemovedApps(old_apps_to_remove);
167   NotifyKioskAppsChanged();
168 }
169 
170 }  // namespace chromeos
171