1 // Copyright (c) 2012 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.
5 #include "chrome/browser/ui/webui/chromeos/login/network_screen_handler.h"
10 #include "base/bind_helpers.h"
11 #include "base/command_line.h"
12 #include "base/memory/weak_ptr.h"
13 #include "base/prefs/pref_registry_simple.h"
14 #include "base/prefs/pref_service.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/values.h"
19 #include "chrome/browser/browser_process.h"
20 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
21 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
22 #include "chrome/browser/chromeos/base/locale_util.h"
23 #include "chrome/browser/chromeos/idle_detector.h"
24 #include "chrome/browser/chromeos/input_method/input_method_util.h"
25 #include "chrome/browser/chromeos/login/input_events_blocker.h"
26 #include "chrome/browser/chromeos/login/login_display_host_impl.h"
27 #include "chrome/browser/chromeos/login/screens/core_oobe_actor.h"
28 #include "chrome/browser/chromeos/system/input_device_settings.h"
29 #include "chrome/browser/chromeos/system/timezone_util.h"
30 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
31 #include "chrome/browser/ui/webui/options/chromeos/cros_language_options_handler.h"
32 #include "chrome/common/pref_names.h"
33 #include "chromeos/chromeos_switches.h"
34 #include "chromeos/ime/extension_ime_util.h"
35 #include "chromeos/ime/input_method_manager.h"
36 #include "grit/chromium_strings.h"
37 #include "grit/generated_resources.h"
38 #include "ui/base/l10n/l10n_util.h"
39 #include "ui/gfx/rect.h"
40 #include "ui/views/layout/fill_layout.h"
41 #include "ui/views/widget/widget.h"
45 const char kJsScreenPath
[] = "login.NetworkScreen";
47 // JS API callbacks names.
48 const char kJsApiNetworkOnExit
[] = "networkOnExit";
49 const char kJsApiNetworkOnLanguageChanged
[] = "networkOnLanguageChanged";
50 const char kJsApiNetworkOnInputMethodChanged
[] = "networkOnInputMethodChanged";
51 const char kJsApiNetworkOnTimezoneChanged
[] = "networkOnTimezoneChanged";
53 const char kUSLayout
[] = "xkb:us::eng";
55 const int kDerelectDetectionTimeoutSeconds
= 8 * 60 * 60; // 8 hours.
56 const int kDerelectIdleTimeoutSeconds
= 5 * 60; // 5 minutes.
57 const int kOobeTimerUpdateIntervalSeconds
= 5 * 60; // 5 minutes.
59 // Returns true if element was inserted.
60 bool InsertString(const std::string
& str
, std::set
<std::string
>& to
) {
61 const std::pair
<std::set
<std::string
>::iterator
, bool> result
=
66 void AddOptgroupOtherLayouts(base::ListValue
* input_methods_list
) {
67 base::DictionaryValue
* optgroup
= new base::DictionaryValue
;
70 l10n_util::GetStringUTF16(IDS_OOBE_OTHER_KEYBOARD_LAYOUTS
));
71 input_methods_list
->Append(optgroup
);
78 // NetworkScreenHandler, public: -----------------------------------------------
80 NetworkScreenHandler::NetworkScreenHandler(CoreOobeActor
* core_oobe_actor
)
81 : BaseScreenHandler(kJsScreenPath
),
83 core_oobe_actor_(core_oobe_actor
),
84 is_continue_enabled_(false),
86 weak_ptr_factory_(this) {
87 DCHECK(core_oobe_actor_
);
90 input_method::InputMethodManager
* manager
=
91 input_method::InputMethodManager::Get();
92 manager
->SetInputMethodLoginDefault();
93 manager
->GetComponentExtensionIMEManager()->AddObserver(this);
96 NetworkScreenHandler::~NetworkScreenHandler() {
98 screen_
->OnActorDestroyed(this);
100 input_method::InputMethodManager::Get()
101 ->GetComponentExtensionIMEManager()
102 ->RemoveObserver(this);
105 // NetworkScreenHandler, NetworkScreenActor implementation: --------------------
107 void NetworkScreenHandler::SetDelegate(NetworkScreenActor::Delegate
* screen
) {
111 void NetworkScreenHandler::PrepareToShow() {
114 void NetworkScreenHandler::Show() {
115 if (!page_is_ready()) {
116 show_on_init_
= true;
120 ShowScreen(OobeUI::kScreenOobeNetwork
, NULL
);
122 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableDemoMode
))
126 StartIdleDetection();
131 void NetworkScreenHandler::Hide() {
134 void NetworkScreenHandler::ShowError(const base::string16
& message
) {
135 CallJS("showError", message
);
138 void NetworkScreenHandler::ClearErrors() {
140 core_oobe_actor_
->ClearErrors();
143 void NetworkScreenHandler::ShowConnectingStatus(
145 const base::string16
& network_id
) {
146 // base::string16 connecting_label =
147 // l10n_util::GetStringFUTF16(IDS_NETWORK_SELECTION_CONNECTING,
149 // CallJS("cr.ui.Oobe.showConnectingStatus",
150 // base::FundamentalValue(connecting),
151 // base::StringValue(network_id),
152 // base::StringValue(connecting_label_value));
155 void NetworkScreenHandler::EnableContinue(bool enabled
) {
156 is_continue_enabled_
= enabled
;
158 CallJS("enableContinueButton", enabled
);
161 // NetworkScreenHandler, BaseScreenHandler implementation: --------------------
163 void NetworkScreenHandler::DeclareLocalizedValues(
164 LocalizedValuesBuilder
* builder
) {
165 if (system::InputDeviceSettings::Get()->ForceKeyboardDrivenUINavigation())
166 builder
->Add("networkScreenGreeting", IDS_REMORA_CONFIRM_MESSAGE
);
168 builder
->Add("networkScreenGreeting", IDS_WELCOME_SCREEN_GREETING
);
170 builder
->Add("networkScreenTitle", IDS_WELCOME_SCREEN_TITLE
);
171 builder
->Add("selectLanguage", IDS_LANGUAGE_SELECTION_SELECT
);
172 builder
->Add("selectKeyboard", IDS_KEYBOARD_SELECTION_SELECT
);
173 builder
->Add("selectNetwork", IDS_NETWORK_SELECTION_SELECT
);
174 builder
->Add("selectTimezone", IDS_OPTIONS_SETTINGS_TIMEZONE_DESCRIPTION
);
175 builder
->Add("proxySettings", IDS_OPTIONS_PROXIES_CONFIGURE_BUTTON
);
176 builder
->Add("continueButton", IDS_NETWORK_SELECTION_CONTINUE_BUTTON
);
179 void NetworkScreenHandler::GetAdditionalParameters(
180 base::DictionaryValue
* dict
) {
181 dict
->Set("languageList", GetLanguageList());
182 dict
->Set("inputMethodsList", GetInputMethods());
183 dict
->Set("timezoneList", GetTimezoneList());
186 void NetworkScreenHandler::Initialize() {
187 EnableContinue(is_continue_enabled_
);
189 show_on_init_
= false;
193 timezone_subscription_
= CrosSettings::Get()->AddSettingsObserver(
195 base::Bind(&NetworkScreenHandler::OnSystemTimezoneChanged
,
196 base::Unretained(this)));
197 OnSystemTimezoneChanged();
200 // NetworkScreenHandler, WebUIMessageHandler implementation: -------------------
202 void NetworkScreenHandler::RegisterMessages() {
203 AddCallback(kJsApiNetworkOnExit
, &NetworkScreenHandler::HandleOnExit
);
204 AddCallback(kJsApiNetworkOnLanguageChanged
,
205 &NetworkScreenHandler::HandleOnLanguageChanged
);
206 AddCallback(kJsApiNetworkOnInputMethodChanged
,
207 &NetworkScreenHandler::HandleOnInputMethodChanged
);
208 AddCallback(kJsApiNetworkOnTimezoneChanged
,
209 &NetworkScreenHandler::HandleOnTimezoneChanged
);
214 void NetworkScreenHandler::RegisterPrefs(PrefRegistrySimple
* registry
) {
215 registry
->RegisterInt64Pref(prefs::kTimeOnOobe
, 0);
218 // NetworkScreenHandler, private: ----------------------------------------------
220 void NetworkScreenHandler::HandleOnExit() {
224 screen_
->OnContinuePressed();
227 struct NetworkScreenHandlerOnLanguageChangedCallbackData
{
228 explicit NetworkScreenHandlerOnLanguageChangedCallbackData(
229 base::WeakPtr
<NetworkScreenHandler
>& handler
)
230 : handler_(handler
) {}
232 base::WeakPtr
<NetworkScreenHandler
> handler_
;
234 // Block UI while resource bundle is being reloaded.
235 chromeos::InputEventsBlocker input_events_blocker
;
239 void NetworkScreenHandler::OnLanguageChangedCallback(
240 scoped_ptr
<NetworkScreenHandlerOnLanguageChangedCallbackData
> context
,
241 const std::string
& /*requested locale*/,
242 const std::string
& /*loaded_locale*/,
243 const bool /*success*/) {
244 if (!context
or !context
->handler_
)
247 NetworkScreenHandler
* const self
= context
->handler_
.get();
249 base::DictionaryValue localized_strings
;
250 static_cast<OobeUI
*>(self
->web_ui()->GetController())
251 ->GetLocalizedStrings(&localized_strings
);
252 self
->core_oobe_actor_
->ReloadContent(localized_strings
);
254 // Buttons are recreated, updated "Continue" button state.
255 self
->EnableContinue(self
->is_continue_enabled_
);
257 AccessibilityManager::Get()->OnLocaleChanged();
260 void NetworkScreenHandler::HandleOnLanguageChanged(const std::string
& locale
) {
261 const std::string app_locale
= g_browser_process
->GetApplicationLocale();
262 if (app_locale
== locale
)
265 base::WeakPtr
<NetworkScreenHandler
> weak_self
=
266 weak_ptr_factory_
.GetWeakPtr();
267 scoped_ptr
<NetworkScreenHandlerOnLanguageChangedCallbackData
> callback_data(
268 new NetworkScreenHandlerOnLanguageChangedCallbackData(weak_self
));
269 scoped_ptr
<locale_util::SwitchLanguageCallback
> callback(
270 new locale_util::SwitchLanguageCallback(
271 base::Bind(&NetworkScreenHandler::OnLanguageChangedCallback
,
272 base::Passed(callback_data
.Pass()))));
273 locale_util::SwitchLanguage(locale
,
274 true /* enableLocaleKeyboardLayouts */,
275 true /* login_layouts_only */,
279 void NetworkScreenHandler::HandleOnInputMethodChanged(const std::string
& id
) {
280 input_method::InputMethodManager::Get()->ChangeInputMethod(id
);
283 void NetworkScreenHandler::HandleOnTimezoneChanged(
284 const std::string
& timezone_id
) {
285 std::string current_timezone_id
;
286 CrosSettings::Get()->GetString(kSystemTimezone
, ¤t_timezone_id
);
287 if (current_timezone_id
== timezone_id
)
290 CrosSettings::Get()->SetString(kSystemTimezone
, timezone_id
);
293 void NetworkScreenHandler::OnSystemTimezoneChanged() {
294 std::string current_timezone_id
;
295 CrosSettings::Get()->GetString(kSystemTimezone
, ¤t_timezone_id
);
296 CallJS("setTimezone", current_timezone_id
);
299 void NetworkScreenHandler::StartIdleDetection() {
300 if (!detector_
.get()) {
302 new IdleDetector(base::Closure(),
303 base::Bind(&NetworkScreenHandler::OnIdle
,
304 weak_ptr_factory_
.GetWeakPtr())));
306 detector_
->Start(derelict_idle_timeout_
);
309 void NetworkScreenHandler::StartOobeTimer() {
310 oobe_timer_
.Start(FROM_HERE
,
311 oobe_timer_update_interval_
,
313 &NetworkScreenHandler::OnOobeTimerUpdate
);
316 void NetworkScreenHandler::OnIdle() {
317 LoginDisplayHost
* host
= LoginDisplayHostImpl::default_host();
318 host
->StartDemoAppLaunch();
321 void NetworkScreenHandler::OnOobeTimerUpdate() {
322 time_on_oobe_
+= oobe_timer_update_interval_
;
324 PrefService
* prefs
= g_browser_process
->local_state();
325 prefs
->SetInt64(prefs::kTimeOnOobe
, time_on_oobe_
.InSeconds());
329 StartIdleDetection();
333 void NetworkScreenHandler::SetupTimeouts() {
334 CommandLine
* cmdline
= CommandLine::ForCurrentProcess();
337 PrefService
* prefs
= g_browser_process
->local_state();
339 base::TimeDelta::FromSeconds(prefs
->GetInt64(prefs::kTimeOnOobe
));
341 int derelict_detection_timeout
;
342 if (!cmdline
->HasSwitch(switches::kDerelictDetectionTimeout
) ||
344 cmdline
->GetSwitchValueASCII(switches::kDerelictDetectionTimeout
),
345 &derelict_detection_timeout
)) {
346 derelict_detection_timeout
= kDerelectDetectionTimeoutSeconds
;
348 derelict_detection_timeout_
=
349 base::TimeDelta::FromSeconds(derelict_detection_timeout
);
351 int derelict_idle_timeout
;
352 if (!cmdline
->HasSwitch(switches::kDerelictIdleTimeout
) ||
354 cmdline
->GetSwitchValueASCII(switches::kDerelictIdleTimeout
),
355 &derelict_idle_timeout
)) {
356 derelict_idle_timeout
= kDerelectIdleTimeoutSeconds
;
358 derelict_idle_timeout_
= base::TimeDelta::FromSeconds(derelict_idle_timeout
);
361 int oobe_timer_update_interval
;
362 if (!cmdline
->HasSwitch(switches::kOobeTimerInterval
) ||
364 cmdline
->GetSwitchValueASCII(switches::kOobeTimerInterval
),
365 &oobe_timer_update_interval
)) {
366 oobe_timer_update_interval
= kOobeTimerUpdateIntervalSeconds
;
368 oobe_timer_update_interval_
=
369 base::TimeDelta::FromSeconds(oobe_timer_update_interval
);
371 // In case we'd be derelict before our timer is set to trigger, reduce
372 // the interval so we check again when we're scheduled to go derelict.
373 oobe_timer_update_interval_
=
374 std::max(std::min(oobe_timer_update_interval_
,
375 derelict_detection_timeout_
- time_on_oobe_
),
376 base::TimeDelta::FromSeconds(0));
379 bool NetworkScreenHandler::IsDerelict() {
380 return time_on_oobe_
>= derelict_detection_timeout_
;
384 base::ListValue
* NetworkScreenHandler::GetLanguageList() {
385 const std::string app_locale
= g_browser_process
->GetApplicationLocale();
386 input_method::InputMethodManager
* manager
=
387 input_method::InputMethodManager::Get();
388 ComponentExtensionIMEManager
* comp_manager
=
389 manager
->GetComponentExtensionIMEManager();
390 input_method::InputMethodDescriptors descriptors
;
391 if (extension_ime_util::UseWrappedExtensionKeyboardLayouts()) {
392 if (comp_manager
->IsInitialized())
393 descriptors
= comp_manager
->GetXkbIMEAsInputMethodDescriptor();
395 descriptors
= *(manager
->GetSupportedInputMethods());
397 base::ListValue
* languages_list
=
398 options::CrosLanguageOptionsHandler::GetUILanguageList(descriptors
);
399 for (size_t i
= 0; i
< languages_list
->GetSize(); ++i
) {
400 base::DictionaryValue
* language_info
= NULL
;
401 if (!languages_list
->GetDictionary(i
, &language_info
))
405 language_info
->GetString("code", &value
);
406 std::string display_name
;
407 language_info
->GetString("displayName", &display_name
);
408 std::string native_name
;
409 language_info
->GetString("nativeDisplayName", &native_name
);
411 // If it's option group divider, add field name.
412 if (value
== options::kVendorOtherLanguagesListDivider
) {
413 language_info
->SetString(
415 l10n_util::GetStringUTF16(IDS_OOBE_OTHER_LANGUAGES
));
417 if (display_name
!= native_name
) {
418 display_name
= base::StringPrintf("%s - %s",
419 display_name
.c_str(),
420 native_name
.c_str());
423 language_info
->SetString("value", value
);
424 language_info
->SetString("title", display_name
);
425 language_info
->SetBoolean("selected", value
== app_locale
);
427 return languages_list
;
430 base::DictionaryValue
* CreateInputMethodsEntry(
431 const input_method::InputMethodDescriptor
& method
,
432 const std::string current_input_method_id
) {
433 input_method::InputMethodUtil
* util
=
434 input_method::InputMethodManager::Get()->GetInputMethodUtil();
435 const std::string
& ime_id
= method
.id();
436 scoped_ptr
<base::DictionaryValue
> input_method(new base::DictionaryValue
);
437 input_method
->SetString("value", ime_id
);
438 input_method
->SetString("title", util
->GetInputMethodLongName(method
));
439 input_method
->SetBoolean("selected", ime_id
== current_input_method_id
);
440 return input_method
.release();
443 void NetworkScreenHandler::OnImeComponentExtensionInitialized() {
444 input_method::InputMethodManager::Get()->SetInputMethodLoginDefault();
446 // Refreshes the language and keyboard list once the component extension
447 // IMEs are initialized.
448 base::DictionaryValue localized_strings
;
449 static_cast<OobeUI
*>(this->web_ui()->GetController())
450 ->GetLocalizedStrings(&localized_strings
);
451 this->core_oobe_actor_
->ReloadContent(localized_strings
);
452 this->EnableContinue(this->is_continue_enabled_
);
456 base::ListValue
* NetworkScreenHandler::GetInputMethods() {
457 base::ListValue
* input_methods_list
= new base::ListValue
;
458 input_method::InputMethodManager
* manager
=
459 input_method::InputMethodManager::Get();
460 input_method::InputMethodUtil
* util
= manager
->GetInputMethodUtil();
461 if (extension_ime_util::UseWrappedExtensionKeyboardLayouts()) {
462 ComponentExtensionIMEManager
* comp_manager
=
463 manager
->GetComponentExtensionIMEManager();
464 if (!comp_manager
->IsInitialized()) {
465 input_method::InputMethodDescriptor fallback
=
466 util
->GetFallbackInputMethodDescriptor();
467 input_methods_list
->Append(
468 CreateInputMethodsEntry(fallback
, fallback
.id()));
469 return input_methods_list
;
473 scoped_ptr
<input_method::InputMethodDescriptors
> input_methods(
474 manager
->GetActiveInputMethods());
475 const std::string
& current_input_method_id
=
476 manager
->GetCurrentInputMethod().id();
477 const std::vector
<std::string
>& hardware_login_input_methods
=
478 util
->GetHardwareLoginInputMethodIds();
479 std::set
<std::string
> input_methods_added
;
481 for (std::vector
<std::string
>::const_iterator i
=
482 hardware_login_input_methods
.begin();
483 i
!= hardware_login_input_methods
.end();
485 const input_method::InputMethodDescriptor
* ime
=
486 util
->GetInputMethodDescriptorFromId(*i
);
488 // Do not crash in case of misconfiguration.
490 input_methods_added
.insert(*i
);
491 input_methods_list
->Append(
492 CreateInputMethodsEntry(*ime
, current_input_method_id
));
496 bool optgroup_added
= false;
497 for (size_t i
= 0; i
< input_methods
->size(); ++i
) {
498 // Makes sure the id is in legacy xkb id format.
499 const std::string
& ime_id
= (*input_methods
)[i
].id();
500 if (!InsertString(ime_id
, input_methods_added
))
502 if (!optgroup_added
) {
503 optgroup_added
= true;
504 AddOptgroupOtherLayouts(input_methods_list
);
506 input_methods_list
->Append(
507 CreateInputMethodsEntry((*input_methods
)[i
], current_input_method_id
));
509 // "xkb:us::eng" should always be in the list of available layouts.
510 const std::string
& us_keyboard_id
=
511 extension_ime_util::GetInputMethodIDByKeyboardLayout(kUSLayout
);
512 if (input_methods_added
.find(us_keyboard_id
) == input_methods_added
.end()) {
513 const input_method::InputMethodDescriptor
* us_eng_descriptor
=
514 util
->GetInputMethodDescriptorFromId(us_keyboard_id
);
515 DCHECK(us_eng_descriptor
!= NULL
);
516 if (!optgroup_added
) {
517 optgroup_added
= true;
518 AddOptgroupOtherLayouts(input_methods_list
);
520 input_methods_list
->Append(
521 CreateInputMethodsEntry(*us_eng_descriptor
, current_input_method_id
));
523 return input_methods_list
;
527 base::ListValue
* NetworkScreenHandler::GetTimezoneList() {
528 std::string current_timezone_id
;
529 CrosSettings::Get()->GetString(kSystemTimezone
, ¤t_timezone_id
);
531 scoped_ptr
<base::ListValue
> timezone_list(new base::ListValue
);
532 scoped_ptr
<base::ListValue
> timezones
= system::GetTimezoneList().Pass();
533 for (size_t i
= 0; i
< timezones
->GetSize(); ++i
) {
534 const base::ListValue
* timezone
= NULL
;
535 CHECK(timezones
->GetList(i
, &timezone
));
537 std::string timezone_id
;
538 CHECK(timezone
->GetString(0, &timezone_id
));
540 std::string timezone_name
;
541 CHECK(timezone
->GetString(1, &timezone_name
));
543 scoped_ptr
<base::DictionaryValue
> timezone_option(
544 new base::DictionaryValue
);
545 timezone_option
->SetString("value", timezone_id
);
546 timezone_option
->SetString("title", timezone_name
);
547 timezone_option
->SetBoolean("selected", timezone_id
== current_timezone_id
);
548 timezone_list
->Append(timezone_option
.release());
551 return timezone_list
.release();
554 } // namespace chromeos