Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / webui / chromeos / login / network_screen_handler.cc
index ff2625f..4881d5a 100644 (file)
@@ -4,19 +4,42 @@
 
 #include "chrome/browser/ui/webui/chromeos/login/network_screen_handler.h"
 
+#include <algorithm>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/memory/weak_ptr.h"
+#include "base/prefs/pref_registry_simple.h"
+#include "base/prefs/pref_service.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/sys_info.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
+#include "chrome/browser/chromeos/base/locale_util.h"
+#include "chrome/browser/chromeos/idle_detector.h"
 #include "chrome/browser/chromeos/input_method/input_method_util.h"
-#include "chrome/browser/chromeos/login/language_switch_menu.h"
+#include "chrome/browser/chromeos/login/input_events_blocker.h"
+#include "chrome/browser/chromeos/login/login_display_host.h"
+#include "chrome/browser/chromeos/login/login_display_host_impl.h"
 #include "chrome/browser/chromeos/login/screens/core_oobe_actor.h"
+#include "chrome/browser/chromeos/system/input_device_settings.h"
 #include "chrome/browser/chromeos/system/timezone_util.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
 #include "chrome/browser/ui/webui/options/chromeos/cros_language_options_handler.h"
-#include "chromeos/ime/input_method_manager.h"
+#include "chrome/common/pref_names.h"
+#include "chromeos/chromeos_switches.h"
+#include "chromeos/ime/extension_ime_util.h"
+#include "chromeos/network/network_handler.h"
+#include "chromeos/network/network_state_handler.h"
+#include "chromeos/network/shill_property_util.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/rect.h"
 #include "ui/views/layout/fill_layout.h"
 #include "ui/views/widget/widget.h"
@@ -31,6 +54,44 @@ const char kJsApiNetworkOnLanguageChanged[] = "networkOnLanguageChanged";
 const char kJsApiNetworkOnInputMethodChanged[] = "networkOnInputMethodChanged";
 const char kJsApiNetworkOnTimezoneChanged[] = "networkOnTimezoneChanged";
 
