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. 4 5 #include "chrome/browser/ui/webui/chromeos/login/network_screen_handler.h" 6 7 #include "base/bind.h" 8 #include "base/bind_helpers.h" 9 #include "base/memory/weak_ptr.h" 10 #include "base/prefs/pref_service.h" 11 #include "base/strings/utf_string_conversions.h" 12 #include "base/values.h" 13 #include "chrome/browser/browser_process.h" 14 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h" 15 #include "chrome/browser/chromeos/base/locale_util.h" 16 #include "chrome/browser/chromeos/customization_document.h" 17 #include "chrome/browser/chromeos/idle_detector.h" 18 #include "chrome/browser/chromeos/login/screens/core_oobe_actor.h" 19 #include "chrome/browser/chromeos/login/ui/input_events_blocker.h" 20 #include "chrome/browser/chromeos/system/input_device_settings.h" 21 #include "chrome/browser/chromeos/system/timezone_util.h" 22 #include "chrome/browser/ui/webui/chromeos/login/l10n_util.h" 23 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" 24 #include "chrome/common/pref_names.h" 25 #include "chrome/grit/generated_resources.h" 26 #include "chromeos/ime/extension_ime_util.h" 27 #include "chromeos/network/network_handler.h" 28 #include "chromeos/network/network_state_handler.h" 29 #include "ui/base/l10n/l10n_util.h" 30 #include "ui/gfx/rect.h" 31 #include "ui/views/layout/fill_layout.h" 32 #include "ui/views/widget/widget.h" 33 34 namespace { 35 36 const char kJsScreenPath[] = "login.NetworkScreen"; 37 38 // JS API callbacks names. 39 const char kJsApiNetworkOnExit[] = "networkOnExit"; 40 const char kJsApiNetworkOnLanguageChanged[] = "networkOnLanguageChanged"; 41 const char kJsApiNetworkOnInputMethodChanged[] = "networkOnInputMethodChanged"; 42 const char kJsApiNetworkOnTimezoneChanged[] = "networkOnTimezoneChanged"; 43 44 // For "UI Language" drop-down menu at OOBE screen we need to decide which 45 // entry to mark "selected". If user has just selected "requested_locale", 46 // but "loaded_locale" was actually loaded, we mark original user choice 47 // "selected" only if loaded_locale is a backup for "requested_locale". 48 std::string CalculateSelectedLanguage(const std::string& requested_locale, 49 const std::string& loaded_locale) { 50 std::string resolved_locale; 51 if (!l10n_util::CheckAndResolveLocale(requested_locale, &resolved_locale)) 52 return loaded_locale; 53 54 if (resolved_locale == loaded_locale) 55 return requested_locale; 56 57 return loaded_locale; 58 } 59 60 } // namespace 61 62 namespace chromeos { 63 64 // NetworkScreenHandler, public: ----------------------------------------------- 65 66 NetworkScreenHandler::NetworkScreenHandler(CoreOobeActor* core_oobe_actor) 67 : BaseScreenHandler(kJsScreenPath), 68 screen_(NULL), 69 core_oobe_actor_(core_oobe_actor), 70 is_continue_enabled_(false), 71 show_on_init_(false), 72 weak_ptr_factory_(this) { 73 DCHECK(core_oobe_actor_); 74 75 input_method::InputMethodManager* manager = 76 input_method::InputMethodManager::Get(); 77 manager->AddObserver(this); 78 } 79 80 NetworkScreenHandler::~NetworkScreenHandler() { 81 if (screen_) 82 screen_->OnActorDestroyed(this); 83 84 input_method::InputMethodManager* manager = 85 input_method::InputMethodManager::Get(); 86 manager->RemoveObserver(this); 87 } 88 89 // NetworkScreenHandler, NetworkScreenActor implementation: -------------------- 90 91 void NetworkScreenHandler::SetDelegate(NetworkScreenActor::Delegate* screen) { 92 screen_ = screen; 93 } 94 95 void NetworkScreenHandler::PrepareToShow() { 96 } 97 98 void NetworkScreenHandler::Show() { 99 if (!page_is_ready()) { 100 show_on_init_ = true; 101 return; 102 } 103 104 // Here we should handle default locales, for which we do not have UI 105 // resources. This would load fallback, but properly show "selected" locale 106 // in the UI. 107 if (selected_language_code_.empty()) { 108 const StartupCustomizationDocument* startup_manifest = 109 StartupCustomizationDocument::GetInstance(); 110 HandleOnLanguageChanged(startup_manifest->initial_locale_default()); 111 } 112 113 PrefService* prefs = g_browser_process->local_state(); 114 if (prefs->GetBoolean(prefs::kFactoryResetRequested)) { 115 if (core_oobe_actor_) 116 core_oobe_actor_->ShowDeviceResetScreen(); 117 return; 118 } 119 120 // Make sure all our network technologies are turned on. On OOBE, the user 121 // should be able to select any of the available networks on the device. 122 NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); 123 handler->SetTechnologyEnabled(NetworkTypePattern::NonVirtual(), 124 true, 125 chromeos::network_handler::ErrorCallback()); 126 ShowScreen(OobeUI::kScreenOobeNetwork, NULL); 127 core_oobe_actor_->InitDemoModeDetection(); 128 } 129 130 void NetworkScreenHandler::Hide() { 131 } 132 133 void NetworkScreenHandler::ShowError(const base::string16& message) { 134 CallJS("showError", message); 135 } 136 137 void NetworkScreenHandler::ClearErrors() { 138 if (page_is_ready()) 139 core_oobe_actor_->ClearErrors(); 140 } 141 142 void NetworkScreenHandler::ShowConnectingStatus( 143 bool connecting, 144 const base::string16& network_id) { 145 } 146 147 void NetworkScreenHandler::EnableContinue(bool enabled) { 148 is_continue_enabled_ = enabled; 149 if (page_is_ready()) 150 CallJS("enableContinueButton", enabled); 151 } 152 153 // NetworkScreenHandler, BaseScreenHandler implementation: -------------------- 154 155 void NetworkScreenHandler::DeclareLocalizedValues( 156 LocalizedValuesBuilder* builder) { 157 if (system::InputDeviceSettings::Get()->ForceKeyboardDrivenUINavigation()) 158 builder->Add("networkScreenGreeting", IDS_REMORA_CONFIRM_MESSAGE); 159 else 160 builder->Add("networkScreenGreeting", IDS_WELCOME_SCREEN_GREETING); 161 162 builder->Add("networkScreenTitle", IDS_WELCOME_SCREEN_TITLE); 163 builder->Add("networkScreenAccessibleTitle", 164 IDS_NETWORK_SCREEN_ACCESSIBLE_TITLE); 165 builder->Add("selectLanguage", IDS_LANGUAGE_SELECTION_SELECT); 166 builder->Add("selectKeyboard", IDS_KEYBOARD_SELECTION_SELECT); 167 builder->Add("selectNetwork", IDS_NETWORK_SELECTION_SELECT); 168 builder->Add("selectTimezone", IDS_OPTIONS_SETTINGS_TIMEZONE_DESCRIPTION); 169 builder->Add("proxySettings", IDS_OPTIONS_PROXIES_CONFIGURE_BUTTON); 170 builder->Add("continueButton", IDS_NETWORK_SELECTION_CONTINUE_BUTTON); 171 } 172 173 void NetworkScreenHandler::GetAdditionalParameters( 174 base::DictionaryValue* dict) { 175 const std::string application_locale = 176 g_browser_process->GetApplicationLocale(); 177 const std::string selected_language = selected_language_code_.empty() ? 178 application_locale : selected_language_code_; 179 const std::string selected_input_method = 180 input_method::InputMethodManager::Get() 181 ->GetActiveIMEState() 182 ->GetCurrentInputMethod() 183 .id(); 184 185 dict->Set("languageList", 186 GetUILanguageList(NULL, selected_language).release()); 187 dict->Set("inputMethodsList", 188 GetAndActivateLoginKeyboardLayouts( 189 application_locale, selected_input_method).release()); 190 dict->Set("timezoneList", GetTimezoneList()); 191 } 192 193 void NetworkScreenHandler::Initialize() { 194 EnableContinue(is_continue_enabled_); 195 if (show_on_init_) { 196 show_on_init_ = false; 197 Show(); 198 } 199 200 timezone_subscription_ = CrosSettings::Get()->AddSettingsObserver( 201 kSystemTimezone, 202 base::Bind(&NetworkScreenHandler::OnSystemTimezoneChanged, 203 base::Unretained(this))); 204 OnSystemTimezoneChanged(); 205 } 206 207 // NetworkScreenHandler, WebUIMessageHandler implementation: ------------------- 208 209 void NetworkScreenHandler::RegisterMessages() { 210 AddCallback(kJsApiNetworkOnExit, &NetworkScreenHandler::HandleOnExit); 211 AddCallback(kJsApiNetworkOnLanguageChanged, 212 &NetworkScreenHandler::HandleOnLanguageChanged); 213 AddCallback(kJsApiNetworkOnInputMethodChanged, 214 &NetworkScreenHandler::HandleOnInputMethodChanged); 215 AddCallback(kJsApiNetworkOnTimezoneChanged, 216 &NetworkScreenHandler::HandleOnTimezoneChanged); 217 } 218 219 220 // NetworkScreenHandler, private: ---------------------------------------------- 221 222 void NetworkScreenHandler::HandleOnExit() { 223 core_oobe_actor_->StopDemoModeDetection(); 224 ClearErrors(); 225 if (screen_) 226 screen_->OnContinuePressed(); 227 } 228 229 struct NetworkScreenHandlerOnLanguageChangedCallbackData { 230 explicit NetworkScreenHandlerOnLanguageChangedCallbackData( 231 const base::WeakPtr<NetworkScreenHandler>& handler) 232 : handler(handler) {} 233 234 base::WeakPtr<NetworkScreenHandler> handler; 235 236 // Block UI while resource bundle is being reloaded. 237 chromeos::InputEventsBlocker input_events_blocker; 238 }; 239 240 // static 241 void NetworkScreenHandler::OnLanguageChangedCallback( 242 scoped_ptr<NetworkScreenHandlerOnLanguageChangedCallbackData> context, 243 const std::string& requested_locale, 244 const std::string& loaded_locale, 245 const bool success) { 246 if (!context || !context->handler) 247 return; 248 249 NetworkScreenHandler* const self = context->handler.get(); 250 251 if (success) { 252 if (requested_locale == loaded_locale) { 253 self->selected_language_code_ = requested_locale; 254 } else { 255 self->selected_language_code_ = 256 CalculateSelectedLanguage(requested_locale, loaded_locale); 257 } 258 } else { 259 self->selected_language_code_ = loaded_locale; 260 } 261 262 self->ReloadLocalizedContent(); 263 264 // We still do not have device owner, so owner settings are not applied. 265 // But Guest session can be started before owner is created, so we need to 266 // save locale settings directly here. 267 g_browser_process->local_state()->SetString(prefs::kApplicationLocale, 268 self->selected_language_code_); 269 270 AccessibilityManager::Get()->OnLocaleChanged(); 271 } 272 273 void NetworkScreenHandler::HandleOnLanguageChanged(const std::string& locale) { 274 const std::string app_locale = g_browser_process->GetApplicationLocale(); 275 if (app_locale == locale) 276 return; 277 278 base::WeakPtr<NetworkScreenHandler> weak_self = 279 weak_ptr_factory_.GetWeakPtr(); 280 scoped_ptr<NetworkScreenHandlerOnLanguageChangedCallbackData> callback_data( 281 new NetworkScreenHandlerOnLanguageChangedCallbackData(weak_self)); 282 scoped_ptr<locale_util::SwitchLanguageCallback> callback( 283 new locale_util::SwitchLanguageCallback( 284 base::Bind(&NetworkScreenHandler::OnLanguageChangedCallback, 285 base::Passed(callback_data.Pass())))); 286 locale_util::SwitchLanguage(locale, 287 true /* enableLocaleKeyboardLayouts */, 288 true /* login_layouts_only */, 289 callback.Pass()); 290 } 291 292 void NetworkScreenHandler::HandleOnInputMethodChanged(const std::string& id) { 293 input_method::InputMethodManager::Get() 294 ->GetActiveIMEState() 295 ->ChangeInputMethod(id, false /* show_message */); 296 } 297 298 void NetworkScreenHandler::HandleOnTimezoneChanged( 299 const std::string& timezone_id) { 300 std::string current_timezone_id; 301 CrosSettings::Get()->GetString(kSystemTimezone, ¤t_timezone_id); 302 if (current_timezone_id == timezone_id) 303 return; 304 305 CrosSettings::Get()->SetString(kSystemTimezone, timezone_id); 306 } 307 308 void NetworkScreenHandler::OnSystemTimezoneChanged() { 309 std::string current_timezone_id; 310 CrosSettings::Get()->GetString(kSystemTimezone, ¤t_timezone_id); 311 CallJS("setTimezone", current_timezone_id); 312 } 313 314 void NetworkScreenHandler::InputMethodChanged( 315 input_method::InputMethodManager* manager, bool show_message) { 316 CallJS("setInputMethod", 317 manager->GetActiveIMEState()->GetCurrentInputMethod().id()); 318 } 319 320 void NetworkScreenHandler::ReloadLocalizedContent() { 321 base::DictionaryValue localized_strings; 322 static_cast<OobeUI*>(web_ui()->GetController()) 323 ->GetLocalizedStrings(&localized_strings); 324 core_oobe_actor_->ReloadContent(localized_strings); 325 326 // Buttons are recreated, updated "Continue" button state. 327 EnableContinue(is_continue_enabled_); 328 } 329 330 // static 331 base::ListValue* NetworkScreenHandler::GetTimezoneList() { 332 std::string current_timezone_id; 333 CrosSettings::Get()->GetString(kSystemTimezone, ¤t_timezone_id); 334 335 scoped_ptr<base::ListValue> timezone_list(new base::ListValue); 336 scoped_ptr<base::ListValue> timezones = system::GetTimezoneList().Pass(); 337 for (size_t i = 0; i < timezones->GetSize(); ++i) { 338 const base::ListValue* timezone = NULL; 339 CHECK(timezones->GetList(i, &timezone)); 340 341 std::string timezone_id; 342 CHECK(timezone->GetString(0, &timezone_id)); 343 344 std::string timezone_name; 345 CHECK(timezone->GetString(1, &timezone_name)); 346 347 scoped_ptr<base::DictionaryValue> timezone_option( 348 new base::DictionaryValue); 349 timezone_option->SetString("value", timezone_id); 350 timezone_option->SetString("title", timezone_name); 351 timezone_option->SetBoolean("selected", timezone_id == current_timezone_id); 352 timezone_list->Append(timezone_option.release()); 353 } 354 355 return timezone_list.release(); 356 } 357 358 } // namespace chromeos 359