Chromium Code Reviews| 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(kAccountsPrefDeviceLocalAccountAutoLoginId, |
| 118 FormatKioskAppUserId(app_id)); | |
| 119 CrosSettings::Get()->SetInteger(kAccountsPrefDeviceLocalAccountAutoLoginDelay, | |
| 120 0); | |
| 81 } | 121 } |
| 82 | 122 |
| 83 void KioskAppManager::AddApp(const std::string& app_id) { | 123 void KioskAppManager::AddApp(const std::string& app_id) { |
| 84 base::StringValue value(app_id); | 124 CrosSettings* cros_settings = CrosSettings::Get(); |
| 85 CrosSettings::Get()->AppendToList(kKioskApps, &value); | 125 const base::ListValue* accounts_list = NULL; |
| 126 cros_settings->GetList(kAccountsPrefDeviceLocalAccounts, &accounts_list); | |
| 127 | |
| 128 // Don't insert if the app if it's already in the list. | |
| 129 base::ListValue new_accounts_list; | |
| 130 for (base::ListValue::const_iterator entry(accounts_list->begin()); | |
| 131 entry != accounts_list->end(); ++entry) { | |
| 132 std::string account_id; | |
| 133 std::string kiosk_app_id; | |
| 134 if (DecodeDeviceLocalAccount(*entry, &account_id, &kiosk_app_id) && | |
| 135 kiosk_app_id == app_id) { | |
| 136 return; | |
| 137 } | |
| 138 new_accounts_list.Append((*entry)->DeepCopy()); | |
| 139 } | |
| 140 | |
| 141 // Add the new account. | |
| 142 scoped_ptr<base::DictionaryValue> new_entry(new base::DictionaryValue()); | |
| 143 new_entry->SetStringWithoutPathExpansion( | |
| 144 kAccountsPrefDeviceLocalAccountsKeyId, FormatKioskAppUserId(app_id)); | |
| 145 new_entry->SetIntegerWithoutPathExpansion( | |
| 146 kAccountsPrefDeviceLocalAccountsKeyType, | |
| 147 DEVICE_LOCAL_ACCOUNT_TYPE_KIOSK_APP); | |
| 148 new_entry->SetStringWithoutPathExpansion( | |
| 149 kAccountsPrefDeviceLocalAccountsKeyKioskAppId, app_id); | |
| 150 new_accounts_list.Append(new_entry.release()); | |
| 151 cros_settings->Set(kAccountsPrefDeviceLocalAccounts, new_accounts_list); | |
| 86 } | 152 } |
| 87 | 153 |
| 88 void KioskAppManager::RemoveApp(const std::string& app_id) { | 154 void KioskAppManager::RemoveApp(const std::string& app_id) { |
| 89 base::StringValue value(app_id); | 155 CrosSettings* cros_settings = CrosSettings::Get(); |
| 90 CrosSettings::Get()->RemoveFromList(kKioskApps, &value); | 156 const base::ListValue* accounts_list = NULL; |
| 157 cros_settings->GetList(kAccountsPrefDeviceLocalAccounts, &accounts_list); | |
| 158 | |
| 159 // Duplicate the list, filtering out entries that match |app_id|. | |
| 160 base::ListValue new_accounts_list; | |
| 161 for (base::ListValue::const_iterator entry(accounts_list->begin()); | |
| 162 entry != accounts_list->end(); ++entry) { | |
| 163 std::string account_id; | |
| 164 std::string kiosk_app_id; | |
| 165 if (DecodeDeviceLocalAccount(*entry, &account_id, &kiosk_app_id) && | |
| 166 kiosk_app_id == app_id) { | |
| 167 continue; | |
| 168 } | |
| 169 new_accounts_list.Append((*entry)->DeepCopy()); | |
| 170 } | |
| 171 | |
| 172 cros_settings->Set(kAccountsPrefDeviceLocalAccounts, new_accounts_list); | |
| 91 } | 173 } |
| 92 | 174 |
| 93 void KioskAppManager::GetApps(Apps* apps) const { | 175 void KioskAppManager::GetApps(Apps* apps) const { |
| 94 apps->reserve(apps_.size()); | 176 apps->reserve(apps_.size()); |
| 95 for (size_t i = 0; i < apps_.size(); ++i) | 177 for (size_t i = 0; i < apps_.size(); ++i) |
| 96 apps->push_back(App(*apps_[i])); | 178 apps->push_back(App(*apps_[i])); |
| 97 } | 179 } |
| 98 | 180 |
| 99 bool KioskAppManager::GetApp(const std::string& app_id, App* app) const { | 181 bool KioskAppManager::GetApp(const std::string& app_id, App* app) const { |
| 100 const KioskAppData* data = GetAppData(app_id); | 182 const KioskAppData* data = GetAppData(app_id); |
| 101 if (!data) | 183 if (!data) |
| 102 return false; | 184 return false; |
| 103 | 185 |
| 104 *app = App(*data); | 186 *app = App(*data); |
| 105 return true; | 187 return true; |
| 106 } | 188 } |
| 107 | 189 |
| 108 const base::RefCountedString* KioskAppManager::GetAppRawIcon( | 190 const base::RefCountedString* KioskAppManager::GetAppRawIcon( |
| 109 const std::string& app_id) const { | 191 const std::string& app_id) const { |
| 110 const KioskAppData* data = GetAppData(app_id); | 192 const KioskAppData* data = GetAppData(app_id); |
| 111 if (!data) | 193 if (!data) |
| 112 return NULL; | 194 return NULL; |
| 113 | 195 |
| 114 return data->raw_icon(); | 196 return data->raw_icon(); |
| 115 } | 197 } |
| 116 | 198 |
| 117 bool KioskAppManager::GetDisableBailoutShortcut() const { | 199 bool KioskAppManager::GetDisableBailoutShortcut() const { |
| 118 bool disable; | 200 bool enable; |
| 119 if (CrosSettings::Get()->GetBoolean(kKioskDisableBailoutShortcut, &disable)) | 201 if (CrosSettings::Get()->GetBoolean( |
| 120 return disable; | 202 kAccountsPrefDeviceLocalAccountAutoLoginBailoutEnabled, &enable)) { |
| 203 return !enable; | |
| 204 } | |
| 121 | 205 |
| 122 return false; | 206 return false; |
| 123 } | 207 } |
| 124 | 208 |
| 125 void KioskAppManager::AddObserver(KioskAppManagerObserver* observer) { | 209 void KioskAppManager::AddObserver(KioskAppManagerObserver* observer) { |
| 126 observers_.AddObserver(observer); | 210 observers_.AddObserver(observer); |
| 127 } | 211 } |
| 128 | 212 |
| 129 void KioskAppManager::RemoveObserver(KioskAppManagerObserver* observer) { | 213 void KioskAppManager::RemoveObserver(KioskAppManagerObserver* observer) { |
| 130 observers_.RemoveObserver(observer); | 214 observers_.RemoveObserver(observer); |
| 131 } | 215 } |
| 132 | 216 |
| 133 KioskAppManager::KioskAppManager() { | 217 KioskAppManager::KioskAppManager() { |
| 134 UpdateAppData(); | 218 UpdateAppData(); |
| 135 CrosSettings::Get()->AddSettingsObserver(kKioskApps, this); | 219 CrosSettings::Get()->AddSettingsObserver( |
| 220 kAccountsPrefDeviceLocalAccounts, this); | |
| 221 CrosSettings::Get()->AddSettingsObserver( | |
| 222 kAccountsPrefDeviceLocalAccountAutoLoginId, this); | |
| 136 } | 223 } |
| 137 | 224 |
| 138 KioskAppManager::~KioskAppManager() {} | 225 KioskAppManager::~KioskAppManager() {} |
| 139 | 226 |
| 140 void KioskAppManager::CleanUp() { | 227 void KioskAppManager::CleanUp() { |
| 141 CrosSettings::Get()->RemoveSettingsObserver(kKioskApps, this); | 228 CrosSettings::Get()->RemoveSettingsObserver( |
| 229 kAccountsPrefDeviceLocalAccounts, this); | |
| 230 CrosSettings::Get()->RemoveSettingsObserver( | |
| 231 kAccountsPrefDeviceLocalAccountAutoLoginId, this); | |
| 142 apps_.clear(); | 232 apps_.clear(); |
| 143 } | 233 } |
| 144 | 234 |
| 145 const KioskAppData* KioskAppManager::GetAppData( | 235 const KioskAppData* KioskAppManager::GetAppData( |
| 146 const std::string& app_id) const { | 236 const std::string& app_id) const { |
| 147 for (size_t i = 0; i < apps_.size(); ++i) { | 237 for (size_t i = 0; i < apps_.size(); ++i) { |
| 148 const KioskAppData* data = apps_[i]; | 238 const KioskAppData* data = apps_[i]; |
| 149 if (data->id() == app_id) | 239 if (data->id() == app_id) |
| 150 return data; | 240 return data; |
| 151 } | 241 } |
| 152 | 242 |
| 153 return NULL; | 243 return NULL; |
| 154 } | 244 } |
| 155 | 245 |
| 156 void KioskAppManager::UpdateAppData() { | 246 void KioskAppManager::UpdateAppData() { |
| 157 // Gets app id to data mapping for existing apps. | 247 // Gets app id to data mapping for existing apps. |
| 158 std::map<std::string, KioskAppData*> old_apps; | 248 std::map<std::string, KioskAppData*> old_apps; |
| 159 for (size_t i = 0; i < apps_.size(); ++i) | 249 for (size_t i = 0; i < apps_.size(); ++i) |
| 160 old_apps[apps_[i]->id()] = apps_[i]; | 250 old_apps[apps_[i]->id()] = apps_[i]; |
| 161 apps_.weak_clear(); // |old_apps| takes ownership | 251 apps_.weak_clear(); // |old_apps| takes ownership |
| 162 | 252 |
| 163 const base::ListValue* new_apps; | 253 auto_launch_app_id_.clear(); |
| 164 CHECK(CrosSettings::Get()->GetList(kKioskApps, &new_apps)); | 254 std::string auto_login_account_id_; |
|
bartfab (slow)
2013/04/26 12:34:59
Nit: Remove trailing underscore.
Mattias Nissler (ping if slow)
2013/04/26 13:44:46
Done.
| |
| 255 CrosSettings::Get()->GetString(kAccountsPrefDeviceLocalAccountAutoLoginId, | |
| 256 &auto_login_account_id_); | |
| 165 | 257 |
| 166 // Re-populates |apps_| and reuses existing KioskAppData when possible. | 258 const base::ListValue* local_accounts; |
| 167 for (base::ListValue::const_iterator new_it = new_apps->begin(); | 259 if (CrosSettings::Get()->GetList(kAccountsPrefDeviceLocalAccounts, |
|
bartfab (slow)
2013/04/26 12:34:59
Nit: This is a bit inconsistent: In some places, e
Mattias Nissler (ping if slow)
2013/04/26 13:44:46
Fixed the other two call sites.
| |
| 168 new_it != new_apps->end(); | 260 &local_accounts)) { |
| 169 ++new_it) { | 261 // Re-populates |apps_| and reuses existing KioskAppData when possible. |
| 170 std::string id; | 262 for (base::ListValue::const_iterator account(local_accounts->begin()); |
| 171 CHECK((*new_it)->GetAsString(&id)); | 263 account != local_accounts->end(); ++account) { |
| 264 std::string account_id; | |
| 265 std::string kiosk_app_id; | |
| 266 if (!DecodeDeviceLocalAccount(*account, &account_id, &kiosk_app_id)) | |
| 267 continue; | |
| 172 | 268 |
| 173 std::map<std::string, KioskAppData*>::iterator old_it = old_apps.find(id); | 269 if (account_id == auto_login_account_id_) |
| 174 if (old_it != old_apps.end()) { | 270 auto_launch_app_id_ = kiosk_app_id; |
| 175 apps_.push_back(old_it->second); | 271 |
| 176 old_apps.erase(old_it); | 272 // TODO(mnissler): Support non-CWS update URLs. |
| 177 } else { | 273 |
| 178 KioskAppData* new_app = new KioskAppData(this, id); | 274 std::map<std::string, KioskAppData*>::iterator old_it = |
| 179 apps_.push_back(new_app); // Takes ownership of |new_app|. | 275 old_apps.find(kiosk_app_id); |
| 180 new_app->Load(); | 276 if (old_it != old_apps.end()) { |
| 277 apps_.push_back(old_it->second); | |
| 278 old_apps.erase(old_it); | |
| 279 } else { | |
| 280 KioskAppData* new_app = new KioskAppData(this, kiosk_app_id); | |
| 281 apps_.push_back(new_app); // Takes ownership of |new_app|. | |
| 282 new_app->Load(); | |
| 283 } | |
| 181 } | 284 } |
| 182 } | 285 } |
| 183 | 286 |
| 184 // Clears cache and deletes the remaining old data. | 287 // Clears cache and deletes the remaining old data. |
| 185 for (std::map<std::string, KioskAppData*>::iterator it = old_apps.begin(); | 288 for (std::map<std::string, KioskAppData*>::iterator it = old_apps.begin(); |
| 186 it != old_apps.end(); ++it) { | 289 it != old_apps.end(); ++it) { |
| 187 it->second->ClearCache(); | 290 it->second->ClearCache(); |
| 188 cryptohome::AsyncMethodCaller::GetInstance()->AsyncRemove( | 291 cryptohome::AsyncMethodCaller::GetInstance()->AsyncRemove( |
| 189 it->first, base::Bind(&OnRemoveAppCryptohomeComplete, it->first)); | 292 it->first, base::Bind(&OnRemoveAppCryptohomeComplete, it->first)); |
| 190 } | 293 } |
| 191 STLDeleteValues(&old_apps); | 294 STLDeleteValues(&old_apps); |
| 295 | |
| 296 FOR_EACH_OBSERVER(KioskAppManagerObserver, observers_, | |
| 297 OnKioskAppsListChanged()); | |
| 192 } | 298 } |
| 193 | 299 |
| 194 void KioskAppManager::Observe(int type, | 300 void KioskAppManager::Observe(int type, |
| 195 const content::NotificationSource& source, | 301 const content::NotificationSource& source, |
| 196 const content::NotificationDetails& details) { | 302 const content::NotificationDetails& details) { |
| 197 DCHECK_EQ(chrome::NOTIFICATION_SYSTEM_SETTING_CHANGED, type); | 303 DCHECK_EQ(chrome::NOTIFICATION_SYSTEM_SETTING_CHANGED, type); |
| 198 DCHECK_EQ(kKioskApps, | |
| 199 *content::Details<const std::string>(details).ptr()); | |
| 200 | |
| 201 UpdateAppData(); | 304 UpdateAppData(); |
| 202 } | 305 } |
| 203 | 306 |
| 204 void KioskAppManager::GetKioskAppIconCacheDir(base::FilePath* cache_dir) { | 307 void KioskAppManager::GetKioskAppIconCacheDir(base::FilePath* cache_dir) { |
| 205 base::FilePath user_data_dir; | 308 base::FilePath user_data_dir; |
| 206 CHECK(PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)); | 309 CHECK(PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)); |
| 207 *cache_dir = user_data_dir.AppendASCII(kIconCacheDir); | 310 *cache_dir = user_data_dir.AppendASCII(kIconCacheDir); |
| 208 } | 311 } |
| 209 | 312 |
| 210 void KioskAppManager::OnKioskAppDataChanged(const std::string& app_id) { | 313 void KioskAppManager::OnKioskAppDataChanged(const std::string& app_id) { |
| 211 FOR_EACH_OBSERVER(KioskAppManagerObserver, | 314 FOR_EACH_OBSERVER(KioskAppManagerObserver, |
| 212 observers_, | 315 observers_, |
| 213 OnKioskAppDataChanged(app_id)); | 316 OnKioskAppDataChanged(app_id)); |
| 214 } | 317 } |
| 215 | 318 |
| 216 void KioskAppManager::OnKioskAppDataLoadFailure(const std::string& app_id) { | 319 void KioskAppManager::OnKioskAppDataLoadFailure(const std::string& app_id) { |
| 217 FOR_EACH_OBSERVER(KioskAppManagerObserver, | 320 FOR_EACH_OBSERVER(KioskAppManagerObserver, |
| 218 observers_, | 321 observers_, |
| 219 OnKioskAppDataLoadFailure(app_id)); | 322 OnKioskAppDataLoadFailure(app_id)); |
| 220 RemoveApp(app_id); | 323 RemoveApp(app_id); |
| 221 } | 324 } |
| 222 | 325 |
| 223 } // namespace chromeos | 326 } // namespace chromeos |
| OLD | NEW |