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/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