OLD | NEW |
| (Empty) |
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/chromeos/login/base_login_display_host.h" | |
6 | |
7 #include "ash/desktop_background/desktop_background_controller.h" | |
8 #include "ash/shell.h" | |
9 #include "ash/shell_window_ids.h" | |
10 #include "base/bind.h" | |
11 #include "base/command_line.h" | |
12 #include "base/debug/trace_event.h" | |
13 #include "base/file_util.h" | |
14 #include "base/logging.h" | |
15 #include "base/prefs/pref_service.h" | |
16 #include "base/threading/thread_restrictions.h" | |
17 #include "base/utf_string_conversions.h" | |
18 #include "chrome/browser/browser_process.h" | |
19 #include "chrome/browser/browser_shutdown.h" | |
20 #include "chrome/browser/chromeos/cros/cros_library.h" | |
21 #include "chrome/browser/chromeos/customization_document.h" | |
22 #include "chrome/browser/chromeos/input_method/input_method_configuration.h" | |
23 #include "chrome/browser/chromeos/input_method/input_method_manager.h" | |
24 #include "chrome/browser/chromeos/input_method/input_method_util.h" | |
25 #include "chrome/browser/chromeos/language_preferences.h" | |
26 #include "chrome/browser/chromeos/login/existing_user_controller.h" | |
27 #include "chrome/browser/chromeos/login/helper.h" | |
28 #include "chrome/browser/chromeos/login/language_switch_menu.h" | |
29 #include "chrome/browser/chromeos/login/login_utils.h" | |
30 #include "chrome/browser/chromeos/login/login_wizard.h" | |
31 #include "chrome/browser/chromeos/login/user_manager.h" | |
32 #include "chrome/browser/chromeos/login/webui_login_display_host.h" | |
33 #include "chrome/browser/chromeos/login/wizard_controller.h" | |
34 #include "chrome/browser/chromeos/mobile_config.h" | |
35 #include "chrome/browser/chromeos/policy/auto_enrollment_client.h" | |
36 #include "chrome/browser/chromeos/system/input_device_settings.h" | |
37 #include "chrome/browser/chromeos/system/timezone_settings.h" | |
38 #include "chrome/browser/lifetime/application_lifetime.h" | |
39 #include "chrome/browser/managed_mode/managed_mode.h" | |
40 #include "chrome/browser/policy/browser_policy_connector.h" | |
41 #include "chrome/common/chrome_notification_types.h" | |
42 #include "chrome/common/chrome_switches.h" | |
43 #include "chrome/common/pref_names.h" | |
44 #include "chromeos/dbus/dbus_thread_manager.h" | |
45 #include "chromeos/dbus/session_manager_client.h" | |
46 #include "content/public/browser/notification_service.h" | |
47 #include "content/public/browser/notification_types.h" | |
48 #include "googleurl/src/gurl.h" | |
49 #include "ui/aura/window.h" | |
50 #include "ui/base/events/event_utils.h" | |
51 #include "ui/base/resource/resource_bundle.h" | |
52 #include "ui/compositor/layer.h" | |
53 #include "ui/compositor/layer_animation_element.h" | |
54 #include "ui/compositor/layer_animation_sequence.h" | |
55 #include "ui/compositor/layer_animator.h" | |
56 #include "ui/compositor/scoped_layer_animation_settings.h" | |
57 #include "ui/gfx/rect.h" | |
58 #include "ui/gfx/transform.h" | |
59 #include "ui/views/widget/widget.h" | |
60 | |
61 namespace { | |
62 | |
63 // The delay of triggering initialization of the device policy subsystem | |
64 // after the login screen is initialized. This makes sure that device policy | |
65 // network requests are made while the system is idle waiting for user input. | |
66 const int64 kPolicyServiceInitializationDelayMilliseconds = 100; | |
67 | |
68 // Determines the hardware keyboard from the given locale code | |
69 // and the OEM layout information, and saves it to "Locale State". | |
70 // The information will be used in InputMethodUtil::GetHardwareInputMethodId(). | |
71 void DetermineAndSaveHardwareKeyboard(const std::string& locale, | |
72 const std::string& oem_layout) { | |
73 std::string layout; | |
74 if (!oem_layout.empty()) { | |
75 // If the OEM layout information is provided, use it. | |
76 layout = oem_layout; | |
77 } else { | |
78 chromeos::input_method::InputMethodManager* manager = | |
79 chromeos::input_method::GetInputMethodManager(); | |
80 // Otherwise, determine the hardware keyboard from the locale. | |
81 std::vector<std::string> input_method_ids; | |
82 if (manager->GetInputMethodUtil()->GetInputMethodIdsFromLanguageCode( | |
83 locale, | |
84 chromeos::input_method::kKeyboardLayoutsOnly, | |
85 &input_method_ids)) { | |
86 // The output list |input_method_ids| is sorted by popularity, hence | |
87 // input_method_ids[0] now contains the most popular keyboard layout | |
88 // for the given locale. | |
89 layout = input_method_ids[0]; | |
90 } | |
91 } | |
92 | |
93 if (!layout.empty()) { | |
94 PrefService* prefs = g_browser_process->local_state(); | |
95 prefs->SetString(prefs::kHardwareKeyboardLayout, layout); | |
96 // This asks the file thread to save the prefs (i.e. doesn't block). | |
97 // The latest values of Local State reside in memory so we can safely | |
98 // get the value of kHardwareKeyboardLayout even if the data is not | |
99 // yet saved to disk. | |
100 prefs->CommitPendingWrite(); | |
101 } | |
102 } | |
103 | |
104 ui::Layer* GetLayer(views::Widget* widget) { | |
105 return widget->GetNativeView()->layer(); | |
106 } | |
107 | |
108 } // namespace | |
109 | |
110 namespace chromeos { | |
111 | |
112 // static | |
113 LoginDisplayHost* BaseLoginDisplayHost::default_host_ = NULL; | |
114 | |
115 //////////////////////////////////////////////////////////////////////////////// | |
116 // BaseLoginDisplayHost, public | |
117 | |
118 BaseLoginDisplayHost::BaseLoginDisplayHost(const gfx::Rect& background_bounds) | |
119 : background_bounds_(background_bounds), | |
120 ALLOW_THIS_IN_INITIALIZER_LIST(pointer_factory_(this)), | |
121 shutting_down_(false), | |
122 oobe_progress_bar_visible_(false), | |
123 session_starting_(false) { | |
124 // We need to listen to CLOSE_ALL_BROWSERS_REQUEST but not APP_TERMINATIN | |
125 // because/ APP_TERMINATING will never be fired as long as this keeps | |
126 // ref-count. CLOSE_ALL_BROWSERS_REQUEST is safe here because there will be no | |
127 // browser instance that will block the shutdown. | |
128 registrar_.Add(this, | |
129 chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST, | |
130 content::NotificationService::AllSources()); | |
131 | |
132 // NOTIFICATION_BROWSER_OPENED is issued after browser is created, but | |
133 // not shown yet. Lock window has to be closed at this point so that | |
134 // a browser window exists and the window can acquire input focus. | |
135 registrar_.Add(this, | |
136 chrome::NOTIFICATION_BROWSER_OPENED, | |
137 content::NotificationService::AllSources()); | |
138 | |
139 // Login screen is moved to lock screen container when user logs in. | |
140 registrar_.Add(this, | |
141 chrome::NOTIFICATION_LOGIN_USER_CHANGED, | |
142 content::NotificationService::AllSources()); | |
143 | |
144 DCHECK(default_host_ == NULL); | |
145 default_host_ = this; | |
146 | |
147 // Make sure chrome won't exit while we are at login/oobe screen. | |
148 chrome::StartKeepAlive(); | |
149 } | |
150 | |
151 BaseLoginDisplayHost::~BaseLoginDisplayHost() { | |
152 // Let chrome process exit after login/oobe screen if needed. | |
153 chrome::EndKeepAlive(); | |
154 | |
155 default_host_ = NULL; | |
156 } | |
157 | |
158 //////////////////////////////////////////////////////////////////////////////// | |
159 // BaseLoginDisplayHost, LoginDisplayHost implementation: | |
160 | |
161 void BaseLoginDisplayHost::BeforeSessionStart() { | |
162 session_starting_ = true; | |
163 } | |
164 | |
165 void BaseLoginDisplayHost::OnSessionStart() { | |
166 DVLOG(1) << "Session starting"; | |
167 ash::Shell::GetInstance()-> | |
168 desktop_background_controller()->MoveDesktopToUnlockedContainer(); | |
169 if (wizard_controller_.get()) | |
170 wizard_controller_->OnSessionStart(); | |
171 // Display host is deleted once animation is completed | |
172 // since sign in screen widget has to stay alive. | |
173 StartAnimation(); | |
174 ShutdownDisplayHost(false); | |
175 } | |
176 | |
177 void BaseLoginDisplayHost::OnCompleteLogin() { | |
178 // Cancelling the |auto_enrollment_client_| now allows it to determine whether | |
179 // its protocol finished before login was complete. | |
180 if (auto_enrollment_client_.get()) | |
181 auto_enrollment_client_.release()->CancelAndDeleteSoon(); | |
182 } | |
183 | |
184 void BaseLoginDisplayHost::StartWizard( | |
185 const std::string& first_screen_name, | |
186 DictionaryValue* screen_parameters) { | |
187 DVLOG(1) << "Starting wizard, first_screen_name: " << first_screen_name; | |
188 // Create and show the wizard. | |
189 // Note, dtor of the old WizardController should be called before ctor of the | |
190 // new one, because "default_controller()" is updated there. So pure "reset()" | |
191 // is done before new controller creation. | |
192 wizard_controller_.reset(); | |
193 wizard_controller_.reset(CreateWizardController()); | |
194 | |
195 oobe_progress_bar_visible_ = !WizardController::IsDeviceRegistered(); | |
196 SetOobeProgressBarVisible(oobe_progress_bar_visible_); | |
197 wizard_controller_->Init(first_screen_name, screen_parameters); | |
198 } | |
199 | |
200 void BaseLoginDisplayHost::StartSignInScreen() { | |
201 DVLOG(1) << "Starting sign in screen"; | |
202 const chromeos::UserList& users = chromeos::UserManager::Get()->GetUsers(); | |
203 | |
204 // Fix for users who updated device and thus never passed register screen. | |
205 // If we already have users, we assume that it is not a second part of | |
206 // OOBE. See http://crosbug.com/6289 | |
207 if (!WizardController::IsDeviceRegistered() && !users.empty()) { | |
208 VLOG(1) << "Mark device registered because there are remembered users: " | |
209 << users.size(); | |
210 WizardController::MarkDeviceRegistered(); | |
211 } | |
212 | |
213 sign_in_controller_.reset(); // Only one controller in a time. | |
214 sign_in_controller_.reset(new chromeos::ExistingUserController(this)); | |
215 oobe_progress_bar_visible_ = !WizardController::IsDeviceRegistered(); | |
216 SetOobeProgressBarVisible(oobe_progress_bar_visible_); | |
217 SetStatusAreaVisible(true); | |
218 SetShutdownButtonEnabled(true); | |
219 sign_in_controller_->Init(users); | |
220 | |
221 // We might be here after a reboot that was triggered after OOBE was complete, | |
222 // so check for auto-enrollment again. This might catch a cached decision from | |
223 // a previous oobe flow, or might start a new check with the server. | |
224 CheckForAutoEnrollment(); | |
225 | |
226 // Initiate services customization manifest fetching. | |
227 ServicesCustomizationDocument::GetInstance()->StartFetching(); | |
228 | |
229 // Initiate mobile config load. | |
230 MobileConfig::GetInstance(); | |
231 | |
232 // Initiate device policy fetching. | |
233 g_browser_process->browser_policy_connector()->ScheduleServiceInitialization( | |
234 kPolicyServiceInitializationDelayMilliseconds); | |
235 } | |
236 | |
237 WizardController* BaseLoginDisplayHost::GetWizardController() { | |
238 return wizard_controller_.get(); | |
239 } | |
240 | |
241 void BaseLoginDisplayHost::ResumeSignInScreen() { | |
242 // We only get here after a previous call the StartSignInScreen. That sign-in | |
243 // was successful but was interrupted by an auto-enrollment execution; once | |
244 // auto-enrollment is complete we resume the normal login flow from here. | |
245 DVLOG(1) << "Resuming sign in screen"; | |
246 CHECK(sign_in_controller_.get()); | |
247 SetOobeProgressBarVisible(oobe_progress_bar_visible_); | |
248 SetStatusAreaVisible(true); | |
249 SetShutdownButtonEnabled(true); | |
250 sign_in_controller_->ResumeLogin(); | |
251 } | |
252 | |
253 void BaseLoginDisplayHost::CheckForAutoEnrollment() { | |
254 // This method is called when the controller determines that the | |
255 // auto-enrollment check can start. This happens either after the EULA is | |
256 // accepted, or right after a reboot if the EULA has already been accepted. | |
257 | |
258 if (policy::AutoEnrollmentClient::IsDisabled()) { | |
259 VLOG(1) << "CheckForAutoEnrollment: auto-enrollment disabled"; | |
260 return; | |
261 } | |
262 | |
263 // Start by checking if the device has already been owned. | |
264 pointer_factory_.InvalidateWeakPtrs(); | |
265 DeviceSettingsService::Get()->GetOwnershipStatusAsync( | |
266 base::Bind(&BaseLoginDisplayHost::OnOwnershipStatusCheckDone, | |
267 pointer_factory_.GetWeakPtr())); | |
268 } | |
269 | |
270 //////////////////////////////////////////////////////////////////////////////// | |
271 // BaseLoginDisplayHost, content:NotificationObserver implementation: | |
272 | |
273 void BaseLoginDisplayHost::Observe( | |
274 int type, | |
275 const content::NotificationSource& source, | |
276 const content::NotificationDetails& details) { | |
277 if (type == chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST) { | |
278 ShutdownDisplayHost(true); | |
279 } else if (type == chrome::NOTIFICATION_BROWSER_OPENED && session_starting_) { | |
280 // Browsers created before session start (windows opened by extensions, for | |
281 // example) are ignored. | |
282 OnBrowserCreated(); | |
283 registrar_.Remove(this, | |
284 chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST, | |
285 content::NotificationService::AllSources()); | |
286 registrar_.Remove(this, | |
287 chrome::NOTIFICATION_BROWSER_OPENED, | |
288 content::NotificationService::AllSources()); | |
289 } else if (type == chrome::NOTIFICATION_LOGIN_USER_CHANGED && | |
290 chromeos::UserManager::Get()->IsCurrentUserNew()) { | |
291 // For new user, move desktop to locker container so that windows created | |
292 // during the user image picker step are below it. | |
293 ash::Shell::GetInstance()-> | |
294 desktop_background_controller()->MoveDesktopToLockedContainer(); | |
295 registrar_.Remove(this, | |
296 chrome::NOTIFICATION_LOGIN_USER_CHANGED, | |
297 content::NotificationService::AllSources()); | |
298 } | |
299 } | |
300 | |
301 void BaseLoginDisplayHost::ShutdownDisplayHost(bool post_quit_task) { | |
302 if (shutting_down_) | |
303 return; | |
304 | |
305 shutting_down_ = true; | |
306 registrar_.RemoveAll(); | |
307 MessageLoop::current()->DeleteSoon(FROM_HERE, this); | |
308 if (post_quit_task) | |
309 MessageLoop::current()->Quit(); | |
310 } | |
311 | |
312 void BaseLoginDisplayHost::StartAnimation() { | |
313 if (ash::Shell::GetContainer( | |
314 ash::Shell::GetPrimaryRootWindow(), | |
315 ash::internal::kShellWindowId_DesktopBackgroundContainer)-> | |
316 children().empty()) { | |
317 // If there is no background window, don't perform any animation on the | |
318 // default and background layer because there is nothing behind it. | |
319 return; | |
320 } | |
321 | |
322 if (!CommandLine::ForCurrentProcess()->HasSwitch( | |
323 switches::kDisableLoginAnimations)) | |
324 ash::Shell::GetInstance()->DoInitialWorkspaceAnimation(); | |
325 } | |
326 | |
327 void BaseLoginDisplayHost::OnOwnershipStatusCheckDone( | |
328 DeviceSettingsService::OwnershipStatus status, | |
329 bool current_user_is_owner) { | |
330 if (status != DeviceSettingsService::OWNERSHIP_NONE) { | |
331 // The device is already owned. No need for auto-enrollment checks. | |
332 VLOG(1) << "CheckForAutoEnrollment: device already owned"; | |
333 return; | |
334 } | |
335 | |
336 // Kick off the auto-enrollment client. | |
337 if (auto_enrollment_client_.get()) { | |
338 // They client might have been started after the EULA screen, but we made | |
339 // it to the login screen before it finished. In that case let the current | |
340 // client proceed. | |
341 // | |
342 // CheckForAutoEnrollment() is also called when we reach the sign-in screen, | |
343 // because that's what happens after an auto-update. | |
344 VLOG(1) << "CheckForAutoEnrollment: client already started"; | |
345 | |
346 // If the client already started and already finished too, pass the decision | |
347 // to the |sign_in_controller_| now. | |
348 if (auto_enrollment_client_->should_auto_enroll()) | |
349 ForceAutoEnrollment(); | |
350 } else { | |
351 VLOG(1) << "CheckForAutoEnrollment: starting auto-enrollment client"; | |
352 auto_enrollment_client_.reset(policy::AutoEnrollmentClient::Create( | |
353 base::Bind(&BaseLoginDisplayHost::OnAutoEnrollmentClientDone, | |
354 base::Unretained(this)))); | |
355 auto_enrollment_client_->Start(); | |
356 } | |
357 } | |
358 | |
359 void BaseLoginDisplayHost::OnAutoEnrollmentClientDone() { | |
360 bool auto_enroll = auto_enrollment_client_->should_auto_enroll(); | |
361 VLOG(1) << "OnAutoEnrollmentClientDone, decision is " << auto_enroll; | |
362 | |
363 if (auto_enroll) | |
364 ForceAutoEnrollment(); | |
365 } | |
366 | |
367 void BaseLoginDisplayHost::ForceAutoEnrollment() { | |
368 if (sign_in_controller_.get()) | |
369 sign_in_controller_->DoAutoEnrollment(); | |
370 } | |
371 | |
372 // Declared in login_wizard.h so that others don't need to depend on our .h. | |
373 // TODO(nkostylev): Split this into a smaller functions. | |
374 void ShowLoginWizard(const std::string& first_screen_name, | |
375 const gfx::Size& size) { | |
376 if (browser_shutdown::IsTryingToQuit()) | |
377 return; | |
378 | |
379 // Managed mode is defined as a machine-level setting so we have to reset it | |
380 // each time login screen is shown. See also http://crbug.com/167642 | |
381 // TODO(nkostylev): Remove this call when managed mode scope is | |
382 // limited to user session. | |
383 if (ManagedMode::IsInManagedMode()) | |
384 ManagedMode::LeaveManagedMode(); | |
385 | |
386 VLOG(1) << "Showing OOBE screen: " << first_screen_name; | |
387 | |
388 chromeos::input_method::InputMethodManager* manager = | |
389 chromeos::input_method::GetInputMethodManager(); | |
390 | |
391 // Set up keyboards. For example, when |locale| is "en-US", enable US qwerty | |
392 // and US dvorak keyboard layouts. | |
393 if (g_browser_process && g_browser_process->local_state()) { | |
394 const std::string locale = g_browser_process->GetApplicationLocale(); | |
395 // If the preferred keyboard for the login screen has been saved, use it. | |
396 PrefService* prefs = g_browser_process->local_state(); | |
397 std::string initial_input_method_id = | |
398 prefs->GetString(chromeos::language_prefs::kPreferredKeyboardLayout); | |
399 if (initial_input_method_id.empty()) { | |
400 // If kPreferredKeyboardLayout is not specified, use the hardware layout. | |
401 initial_input_method_id = | |
402 manager->GetInputMethodUtil()->GetHardwareInputMethodId(); | |
403 } | |
404 manager->EnableLayouts(locale, initial_input_method_id); | |
405 | |
406 // Apply owner preferences for tap-to-click and mouse buttons swap for | |
407 // login screen. | |
408 system::mouse_settings::SetPrimaryButtonRight( | |
409 prefs->GetBoolean(prefs::kOwnerPrimaryMouseButtonRight)); | |
410 system::touchpad_settings::SetTapToClick( | |
411 prefs->GetBoolean(prefs::kOwnerTapToClickEnabled)); | |
412 } | |
413 | |
414 ui::SetNaturalScroll(CommandLine::ForCurrentProcess()->HasSwitch( | |
415 switches::kNaturalScrollDefault)); | |
416 | |
417 gfx::Rect screen_bounds(chromeos::CalculateScreenBounds(size)); | |
418 | |
419 // Check whether we need to execute OOBE process. | |
420 bool oobe_complete = chromeos::WizardController::IsOobeCompleted(); | |
421 bool show_login_screen = | |
422 (first_screen_name.empty() && oobe_complete) || | |
423 first_screen_name == chromeos::WizardController::kLoginScreenName; | |
424 | |
425 chromeos::LoginDisplayHost* display_host; | |
426 display_host = new chromeos::WebUILoginDisplayHost(screen_bounds); | |
427 | |
428 if (show_login_screen) { | |
429 // R11 > R12 migration fix. See http://crosbug.com/p/4898. | |
430 // If user has manually changed locale during R11 OOBE, locale will be set. | |
431 // On R12 > R12|R13 etc. this fix won't get activated since | |
432 // OOBE process has set kApplicationLocale to non-default value. | |
433 PrefService* prefs = g_browser_process->local_state(); | |
434 if (!prefs->HasPrefPath(prefs::kApplicationLocale)) { | |
435 std::string locale = chromeos::WizardController::GetInitialLocale(); | |
436 prefs->SetString(prefs::kApplicationLocale, locale); | |
437 manager->EnableLayouts( | |
438 locale, | |
439 manager->GetInputMethodUtil()->GetHardwareInputMethodId()); | |
440 base::ThreadRestrictions::ScopedAllowIO allow_io; | |
441 const std::string loaded_locale = | |
442 ResourceBundle::GetSharedInstance().ReloadLocaleResources(locale); | |
443 g_browser_process->SetApplicationLocale(loaded_locale); | |
444 } | |
445 display_host->StartSignInScreen(); | |
446 return; | |
447 } | |
448 | |
449 // Load startup manifest. | |
450 const chromeos::StartupCustomizationDocument* startup_manifest = | |
451 chromeos::StartupCustomizationDocument::GetInstance(); | |
452 | |
453 // Switch to initial locale if specified by customization | |
454 // and has not been set yet. We cannot call | |
455 // chromeos::LanguageSwitchMenu::SwitchLanguage here before | |
456 // EmitLoginPromptReady. | |
457 PrefService* prefs = g_browser_process->local_state(); | |
458 const std::string current_locale = | |
459 prefs->GetString(prefs::kApplicationLocale); | |
460 VLOG(1) << "Current locale: " << current_locale; | |
461 std::string locale; | |
462 if (current_locale.empty()) { | |
463 locale = startup_manifest->initial_locale(); | |
464 std::string layout = startup_manifest->keyboard_layout(); | |
465 VLOG(1) << "Initial locale: " << locale | |
466 << "keyboard layout " << layout; | |
467 if (!locale.empty()) { | |
468 // Save initial locale from VPD/customization manifest as current | |
469 // Chrome locale. Otherwise it will be lost if Chrome restarts. | |
470 // Don't need to schedule pref save because setting initial local | |
471 // will enforce preference saving. | |
472 prefs->SetString(prefs::kApplicationLocale, locale); | |
473 chromeos::WizardController::SetInitialLocale(locale); | |
474 // Determine keyboard layout from OEM customization (if provided) or | |
475 // initial locale and save it in preferences. | |
476 DetermineAndSaveHardwareKeyboard(locale, layout); | |
477 // Then, enable the hardware keyboard. | |
478 manager->EnableLayouts( | |
479 locale, | |
480 manager->GetInputMethodUtil()->GetHardwareInputMethodId()); | |
481 // Reloading resource bundle causes us to do blocking IO on UI thread. | |
482 // Temporarily allow it until we fix http://crosbug.com/11102 | |
483 base::ThreadRestrictions::ScopedAllowIO allow_io; | |
484 const std::string loaded_locale = | |
485 ResourceBundle::GetSharedInstance().ReloadLocaleResources(locale); | |
486 CHECK(!loaded_locale.empty()) << "Locale could not be found for " | |
487 << locale; | |
488 // Set the application locale here so that the language switch | |
489 // menu works properly with the newly loaded locale. | |
490 g_browser_process->SetApplicationLocale(loaded_locale); | |
491 } | |
492 } | |
493 | |
494 display_host->StartWizard(first_screen_name, NULL); | |
495 | |
496 chromeos::LoginUtils::Get()->PrewarmAuthentication(); | |
497 chromeos::DBusThreadManager::Get()->GetSessionManagerClient() | |
498 ->EmitLoginPromptReady(); | |
499 TRACE_EVENT0("chromeos", "ShowLoginWizard::EmitLoginPromptReady"); | |
500 | |
501 // Set initial timezone if specified by customization. | |
502 const std::string timezone_name = startup_manifest->initial_timezone(); | |
503 VLOG(1) << "Initial time zone: " << timezone_name; | |
504 // Apply locale customizations only once to preserve whatever locale | |
505 // user has changed to during OOBE. | |
506 if (!timezone_name.empty()) { | |
507 chromeos::system::TimezoneSettings::GetInstance()->SetTimezoneFromID( | |
508 UTF8ToUTF16(timezone_name)); | |
509 } | |
510 } | |
511 | |
512 } // namespace chromeos | |
OLD | NEW |