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 3 // found in the LICENSE file. 4 5 #include "chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.h" 6 7 #include <algorithm> 8 #include <set> 9 #include <string> 10 #include <vector> 11 12 #include "base/bind.h" 13 #include "base/chromeos/chromeos_version.h" 14 #include "base/command_line.h" 15 #include "base/memory/scoped_ptr.h" 16 #include "base/values.h" 17 #include "chrome/browser/chromeos/login/user_manager.h" 18 #include "chrome/browser/chromeos/settings/cros_settings.h" 19 #include "chrome/browser/chromeos/settings/cros_settings_names.h" 20 #include "chrome/common/extensions/extension.h" 21 #include "chromeos/chromeos_switches.h" 22 #include "content/public/browser/web_ui.h" 23 #include "content/public/browser/web_ui_data_source.h" 24 #include "grit/chromium_strings.h" 25 #include "grit/generated_resources.h" 26 #include "ui/base/l10n/l10n_util.h" 27 #include "ui/webui/web_ui_util.h" 28 #include "url/gurl.h" 29 30 namespace chromeos { 31 32 namespace { 33 34 // Populates app info dictionary with |app_data|. 35 void PopulateAppDict(const KioskAppManager::App& app_data, 36 base::DictionaryValue* app_dict) { 37 std::string icon_url("chrome://theme/IDR_APP_DEFAULT_ICON"); 38 39 // TODO(xiyuan): Replace data url with a URLDataSource. 40 if (!app_data.icon.isNull()) 41 icon_url = webui::GetBitmapDataUrl(*app_data.icon.bitmap()); 42 43 app_dict->SetString("id", app_data.app_id); 44 app_dict->SetString("name", app_data.name); 45 app_dict->SetString("iconURL", icon_url); 46 app_dict->SetBoolean( 47 "autoLaunch", 48 KioskAppManager::Get()->GetAutoLaunchApp() == app_data.app_id && 49 (KioskAppManager::Get()->IsAutoLaunchEnabled() || 50 KioskAppManager::Get()->IsAutoLaunchRequested())); 51 app_dict->SetBoolean("isLoading", app_data.is_loading); 52 } 53 54 // Sanitize app id input value and extracts app id out of it. 55 // Returns false if an app id could not be derived out of the input. 56 bool ExtractsAppIdFromInput(const std::string& input, 57 std::string* app_id) { 58 if (extensions::Extension::IdIsValid(input)) { 59 *app_id = input; 60 return true; 61 } 62 63 GURL webstore_url = GURL(input); 64 if (!webstore_url.is_valid()) 65 return false; 66 67 GURL webstore_base_url = 68 GURL(extension_urls::GetWebstoreItemDetailURLPrefix()); 69 70 if (webstore_url.scheme() != webstore_base_url.scheme() || 71 webstore_url.host() != webstore_base_url.host() || 72 !StartsWithASCII( 73 webstore_url.path(), webstore_base_url.path(), true)) { 74 return false; 75 } 76 77 const std::string path = webstore_url.path(); 78 const size_t last_slash = path.rfind('/'); 79 if (last_slash == std::string::npos) 80 return false; 81 82 const std::string candidate_id = path.substr(last_slash + 1); 83 if (!extensions::Extension::IdIsValid(candidate_id)) 84 return false; 85 86 *app_id = candidate_id; 87 return true; 88 } 89 90 } // namespace 91 92 KioskAppsHandler::KioskAppsHandler() 93 : kiosk_app_manager_(KioskAppManager::Get()), 94 initialized_(false), 95 is_kiosk_enabled_(false), 96 weak_ptr_factory_(this) { 97 kiosk_app_manager_->AddObserver(this); 98 } 99 100 KioskAppsHandler::~KioskAppsHandler() { 101 kiosk_app_manager_->RemoveObserver(this); 102 } 103 104 void KioskAppsHandler::RegisterMessages() { 105 web_ui()->RegisterMessageCallback("initializeKioskAppSettings", 106 base::Bind(&KioskAppsHandler::HandleInitializeKioskAppSettings, 107 base::Unretained(this))); 108 web_ui()->RegisterMessageCallback("getKioskAppSettings", 109 base::Bind(&KioskAppsHandler::HandleGetKioskAppSettings, 110 base::Unretained(this))); 111 web_ui()->RegisterMessageCallback("addKioskApp", 112 base::Bind(&KioskAppsHandler::HandleAddKioskApp, 113 base::Unretained(this))); 114 web_ui()->RegisterMessageCallback("removeKioskApp", 115 base::Bind(&KioskAppsHandler::HandleRemoveKioskApp, 116 base::Unretained(this))); 117 web_ui()->RegisterMessageCallback("enableKioskAutoLaunch", 118 base::Bind(&KioskAppsHandler::HandleEnableKioskAutoLaunch, 119 base::Unretained(this))); 120 web_ui()->RegisterMessageCallback("disableKioskAutoLaunch", 121 base::Bind(&KioskAppsHandler::HandleDisableKioskAutoLaunch, 122 base::Unretained(this))); 123 web_ui()->RegisterMessageCallback("setDisableBailoutShortcut", 124 base::Bind(&KioskAppsHandler::HandleSetDisableBailoutShortcut, 125 base::Unretained(this))); 126 } 127 128 void KioskAppsHandler::GetLocalizedValues(content::WebUIDataSource* source) { 129 source->AddString( 130 "addKioskAppButton", 131 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ADD_KIOSK_APP_BUTTON)); 132 source->AddString( 133 "kioskOverlayTitle", 134 l10n_util::GetStringUTF16(IDS_OPTIONS_KIOSK_OVERLAY_TITLE)); 135 source->AddString( 136 "addKioskApp", 137 l10n_util::GetStringUTF16(IDS_OPTIONS_KIOSK_ADD_APP)); 138 source->AddString( 139 "kioskAppIdEditHint", 140 l10n_util::GetStringUTF16(IDS_OPTIONS_KIOSK_ADD_APP_HINT)); 141 source->AddString( 142 "enableAutoLaunchButton", 143 l10n_util::GetStringUTF16(IDS_OPTIONS_KIOSK_ENABLE_AUTO_LAUNCH)); 144 source->AddString( 145 "disableAutoLaunchButton", 146 l10n_util::GetStringUTF16(IDS_OPTIONS_KIOSK_DISABLE_AUTO_LAUNCH)); 147 source->AddString( 148 "autoLaunch", 149 l10n_util::GetStringUTF16(IDS_OPTIONS_KIOSK_AUTO_LAUNCH)); 150 source->AddString( 151 "invalidApp", 152 l10n_util::GetStringUTF16(IDS_OPTIONS_KIOSK_INVALID_APP)); 153 source->AddString( 154 "kioskDiableBailoutShortcutLabel", 155 l10n_util::GetStringUTF16( 156 IDS_OPTIONS_KIOSK_DISABLE_BAILOUT_SHORTCUT_LABEL)); 157 source->AddString( 158 "kioskDisableBailoutShortcutWarningBold", 159 l10n_util::GetStringUTF16( 160 IDS_OPTIONS_KIOSK_DISABLE_BAILOUT_SHORTCUT_WARNING_BOLD)); 161 const string16 product_os_name = 162 l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_OS_NAME); 163 source->AddString( 164 "kioskDisableBailoutShortcutWarning", 165 l10n_util::GetStringFUTF16( 166 IDS_OPTIONS_KIOSK_DISABLE_BAILOUT_SHORTCUT_WARNING_FORMAT, 167 product_os_name)); 168 source->AddString( 169 "kioskDisableBailoutShortcutConfirm", 170 l10n_util::GetStringUTF16(IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL)); 171 source->AddString( 172 "kioskDisableBailoutShortcutCancel", 173 l10n_util::GetStringUTF16(IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL)); 174 source->AddString("done", l10n_util::GetStringUTF16(IDS_DONE)); 175 } 176 177 void KioskAppsHandler::OnKioskAppDataChanged(const std::string& app_id) { 178 KioskAppManager::App app_data; 179 if (!kiosk_app_manager_->GetApp(app_id, &app_data)) 180 return; 181 182 base::DictionaryValue app_dict; 183 PopulateAppDict(app_data, &app_dict); 184 185 web_ui()->CallJavascriptFunction("extensions.KioskAppsOverlay.updateApp", 186 app_dict); 187 } 188 189 void KioskAppsHandler::OnKioskAppDataLoadFailure(const std::string& app_id) { 190 base::StringValue app_id_value(app_id); 191 web_ui()->CallJavascriptFunction("extensions.KioskAppsOverlay.showError", 192 app_id_value); 193 } 194 195 196 void KioskAppsHandler::OnGetConsumerKioskModeStatus( 197 chromeos::KioskAppManager::ConsumerKioskModeStatus status) { 198 initialized_ = true; 199 is_kiosk_enabled_ = 200 ((status == KioskAppManager::CONSUMER_KIOSK_MODE_ENABLED) && 201 chromeos::UserManager::Get()->IsCurrentUserOwner()) || 202 !base::chromeos::IsRunningOnChromeOS(); 203 204 if (is_kiosk_enabled_) { 205 base::FundamentalValue enabled(is_kiosk_enabled_); 206 web_ui()->CallJavascriptFunction("extensions.KioskAppsOverlay.enableKiosk", 207 enabled); 208 } 209 } 210 211 212 void KioskAppsHandler::OnKioskAppsSettingsChanged() { 213 SendKioskAppSettings(); 214 } 215 216 void KioskAppsHandler::SendKioskAppSettings() { 217 if (!initialized_ || !is_kiosk_enabled_) 218 return; 219 220 bool enable_bailout_shortcut; 221 if (!CrosSettings::Get()->GetBoolean( 222 kAccountsPrefDeviceLocalAccountAutoLoginBailoutEnabled, 223 &enable_bailout_shortcut)) { 224 enable_bailout_shortcut = true; 225 } 226 227 base::DictionaryValue settings; 228 settings.SetBoolean("disableBailout", !enable_bailout_shortcut); 229 230 KioskAppManager::Apps apps; 231 kiosk_app_manager_->GetApps(&apps); 232 233 scoped_ptr<base::ListValue> apps_list(new base::ListValue); 234 for (size_t i = 0; i < apps.size(); ++i) { 235 const KioskAppManager::App& app_data = apps[i]; 236 237 scoped_ptr<base::DictionaryValue> app_info(new base::DictionaryValue); 238 PopulateAppDict(app_data, app_info.get()); 239 apps_list->Append(app_info.release()); 240 } 241 settings.SetWithoutPathExpansion("apps", apps_list.release()); 242 243 web_ui()->CallJavascriptFunction("extensions.KioskAppsOverlay.setSettings", 244 settings); 245 } 246 247 void KioskAppsHandler::HandleInitializeKioskAppSettings( 248 const base::ListValue* args) { 249 KioskAppManager::Get()->GetConsumerKioskModeStatus( 250 base::Bind(&KioskAppsHandler::OnGetConsumerKioskModeStatus, 251 weak_ptr_factory_.GetWeakPtr())); 252 } 253 254 void KioskAppsHandler::HandleGetKioskAppSettings(const base::ListValue* args) { 255 SendKioskAppSettings(); 256 } 257 258 259 void KioskAppsHandler::HandleAddKioskApp(const base::ListValue* args) { 260 if (!initialized_ || !is_kiosk_enabled_) 261 return; 262 263 std::string input; 264 CHECK(args->GetString(0, &input)); 265 266 std::string app_id; 267 if (!ExtractsAppIdFromInput(input, &app_id)) { 268 OnKioskAppDataLoadFailure(input); 269 return; 270 } 271 272 kiosk_app_manager_->AddApp(app_id); 273 } 274 275 void KioskAppsHandler::HandleRemoveKioskApp(const base::ListValue* args) { 276 if (!initialized_ || !is_kiosk_enabled_) 277 return; 278 279 std::string app_id; 280 CHECK(args->GetString(0, &app_id)); 281 282 kiosk_app_manager_->RemoveApp(app_id); 283 } 284 285 void KioskAppsHandler::HandleEnableKioskAutoLaunch( 286 const base::ListValue* args) { 287 if (!initialized_ || !is_kiosk_enabled_) 288 return; 289 290 std::string app_id; 291 CHECK(args->GetString(0, &app_id)); 292 293 kiosk_app_manager_->SetAutoLaunchApp(app_id); 294 } 295 296 void KioskAppsHandler::HandleDisableKioskAutoLaunch( 297 const base::ListValue* args) { 298 if (!initialized_ || !is_kiosk_enabled_) 299 return; 300 301 std::string app_id; 302 CHECK(args->GetString(0, &app_id)); 303 304 std::string startup_app_id = kiosk_app_manager_->GetAutoLaunchApp(); 305 if (startup_app_id != app_id) 306 return; 307 308 kiosk_app_manager_->SetAutoLaunchApp(""); 309 } 310 311 void KioskAppsHandler::HandleSetDisableBailoutShortcut( 312 const base::ListValue* args) { 313 if (!initialized_ || !is_kiosk_enabled_) 314 return; 315 316 bool disable_bailout_shortcut; 317 CHECK(args->GetBoolean(0, &disable_bailout_shortcut)); 318 319 CrosSettings::Get()->SetBoolean( 320 kAccountsPrefDeviceLocalAccountAutoLoginBailoutEnabled, 321 !disable_bailout_shortcut); 322 } 323 324 } // namespace chromeos 325