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