+const char kUSLayout[] = "xkb:us::eng";
+
+const int kDerelectDetectionTimeoutSeconds = 8 * 60 * 60;  // 8 hours.
+const int kDerelectIdleTimeoutSeconds = 5 * 60;  // 5 minutes.
+const int kOobeTimerUpdateIntervalSeconds = 5 * 60;  // 5 minutes.
+
+// Returns true if element was inserted.
+bool InsertString(const std::string& str, std::set<std::string>& to) {
+  const std::pair<std::set<std::string>::iterator, bool> result =
+      to.insert(str);
+  return result.second;
+}
+
+void AddOptgroupOtherLayouts(base::ListValue* input_methods_list) {
+  base::DictionaryValue* optgroup = new base::DictionaryValue;
+  optgroup->SetString(
+      "optionGroupName",
+      l10n_util::GetStringUTF16(IDS_OOBE_OTHER_KEYBOARD_LAYOUTS));
+  input_methods_list->Append(optgroup);
+}
+
+// For "UI Language" drop-down menu at OOBE screen we need to decide which
+// entry to mark "selected". If user has just selected "requested_locale",
+// but "loaded_locale" was actually loaded, we mark original user choice
+// "selected" only if loaded_locale is a backup for "requested_locale".
+std::string CalculateSelectedLanguage(const std::string& requested_locale,
+                                      const std::string& loaded_locale) {
+
+  std::string resolved_locale;
+  if (!l10n_util::CheckAndResolveLocale(requested_locale, &resolved_locale))
+    return loaded_locale;
+
+  if (resolved_locale == loaded_locale)
+    return requested_locale;
+
+  return loaded_locale;
+}
+
 }  // namespace
 
 namespace chromeos {
@@ -42,13 +103,26 @@ NetworkScreenHandler::NetworkScreenHandler(CoreOobeActor* core_oobe_actor)
       screen_(NULL),
       core_oobe_actor_(core_oobe_actor),
       is_continue_enabled_(false),
-      show_on_init_(false) {
+      show_on_init_(false),
+      should_reinitialize_language_keyboard_list_(false),
+      weak_ptr_factory_(this) {
   DCHECK(core_oobe_actor_);
+  SetupTimeouts();
+
+  input_method::InputMethodManager* manager =
+      input_method::InputMethodManager::Get();
+  manager->AddObserver(this);
+  manager->GetComponentExtensionIMEManager()->AddObserver(this);
 }
 
 NetworkScreenHandler::~NetworkScreenHandler() {
   if (screen_)
     screen_->OnActorDestroyed(this);
+
+  input_method::InputMethodManager* manager =
+      input_method::InputMethodManager::Get();
+  manager->RemoveObserver(this);
+  manager->GetComponentExtensionIMEManager()->RemoveObserver(this);
 }
 
 // NetworkScreenHandler, NetworkScreenActor implementation: --------------------
@@ -66,13 +140,51 @@ void NetworkScreenHandler::Show() {
     return;
   }
 
+  // Here we should handle default locales, for which we do not have UI
+  // resources. This would load fallback, but properly show "selected" locale
+  // in the UI.
+  if (selected_language_code_.empty()) {
+    const StartupCustomizationDocument* startup_manifest =
+        StartupCustomizationDocument::GetInstance();
+    HandleOnLanguageChanged(startup_manifest->initial_locale_default());
+  }
+
+  PrefService* prefs = g_browser_process->local_state();
+  if (prefs->GetBoolean(prefs::kFactoryResetRequested)) {
+    if (core_oobe_actor_)
+      core_oobe_actor_->ShowDeviceResetScreen();
+    return;
+  }
+
+  // Make sure all our network technologies are turned on. On OOBE, the user
+  // should be able to select any of the available networks on the device.
+  NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
+  handler->SetTechnologyEnabled(NetworkTypePattern::NonVirtual(),
+                                true,
+                                chromeos::network_handler::ErrorCallback());
   ShowScreen(OobeUI::kScreenOobeNetwork, NULL);
+
+  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableDemoMode))
+    return;
+  if (base::SysInfo::IsRunningOnChromeOS()) {
+    std::string track;
+    // We're running on an actual device; if we cannot find our release track
+    // value or if the track contains "testimage", don't start demo mode.
+    if (!base::SysInfo::GetLsbReleaseValue("CHROMEOS_RELEASE_TRACK", &track) ||
+        track.find("testimage") != std::string::npos)
+      return;
+  }
+
+  if (IsDerelict())
+    StartIdleDetection();
+  else
+    StartOobeTimer();
 }
 
 void NetworkScreenHandler::Hide() {
 }
 
