OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h" | 5 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h" |
6 | 6 |
7 #include <map> | 7 #include <map> |
| 8 #include <set> |
8 | 9 |
9 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/logging.h" |
| 12 #include "base/memory/scoped_ptr.h" |
10 #include "base/path_service.h" | 13 #include "base/path_service.h" |
11 #include "base/prefs/pref_registry_simple.h" | 14 #include "base/prefs/pref_registry_simple.h" |
12 #include "base/stl_util.h" | 15 #include "base/stl_util.h" |
13 #include "base/values.h" | 16 #include "base/values.h" |
14 #include "chrome/browser/chromeos/app_mode/kiosk_app_data.h" | 17 #include "chrome/browser/chromeos/app_mode/kiosk_app_data.h" |
15 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager_observer.h" | 18 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager_observer.h" |
| 19 #include "chrome/browser/chromeos/login/user_manager.h" |
16 #include "chrome/browser/chromeos/settings/cros_settings.h" | 20 #include "chrome/browser/chromeos/settings/cros_settings.h" |
17 #include "chrome/common/chrome_notification_types.h" | 21 #include "chrome/common/chrome_notification_types.h" |
18 #include "chrome/common/chrome_paths.h" | 22 #include "chrome/common/chrome_paths.h" |
19 #include "chromeos/cryptohome/async_method_caller.h" | 23 #include "chromeos/cryptohome/async_method_caller.h" |
20 #include "content/public/browser/notification_details.h" | |
21 | 24 |
22 namespace chromeos { | 25 namespace chromeos { |
23 | 26 |
24 namespace { | 27 namespace { |
25 | 28 |
| 29 std::string FormatKioskAppUserId(const std::string& app_id) { |
| 30 return app_id + '@' + UserManager::kKioskAppUserDomain; |
| 31 } |
| 32 |
26 void OnRemoveAppCryptohomeComplete(const std::string& app, | 33 void OnRemoveAppCryptohomeComplete(const std::string& app, |
27 bool success, | 34 bool success, |
28 cryptohome::MountError return_code) { | 35 cryptohome::MountError return_code) { |
29 if (!success) { | 36 if (!success) { |
30 LOG(ERROR) << "Remove cryptohome for " << app | 37 LOG(ERROR) << "Remove cryptohome for " << app |
31 << " failed, return code: " << return_code; | 38 << " failed, return code: " << return_code; |
32 } | 39 } |
33 } | 40 } |
34 | 41 |
| 42 // Decodes a device-local account dictionary and extracts the |account_id| and |
| 43 // |app_id| if decoding is successful and the entry refers to a Kiosk App. |
| 44 bool DecodeDeviceLocalAccount(const base::Value* account_spec, |
| 45 std::string* account_id, |
| 46 std::string* app_id) { |
| 47 const base::DictionaryValue* account_dict = NULL; |
| 48 if (!account_spec->GetAsDictionary(&account_dict)) { |
| 49 NOTREACHED(); |
| 50 return false; |
| 51 } |
| 52 |
| 53 if (!account_dict->GetStringWithoutPathExpansion( |
| 54 kAccountsPrefDeviceLocalAccountsKeyId, account_id)) { |
| 55 LOG(ERROR) << "Account ID missing"; |
| 56 return false; |
| 57 } |
| 58 |
| 59 int type; |
| 60 if (!account_dict->GetIntegerWithoutPathExpansion( |
| 61 kAccountsPrefDeviceLocalAccountsKeyType, &type) || |
| 62 type != DEVICE_LOCAL_ACCOUNT_TYPE_KIOSK_APP) { |
| 63 // Not a kiosk app. |
| 64 return false; |
| 65 } |
| 66 |
| 67 if (!account_dict->GetStringWithoutPathExpansion( |
| 68 kAccountsPrefDeviceLocalAccountsKeyKioskAppId, app_id)) { |
| 69 LOG(ERROR) << "Kiosk app id missing for " << *account_id; |
| 70 return false; |
| 71 } |
| 72 |
| 73 return true; |
| 74 } |
| 75 |
35 } // namespace | 76 } // namespace |
36 | 77 |
37 // static | 78 // static |
38 const char KioskAppManager::kKioskDictionaryName[] = "kiosk"; | 79 const char KioskAppManager::kKioskDictionaryName[] = "kiosk"; |
39 const char KioskAppManager::kKeyApps[] = "apps"; | 80 const char KioskAppManager::kKeyApps[] = "apps"; |
40 const char KioskAppManager::kIconCacheDir[] = "kiosk"; | 81 const char KioskAppManager::kIconCacheDir[] = "kiosk"; |
41 | 82 |
42 // static | 83 // static |
43 static base::LazyInstance<KioskAppManager> instance = LAZY_INSTANCE_INITIALIZER; | 84 static base::LazyInstance<KioskAppManager> instance = LAZY_INSTANCE_INITIALIZER; |
44 KioskAppManager* KioskAppManager::Get() { | 85 KioskAppManager* KioskAppManager::Get() { |
(...skipping 17 matching lines...) Expand all Loading... |
62 : id(data.id()), | 103 : id(data.id()), |
63 name(data.name()), | 104 name(data.name()), |
64 icon(data.icon()), | 105 icon(data.icon()), |
65 is_loading(data.IsLoading()) { | 106 is_loading(data.IsLoading()) { |
66 } | 107 } |
67 | 108 |
68 KioskAppManager::App::App() : is_loading(false) {} | 109 KioskAppManager::App::App() : is_loading(false) {} |
69 KioskAppManager::App::~App() {} | 110 KioskAppManager::App::~App() {} |
70 | 111 |
71 std::string KioskAppManager::GetAutoLaunchApp() const { | 112 std::string KioskAppManager::GetAutoLaunchApp() const { |
72 std::string app_id; | 113 return auto_launch_app_id_; |
73 if (CrosSettings::Get()->GetString(kKioskAutoLaunch, &app_id)) | |
74 return app_id; | |
75 | |
76 return std::string(); | |
77 } | 114 } |
78 | 115 |
79 void KioskAppManager::SetAutoLaunchApp(const std::string& app_id) { | 116 void KioskAppManager::SetAutoLaunchApp(const std::string& app_id) { |
80 CrosSettings::Get()->SetString(kKioskAutoLaunch, app_id); | 117 CrosSettings::Get()->SetString( |
| 118 kAccountsPrefDeviceLocalAccountAutoLoginId, |
| 119 app_id.empty() ? std::string() : FormatKioskAppUserId(app_id)); |
| 120 CrosSettings::Get()->SetInteger( |
| 121 kAccountsPrefDeviceLocalAccountAutoLoginDelay, 0); |
81 } | 122 } |
82 | 123 |
83 void KioskAppManager::AddApp(const std::string& app_id) { | 124 void KioskAppManager::AddApp(const std::string& app_id) { |
84 base::StringValue value(app_id); | 125 CrosSettings* cros_settings = CrosSettings::Get(); |
85 CrosSettings::Get()->AppendToList(kKioskApps, &value); | 126 const base::ListValue* accounts_list = NULL; |
| 127 cros_settings->GetList(kAccountsPrefDeviceLocalAccounts, &accounts_list); |
| 128 |
| 129 // Don't insert if the app if it's already in the list. |
| 130 base::ListValue new_accounts_list; |
| 131 if (accounts_list) { |
| 132 for (base::ListValue::const_iterator entry(accounts_list->begin()); |
| 133 entry != accounts_list->end(); ++entry) { |
| 134 std::string account_id; |
| 135 std::string kiosk_app_id; |
| 136 if (DecodeDeviceLocalAccount(*entry, &account_id, &kiosk_app_id) && |
| 137 kiosk_app_id == app_id) { |
| 138 return; |
| 139 } |
| 140 new_accounts_list.Append((*entry)->DeepCopy()); |
| 141 } |
| 142 } |
| 143 |
| 144 // Add the new account. |
| 145 scoped_ptr<base::DictionaryValue> new_entry(new base::DictionaryValue()); |
| 146 new_entry->SetStringWithoutPathExpansion( |
| 147 kAccountsPrefDeviceLocalAccountsKeyId, FormatKioskAppUserId(app_id)); |
| 148 new_entry->SetIntegerWithoutPathExpansion( |
| 149 kAccountsPrefDeviceLocalAccountsKeyType, |
| 150 DEVICE_LOCAL_ACCOUNT_TYPE_KIOSK_APP); |
| 151 new_entry->SetStringWithoutPathExpansion( |
| 152 kAccountsPrefDeviceLocalAccountsKeyKioskAppId, app_id); |
| 153 new_accounts_list.Append(new_entry.release()); |
| 154 cros_settings->Set(kAccountsPrefDeviceLocalAccounts, new_accounts_list); |
86 } | 155 } |
87 | 156 |
88 void KioskAppManager::RemoveApp(const std::string& app_id) { | 157 void KioskAppManager::RemoveApp(const std::string& app_id) { |
89 base::StringValue value(app_id); | 158 CrosSettings* cros_settings = CrosSettings::Get(); |
90 CrosSettings::Get()->RemoveFromList(kKioskApps, &value); | 159 const base::ListValue* accounts_list = NULL; |
| 160 cros_settings->GetList(kAccountsPrefDeviceLocalAccounts, &accounts_list); |
| 161 if (!accounts_list) |
| 162 return; |
| 163 |
| 164 // Duplicate the list, filtering out entries that match |app_id|. |
| 165 base::ListValue new_accounts_list; |
| 166 for (base::ListValue::const_iterator entry(accounts_list->begin()); |
| 167 entry != accounts_list->end(); ++entry) { |
| 168 std::string account_id; |
| 169 std::string kiosk_app_id; |
| 170 if (DecodeDeviceLocalAccount(*entry, &account_id, &kiosk_app_id) && |
| 171 kiosk_app_id == app_id) { |
| 172 continue; |
| 173 } |
| 174 new_accounts_list.Append((*entry)->DeepCopy()); |
| 175 } |
| 176 |
| 177 cros_settings->Set(kAccountsPrefDeviceLocalAccounts, new_accounts_list); |
91 } | 178 } |
92 | 179 |
93 void KioskAppManager::GetApps(Apps* apps) const { | 180 void KioskAppManager::GetApps(Apps* apps) const { |
94 apps->reserve(apps_.size()); | 181 apps->reserve(apps_.size()); |
95 for (size_t i = 0; i < apps_.size(); ++i) | 182 for (size_t i = 0; i < apps_.size(); ++i) |
96 apps->push_back(App(*apps_[i])); | 183 apps->push_back(App(*apps_[i])); |
97 } | 184 } |
98 | 185 |
99 bool KioskAppManager::GetApp(const std::string& app_id, App* app) const { | 186 bool KioskAppManager::GetApp(const std::string& app_id, App* app) const { |
100 const KioskAppData* data = GetAppData(app_id); | 187 const KioskAppData* data = GetAppData(app_id); |
101 if (!data) | 188 if (!data) |
102 return false; | 189 return false; |
103 | 190 |
104 *app = App(*data); | 191 *app = App(*data); |
105 return true; | 192 return true; |
106 } | 193 } |
107 | 194 |
108 const base::RefCountedString* KioskAppManager::GetAppRawIcon( | 195 const base::RefCountedString* KioskAppManager::GetAppRawIcon( |
109 const std::string& app_id) const { | 196 const std::string& app_id) const { |
110 const KioskAppData* data = GetAppData(app_id); | 197 const KioskAppData* data = GetAppData(app_id); |
111 if (!data) | 198 if (!data) |
112 return NULL; | 199 return NULL; |
113 | 200 |
114 return data->raw_icon(); | 201 return data->raw_icon(); |
115 } | 202 } |
116 | 203 |
117 bool KioskAppManager::GetDisableBailoutShortcut() const { | 204 bool KioskAppManager::GetDisableBailoutShortcut() const { |
118 bool disable; | 205 bool enable; |
119 if (CrosSettings::Get()->GetBoolean(kKioskDisableBailoutShortcut, &disable)) | 206 if (CrosSettings::Get()->GetBoolean( |
120 return disable; | 207 kAccountsPrefDeviceLocalAccountAutoLoginBailoutEnabled, &enable)) { |
| 208 return !enable; |
| 209 } |
121 | 210 |
122 return false; | 211 return false; |
123 } | 212 } |
124 | 213 |
125 void KioskAppManager::AddObserver(KioskAppManagerObserver* observer) { | 214 void KioskAppManager::AddObserver(KioskAppManagerObserver* observer) { |
126 observers_.AddObserver(observer); | 215 observers_.AddObserver(observer); |
127 } | 216 } |
128 | 217 |
129 void KioskAppManager::RemoveObserver(KioskAppManagerObserver* observer) { | 218 void KioskAppManager::RemoveObserver(KioskAppManagerObserver* observer) { |
130 observers_.RemoveObserver(observer); | 219 observers_.RemoveObserver(observer); |
131 } | 220 } |
132 | 221 |
133 KioskAppManager::KioskAppManager() { | 222 KioskAppManager::KioskAppManager() { |
134 UpdateAppData(); | 223 UpdateAppData(); |
135 CrosSettings::Get()->AddSettingsObserver(kKioskApps, this); | 224 CrosSettings::Get()->AddSettingsObserver( |
| 225 kAccountsPrefDeviceLocalAccounts, this); |
| 226 CrosSettings::Get()->AddSettingsObserver( |
| 227 kAccountsPrefDeviceLocalAccountAutoLoginId, this); |
136 } | 228 } |
137 | 229 |
138 KioskAppManager::~KioskAppManager() {} | 230 KioskAppManager::~KioskAppManager() {} |
139 | 231 |
140 void KioskAppManager::CleanUp() { | 232 void KioskAppManager::CleanUp() { |
141 CrosSettings::Get()->RemoveSettingsObserver(kKioskApps, this); | 233 CrosSettings::Get()->RemoveSettingsObserver( |
| 234 kAccountsPrefDeviceLocalAccounts, this); |
| 235 CrosSettings::Get()->RemoveSettingsObserver( |
| 236 kAccountsPrefDeviceLocalAccountAutoLoginId, this); |
142 apps_.clear(); | 237 apps_.clear(); |
143 } | 238 } |
144 | 239 |
145 const KioskAppData* KioskAppManager::GetAppData( | 240 const KioskAppData* KioskAppManager::GetAppData( |
146 const std::string& app_id) const { | 241 const std::string& app_id) const { |
147 for (size_t i = 0; i < apps_.size(); ++i) { | 242 for (size_t i = 0; i < apps_.size(); ++i) { |
148 const KioskAppData* data = apps_[i]; | 243 const KioskAppData* data = apps_[i]; |
149 if (data->id() == app_id) | 244 if (data->id() == app_id) |
150 return data; | 245 return data; |
151 } | 246 } |
152 | 247 |
153 return NULL; | 248 return NULL; |
154 } | 249 } |
155 | 250 |
156 void KioskAppManager::UpdateAppData() { | 251 void KioskAppManager::UpdateAppData() { |
157 // Gets app id to data mapping for existing apps. | 252 // Gets app id to data mapping for existing apps. |
158 std::map<std::string, KioskAppData*> old_apps; | 253 std::map<std::string, KioskAppData*> old_apps; |
159 for (size_t i = 0; i < apps_.size(); ++i) | 254 for (size_t i = 0; i < apps_.size(); ++i) |
160 old_apps[apps_[i]->id()] = apps_[i]; | 255 old_apps[apps_[i]->id()] = apps_[i]; |
161 apps_.weak_clear(); // |old_apps| takes ownership | 256 apps_.weak_clear(); // |old_apps| takes ownership |
162 | 257 |
163 const base::ListValue* new_apps; | 258 auto_launch_app_id_.clear(); |
164 CHECK(CrosSettings::Get()->GetList(kKioskApps, &new_apps)); | 259 std::string auto_login_account_id; |
| 260 CrosSettings::Get()->GetString(kAccountsPrefDeviceLocalAccountAutoLoginId, |
| 261 &auto_login_account_id); |
165 | 262 |
166 // Re-populates |apps_| and reuses existing KioskAppData when possible. | 263 const base::ListValue* local_accounts; |
167 for (base::ListValue::const_iterator new_it = new_apps->begin(); | 264 if (CrosSettings::Get()->GetList(kAccountsPrefDeviceLocalAccounts, |
168 new_it != new_apps->end(); | 265 &local_accounts)) { |
169 ++new_it) { | 266 // Re-populates |apps_| and reuses existing KioskAppData when possible. |
170 std::string id; | 267 for (base::ListValue::const_iterator account(local_accounts->begin()); |
171 CHECK((*new_it)->GetAsString(&id)); | 268 account != local_accounts->end(); ++account) { |
| 269 std::string account_id; |
| 270 std::string kiosk_app_id; |
| 271 if (!DecodeDeviceLocalAccount(*account, &account_id, &kiosk_app_id)) |
| 272 continue; |
172 | 273 |
173 std::map<std::string, KioskAppData*>::iterator old_it = old_apps.find(id); | 274 if (account_id == auto_login_account_id) |
174 if (old_it != old_apps.end()) { | 275 auto_launch_app_id_ = kiosk_app_id; |
175 apps_.push_back(old_it->second); | 276 |
176 old_apps.erase(old_it); | 277 // TODO(mnissler): Support non-CWS update URLs. |
177 } else { | 278 |
178 KioskAppData* new_app = new KioskAppData(this, id); | 279 std::map<std::string, KioskAppData*>::iterator old_it = |
179 apps_.push_back(new_app); // Takes ownership of |new_app|. | 280 old_apps.find(kiosk_app_id); |
180 new_app->Load(); | 281 if (old_it != old_apps.end()) { |
| 282 apps_.push_back(old_it->second); |
| 283 old_apps.erase(old_it); |
| 284 } else { |
| 285 KioskAppData* new_app = new KioskAppData(this, kiosk_app_id); |
| 286 apps_.push_back(new_app); // Takes ownership of |new_app|. |
| 287 new_app->Load(); |
| 288 } |
181 } | 289 } |
182 } | 290 } |
183 | 291 |
184 // Clears cache and deletes the remaining old data. | 292 // Clears cache and deletes the remaining old data. |
185 for (std::map<std::string, KioskAppData*>::iterator it = old_apps.begin(); | 293 for (std::map<std::string, KioskAppData*>::iterator it = old_apps.begin(); |
186 it != old_apps.end(); ++it) { | 294 it != old_apps.end(); ++it) { |
187 it->second->ClearCache(); | 295 it->second->ClearCache(); |
188 cryptohome::AsyncMethodCaller::GetInstance()->AsyncRemove( | 296 cryptohome::AsyncMethodCaller::GetInstance()->AsyncRemove( |
189 it->first, base::Bind(&OnRemoveAppCryptohomeComplete, it->first)); | 297 it->first, base::Bind(&OnRemoveAppCryptohomeComplete, it->first)); |
190 } | 298 } |
191 STLDeleteValues(&old_apps); | 299 STLDeleteValues(&old_apps); |
| 300 |
| 301 FOR_EACH_OBSERVER(KioskAppManagerObserver, observers_, |
| 302 OnKioskAppsSettingsChanged()); |
192 } | 303 } |
193 | 304 |
194 void KioskAppManager::Observe(int type, | 305 void KioskAppManager::Observe(int type, |
195 const content::NotificationSource& source, | 306 const content::NotificationSource& source, |
196 const content::NotificationDetails& details) { | 307 const content::NotificationDetails& details) { |
197 DCHECK_EQ(chrome::NOTIFICATION_SYSTEM_SETTING_CHANGED, type); | 308 DCHECK_EQ(chrome::NOTIFICATION_SYSTEM_SETTING_CHANGED, type); |
198 DCHECK_EQ(kKioskApps, | |
199 *content::Details<const std::string>(details).ptr()); | |
200 | |
201 UpdateAppData(); | 309 UpdateAppData(); |
202 } | 310 } |
203 | 311 |
204 void KioskAppManager::GetKioskAppIconCacheDir(base::FilePath* cache_dir) { | 312 void KioskAppManager::GetKioskAppIconCacheDir(base::FilePath* cache_dir) { |
205 base::FilePath user_data_dir; | 313 base::FilePath user_data_dir; |
206 CHECK(PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)); | 314 CHECK(PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)); |
207 *cache_dir = user_data_dir.AppendASCII(kIconCacheDir); | 315 *cache_dir = user_data_dir.AppendASCII(kIconCacheDir); |
208 } | 316 } |
209 | 317 |
210 void KioskAppManager::OnKioskAppDataChanged(const std::string& app_id) { | 318 void KioskAppManager::OnKioskAppDataChanged(const std::string& app_id) { |
211 FOR_EACH_OBSERVER(KioskAppManagerObserver, | 319 FOR_EACH_OBSERVER(KioskAppManagerObserver, |
212 observers_, | 320 observers_, |
213 OnKioskAppDataChanged(app_id)); | 321 OnKioskAppDataChanged(app_id)); |
214 } | 322 } |
215 | 323 |
216 void KioskAppManager::OnKioskAppDataLoadFailure(const std::string& app_id) { | 324 void KioskAppManager::OnKioskAppDataLoadFailure(const std::string& app_id) { |
217 FOR_EACH_OBSERVER(KioskAppManagerObserver, | 325 FOR_EACH_OBSERVER(KioskAppManagerObserver, |
218 observers_, | 326 observers_, |
219 OnKioskAppDataLoadFailure(app_id)); | 327 OnKioskAppDataLoadFailure(app_id)); |
220 RemoveApp(app_id); | 328 RemoveApp(app_id); |
221 } | 329 } |
222 | 330 |
223 } // namespace chromeos | 331 } // namespace chromeos |
OLD | NEW |