-void NetworkScreenHandler::ShowError(const string16& message) {
+void NetworkScreenHandler::ShowError(const base::string16& message) {
   CallJS("showError", message);
 }
 
@@ -83,14 +195,7 @@ void NetworkScreenHandler::ClearErrors() {
 
 void NetworkScreenHandler::ShowConnectingStatus(
     bool connecting,
-    const string16& network_id) {
-  // string16 connecting_label =
-  //     l10n_util::GetStringFUTF16(IDS_NETWORK_SELECTION_CONNECTING,
-  //                                network_id);
-  // CallJS("cr.ui.Oobe.showConnectingStatus",
-  //        base::FundamentalValue(connecting),
-  //        base::StringValue(network_id),
-  //        base::StringValue(connecting_label_value));
+    const base::string16& network_id) {
 }
 
 void NetworkScreenHandler::EnableContinue(bool enabled) {
@@ -103,8 +208,14 @@ void NetworkScreenHandler::EnableContinue(bool enabled) {
 
 void NetworkScreenHandler::DeclareLocalizedValues(
     LocalizedValuesBuilder* builder) {
-  builder->Add("networkScreenGreeting", IDS_WELCOME_SCREEN_GREETING);
+  if (system::InputDeviceSettings::Get()->ForceKeyboardDrivenUINavigation())
+    builder->Add("networkScreenGreeting", IDS_REMORA_CONFIRM_MESSAGE);
+  else
+    builder->Add("networkScreenGreeting", IDS_WELCOME_SCREEN_GREETING);
+
   builder->Add("networkScreenTitle", IDS_WELCOME_SCREEN_TITLE);
+  builder->Add("networkScreenAccessibleTitle",
+               IDS_NETWORK_SCREEN_ACCESSIBLE_TITLE);
   builder->Add("selectLanguage", IDS_LANGUAGE_SELECTION_SELECT);
   builder->Add("selectKeyboard", IDS_KEYBOARD_SELECTION_SELECT);
   builder->Add("selectNetwork", IDS_NETWORK_SELECTION_SELECT);
@@ -127,6 +238,11 @@ void NetworkScreenHandler::Initialize() {
     Show();
   }
 
+  if (should_reinitialize_language_keyboard_list_) {
+    should_reinitialize_language_keyboard_list_ = false;
+    ReloadLocalizedContent();
+  }
+
   timezone_subscription_ = CrosSettings::Get()->AddSettingsObserver(
       kSystemTimezone,
       base::Bind(&NetworkScreenHandler::OnSystemTimezoneChanged,
@@ -146,29 +262,76 @@ void NetworkScreenHandler::RegisterMessages() {
               &NetworkScreenHandler::HandleOnTimezoneChanged);
 }
 
+
+// static
+void NetworkScreenHandler::RegisterPrefs(PrefRegistrySimple* registry) {
+  registry->RegisterInt64Pref(prefs::kTimeOnOobe, 0);
+}
+
 // NetworkScreenHandler, private: ----------------------------------------------
 
 void NetworkScreenHandler::HandleOnExit() {
+  idle_detector_.reset();
   ClearErrors();
   if (screen_)
     screen_->OnContinuePressed();
 }
 
+struct NetworkScreenHandlerOnLanguageChangedCallbackData {
+  explicit NetworkScreenHandlerOnLanguageChangedCallbackData(
+      base::WeakPtr<NetworkScreenHandler>& handler)
+      : handler_(handler) {}
+
+  base::WeakPtr<NetworkScreenHandler> handler_;
+
+  // Block UI while resource bundle is being reloaded.
+  chromeos::InputEventsBlocker input_events_blocker;
+};
+
+// static
+void NetworkScreenHandler::OnLanguageChangedCallback(
+    scoped_ptr<NetworkScreenHandlerOnLanguageChangedCallbackData> context,
+    const std::string& requested_locale,
+    const std::string& loaded_locale,
+    const bool success) {
+  if (!context or !context->handler_)
+    return;
+
+  NetworkScreenHandler* const self = context->handler_.get();
+
+  if (success) {
+    if (requested_locale == loaded_locale) {
+      self->selected_language_code_ = requested_locale;
+    } else {
+      self->selected_language_code_ =
+          CalculateSelectedLanguage(requested_locale, loaded_locale);
+    }
+  } else {
+    self->selected_language_code_ = loaded_locale;
+  }
+
+  self->ReloadLocalizedContent();
+
+  AccessibilityManager::Get()->OnLocaleChanged();
+}
+
 void NetworkScreenHandler::HandleOnLanguageChanged(const std::string& locale) {
   const std::string app_locale = g_browser_process->GetApplicationLocale();
   if (app_locale == locale)
     return;
 
-  // TODO(altimofeev): make language change async.
-  LanguageSwitchMenu::SwitchLanguageAndEnableKeyboardLayouts(locale);
-
-  DictionaryValue localized_strings;
-  static_cast<OobeUI*>(web_ui()->GetController())->GetLocalizedStrings(
-      &localized_strings);
-  core_oobe_actor_->ReloadContent(localized_strings);
-
-  // Buttons are recreated, updated "Continue" button state.
-  EnableContinue(is_continue_enabled_);
+  base::WeakPtr<NetworkScreenHandler> weak_self =
+      weak_ptr_factory_.GetWeakPtr();
+  scoped_ptr<NetworkScreenHandlerOnLanguageChangedCallbackData> callback_data(
+      new NetworkScreenHandlerOnLanguageChangedCallbackData(weak_self));
+  scoped_ptr<locale_util::SwitchLanguageCallback> callback(
+      new locale_util::SwitchLanguageCallback(
+          base::Bind(&NetworkScreenHandler::OnLanguageChangedCallback,
+                     base::Passed(callback_data.Pass()))));
+  locale_util::SwitchLanguage(locale,
+                              true /* enableLocaleKeyboardLayouts */,
+                              true /* login_layouts_only */,
+                              callback.Pass());
 }
 
 void NetworkScreenHandler::HandleOnInputMethodChanged(const std::string& id) {
@@ -191,18 +354,107 @@ void NetworkScreenHandler::OnSystemTimezoneChanged() {
   CallJS("setTimezone", current_timezone_id);
 }
 
-// static
-ListValue* NetworkScreenHandler::GetLanguageList() {
+void NetworkScreenHandler::StartIdleDetection() {
+  if (!idle_detector_.get()) {
+    idle_detector_.reset(
+        new IdleDetector(base::Closure(),
+                         base::Bind(&NetworkScreenHandler::OnIdle,
+                                    weak_ptr_factory_.GetWeakPtr())));
+  }
+  idle_detector_->Start(derelict_idle_timeout_);
+}
+
+void NetworkScreenHandler::StartOobeTimer() {
+  oobe_timer_.Start(FROM_HERE,
+                    oobe_timer_update_interval_,
+                    this,
+                    &NetworkScreenHandler::OnOobeTimerUpdate);
+}
+
+void NetworkScreenHandler::OnIdle() {
+  LoginDisplayHost* host = LoginDisplayHostImpl::default_host();
+  host->StartDemoAppLaunch();
+}
+
+void NetworkScreenHandler::OnOobeTimerUpdate() {
+  time_on_oobe_ += oobe_timer_update_interval_;
+
+  PrefService* prefs = g_browser_process->local_state();
+  prefs->SetInt64(prefs::kTimeOnOobe, time_on_oobe_.InSeconds());
+
+  if (IsDerelict()) {
+    oobe_timer_.Stop();
+    StartIdleDetection();
+  }
+}
+
+void NetworkScreenHandler::SetupTimeouts() {
+  CommandLine* cmdline = CommandLine::ForCurrentProcess();
+  DCHECK(cmdline);
+
+  PrefService* prefs = g_browser_process->local_state();
+  time_on_oobe_ =
+      base::TimeDelta::FromSeconds(prefs->GetInt64(prefs::kTimeOnOobe));
+
+  int derelict_detection_timeout;
+  if (!cmdline->HasSwitch(switches::kDerelictDetectionTimeout) ||
+      !base::StringToInt(
+          cmdline->GetSwitchValueASCII(switches::kDerelictDetectionTimeout),
+          &derelict_detection_timeout)) {
+    derelict_detection_timeout = kDerelectDetectionTimeoutSeconds;
+  }
+  derelict_detection_timeout_ =
+      base::TimeDelta::FromSeconds(derelict_detection_timeout);
+
+  int derelict_idle_timeout;
+  if (!cmdline->HasSwitch(switches::kDerelictIdleTimeout) ||
+      !base::StringToInt(
+          cmdline->GetSwitchValueASCII(switches::kDerelictIdleTimeout),
+          &derelict_idle_timeout)) {
+    derelict_idle_timeout = kDerelectIdleTimeoutSeconds;
+  }
+  derelict_idle_timeout_ = base::TimeDelta::FromSeconds(derelict_idle_timeout);
+
+
+  int oobe_timer_update_interval;
+  if (!cmdline->HasSwitch(switches::kOobeTimerInterval) ||
+      !base::StringToInt(
+          cmdline->GetSwitchValueASCII(switches::kOobeTimerInterval),
+          &oobe_timer_update_interval)) {
+    oobe_timer_update_interval = kOobeTimerUpdateIntervalSeconds;
+  }
+  oobe_timer_update_interval_ =
+      base::TimeDelta::FromSeconds(oobe_timer_update_interval);
+
+  // In case we'd be derelict before our timer is set to trigger, reduce
+  // the interval so we check again when we're scheduled to go derelict.
+  oobe_timer_update_interval_ =
+      std::max(std::min(oobe_timer_update_interval_,
+                        derelict_detection_timeout_ - time_on_oobe_),
+               base::TimeDelta::FromSeconds(0));
+}
+
+bool NetworkScreenHandler::IsDerelict() {
+  return time_on_oobe_ >= derelict_detection_timeout_;
+}
+
+base::ListValue* NetworkScreenHandler::GetLanguageList() {
   const std::string app_locale = g_browser_process->GetApplicationLocale();
   input_method::InputMethodManager* manager =
       input_method::InputMethodManager::Get();
-  // GetSupportedInputMethods() never returns NULL.
-  scoped_ptr<input_method::InputMethodDescriptors> descriptors(
-      manager->GetSupportedInputMethods());
-  ListValue* languages_list =
-      options::CrosLanguageOptionsHandler::GetUILanguageList(*descriptors);
+  ComponentExtensionIMEManager* comp_manager =
+      manager->GetComponentExtensionIMEManager();
+  input_method::InputMethodDescriptors descriptors;
+  if (extension_ime_util::UseWrappedExtensionKeyboardLayouts()) {
+    if (comp_manager->IsInitialized())
+      descriptors = comp_manager->GetXkbIMEAsInputMethodDescriptor();
+  } else {
+    descriptors = *(manager->GetSupportedInputMethods());
+  }
+  base::ListValue* languages_list =
+      options::CrosLanguageOptionsHandler::GetUILanguageList(descriptors);
   for (size_t i = 0; i < languages_list->GetSize(); ++i) {
-    DictionaryValue* language_info = NULL;
+    base::DictionaryValue* language_info = NULL;
     if (!languages_list->GetDictionary(i, &language_info))
       NOTREACHED();
 
@@ -213,37 +465,138 @@ ListValue* NetworkScreenHandler::GetLanguageList() {
     std::string native_name;
     language_info->GetString("nativeDisplayName", &native_name);
 
-    if (display_name != native_name)
+    // If it's option group divider, add field name.
+    if (value == options::kVendorOtherLanguagesListDivider) {
+      language_info->SetString(
+          "optionGroupName",
+          l10n_util::GetStringUTF16(IDS_OOBE_OTHER_LANGUAGES));
+    }
+    if (display_name != native_name) {
       display_name = base::StringPrintf("%s - %s",
                                         display_name.c_str(),
                                         native_name.c_str());
+    }
 
     language_info->SetString("value", value);
     language_info->SetString("title", display_name);
-    language_info->SetBoolean("selected", value == app_locale);
+    if (selected_language_code_.empty()) {
+      if (value == app_locale)
+        language_info->SetBoolean("selected", true);
+    } else {
+      if (value == selected_language_code_)
+        language_info->SetBoolean("selected", true);
+    }
   }
   return languages_list;
 }
 
+base::DictionaryValue* CreateInputMethodsEntry(
+    const input_method::InputMethodDescriptor& method,
+    const std::string current_input_method_id) {
+  input_method::InputMethodUtil* util =
+      input_method::InputMethodManager::Get()->GetInputMethodUtil();
+  const std::string& ime_id = method.id();
+  scoped_ptr<base::DictionaryValue> input_method(new base::DictionaryValue);
+  input_method->SetString("value", ime_id);
+  input_method->SetString("title", util->GetInputMethodLongName(method));
+  input_method->SetBoolean("selected", ime_id == current_input_method_id);
+  return input_method.release();
+}
+
+void NetworkScreenHandler::OnImeComponentExtensionInitialized() {
+  // Refreshes the language and keyboard list once the component extension
+  // IMEs are initialized.
+  if (page_is_ready())
+    ReloadLocalizedContent();
+  else
+    should_reinitialize_language_keyboard_list_ = true;
+}
+
+void NetworkScreenHandler::InputMethodChanged(
+    input_method::InputMethodManager* manager, bool show_message) {
+  CallJS("setInputMethod", manager->GetCurrentInputMethod().id());
+}
+
+void NetworkScreenHandler::ReloadLocalizedContent() {
+  base::DictionaryValue localized_strings;
+  static_cast<OobeUI*>(web_ui()->GetController())
+      ->GetLocalizedStrings(&localized_strings);
+  core_oobe_actor_->ReloadContent(localized_strings);
+
+  // Buttons are recreated, updated "Continue" button state.
+  EnableContinue(is_continue_enabled_);
+}
+
 // static
-ListValue* NetworkScreenHandler::GetInputMethods() {
-  ListValue* input_methods_list = new ListValue;
+base::ListValue* NetworkScreenHandler::GetInputMethods() {
+  base::ListValue* input_methods_list = new base::ListValue;
   input_method::InputMethodManager* manager =
       input_method::InputMethodManager::Get();
   input_method::InputMethodUtil* util = manager->GetInputMethodUtil();
+  if (extension_ime_util::UseWrappedExtensionKeyboardLayouts()) {
+    ComponentExtensionIMEManager* comp_manager =
+        manager->GetComponentExtensionIMEManager();
+    if (!comp_manager->IsInitialized()) {
+      input_method::InputMethodDescriptor fallback =
+          util->GetFallbackInputMethodDescriptor();
+      input_methods_list->Append(
+          CreateInputMethodsEntry(fallback, fallback.id()));
+      return input_methods_list;
+    }
+  }
+
+  const std::vector<std::string>& hardware_login_input_methods =
+      util->GetHardwareLoginInputMethodIds();
+  manager->EnableLoginLayouts(g_browser_process->GetApplicationLocale(),
+                              hardware_login_input_methods);
+
   scoped_ptr<input_method::InputMethodDescriptors> input_methods(
       manager->GetActiveInputMethods());
-  std::string current_input_method_id = manager->GetCurrentInputMethod().id();
+  const std::string& current_input_method_id =
+      manager->GetCurrentInputMethod().id();
+  std::set<std::string> input_methods_added;
+
+  for (std::vector<std::string>::const_iterator i =
+           hardware_login_input_methods.begin();
+       i != hardware_login_input_methods.end();
+       ++i) {
+    const input_method::InputMethodDescriptor* ime =
+        util->GetInputMethodDescriptorFromId(*i);
+    DCHECK(ime != NULL);
+    // Do not crash in case of misconfiguration.
+    if (ime != NULL) {
+      input_methods_added.insert(*i);
+      input_methods_list->Append(
+          CreateInputMethodsEntry(*ime, current_input_method_id));
+    }
+  }
+
+  bool optgroup_added = false;
   for (size_t i = 0; i < input_methods->size(); ++i) {
-    const std::string ime_id = input_methods->at(i).id();
-    DictionaryValue* input_method = new DictionaryValue;
-    input_method->SetString("value", ime_id);
-    input_method->SetString(
-        "title",
-        util->GetInputMethodLongName(input_methods->at(i)));
-    input_method->SetBoolean("selected",
-        ime_id == current_input_method_id);
-    input_methods_list->Append(input_method);
+    // Makes sure the id is in legacy xkb id format.
+    const std::string& ime_id = (*input_methods)[i].id();
+    if (!InsertString(ime_id, input_methods_added))
+      continue;
+    if (!optgroup_added) {
+      optgroup_added = true;
+      AddOptgroupOtherLayouts(input_methods_list);
+    }
+    input_methods_list->Append(
+        CreateInputMethodsEntry((*input_methods)[i], current_input_method_id));
+  }
+  // "xkb:us::eng" should always be in the list of available layouts.
+  const std::string& us_keyboard_id =
+      extension_ime_util::GetInputMethodIDByKeyboardLayout(kUSLayout);
+  if (input_methods_added.find(us_keyboard_id) == input_methods_added.end()) {
+    const input_method::InputMethodDescriptor* us_eng_descriptor =
+        util->GetInputMethodDescriptorFromId(us_keyboard_id);
+    DCHECK(us_eng_descriptor != NULL);
+    if (!optgroup_added) {
+      optgroup_added = true;
+      AddOptgroupOtherLayouts(input_methods_list);
+    }
+    input_methods_list->Append(
+        CreateInputMethodsEntry(*us_eng_descriptor, current_input_method_id));
   }
   return input_methods_list;
 }