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/login_display_host_impl.h" | |
6 | |
7 #include <vector> | |
8 | |
9 #include "ash/audio/sounds.h" | |
10 #include "ash/desktop_background/desktop_background_controller.h" | |
11 #include "ash/desktop_background/user_wallpaper_delegate.h" | |
12 #include "ash/shell.h" | |
13 #include "ash/shell_window_ids.h" | |
14 #include "base/bind.h" | |
15 #include "base/command_line.h" | |
16 #include "base/debug/trace_event.h" | |
17 #include "base/logging.h" | |
18 #include "base/prefs/pref_service.h" | |
19 #include "base/strings/string_split.h" | |
20 #include "base/strings/utf_string_conversions.h" | |
21 #include "base/threading/thread_restrictions.h" | |
22 #include "base/time/time.h" | |
23 #include "base/values.h" | |
24 #include "chrome/browser/browser_process.h" | |
25 #include "chrome/browser/browser_shutdown.h" | |
26 #include "chrome/browser/chrome_notification_types.h" | |
27 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h" | |
28 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h" | |
29 #include "chrome/browser/chromeos/base/locale_util.h" | |
30 #include "chrome/browser/chromeos/boot_times_loader.h" | |
31 #include "chrome/browser/chromeos/charger_replace/charger_replacement_dialog.h" | |
32 #include "chrome/browser/chromeos/first_run/drive_first_run_controller.h" | |
33 #include "chrome/browser/chromeos/first_run/first_run.h" | |
34 #include "chrome/browser/chromeos/input_method/input_method_util.h" | |
35 #include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h" | |
36 #include "chrome/browser/chromeos/language_preferences.h" | |
37 #include "chrome/browser/chromeos/login/demo_mode/demo_app_launcher.h" | |
38 #include "chrome/browser/chromeos/login/existing_user_controller.h" | |
39 #include "chrome/browser/chromeos/login/helper.h" | |
40 #include "chrome/browser/chromeos/login/input_events_blocker.h" | |
41 #include "chrome/browser/chromeos/login/keyboard_driven_oobe_key_handler.h" | |
42 #include "chrome/browser/chromeos/login/login_utils.h" | |
43 #include "chrome/browser/chromeos/login/login_wizard.h" | |
44 #include "chrome/browser/chromeos/login/oobe_display.h" | |
45 #include "chrome/browser/chromeos/login/startup_utils.h" | |
46 #include "chrome/browser/chromeos/login/user_manager.h" | |
47 #include "chrome/browser/chromeos/login/webui_login_display.h" | |
48 #include "chrome/browser/chromeos/login/webui_login_view.h" | |
49 #include "chrome/browser/chromeos/login/wizard_controller.h" | |
50 #include "chrome/browser/chromeos/mobile_config.h" | |
51 #include "chrome/browser/chromeos/net/delay_network_call.h" | |
52 #include "chrome/browser/chromeos/policy/auto_enrollment_client.h" | |
53 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" | |
54 #include "chrome/browser/chromeos/system/input_device_settings.h" | |
55 #include "chrome/browser/chromeos/ui/focus_ring_controller.h" | |
56 #include "chrome/browser/lifetime/application_lifetime.h" | |
57 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" | |
58 #include "chrome/common/chrome_constants.h" | |
59 #include "chrome/common/chrome_switches.h" | |
60 #include "chrome/common/pref_names.h" | |
61 #include "chromeos/audio/chromeos_sounds.h" | |
62 #include "chromeos/chromeos_constants.h" | |
63 #include "chromeos/chromeos_switches.h" | |
64 #include "chromeos/dbus/dbus_thread_manager.h" | |
65 #include "chromeos/dbus/session_manager_client.h" | |
66 #include "chromeos/ime/extension_ime_util.h" | |
67 #include "chromeos/ime/input_method_manager.h" | |
68 #include "chromeos/login/login_state.h" | |
69 #include "chromeos/settings/timezone_settings.h" | |
70 #include "content/public/browser/notification_service.h" | |
71 #include "content/public/browser/notification_types.h" | |
72 #include "content/public/browser/render_frame_host.h" | |
73 #include "content/public/browser/web_contents.h" | |
74 #include "content/public/browser/web_ui.h" | |
75 #include "grit/browser_resources.h" | |
76 #include "media/audio/sounds/sounds_manager.h" | |
77 #include "ui/aura/window.h" | |
78 #include "ui/base/resource/resource_bundle.h" | |
79 #include "ui/compositor/layer.h" | |
80 #include "ui/compositor/layer_animation_observer.h" | |
81 #include "ui/compositor/scoped_layer_animation_settings.h" | |
82 #include "ui/events/event_utils.h" | |
83 #include "ui/gfx/rect.h" | |
84 #include "ui/gfx/transform.h" | |
85 #include "ui/keyboard/keyboard_controller.h" | |
86 #include "ui/views/focus/focus_manager.h" | |
87 #include "ui/views/widget/widget.h" | |
88 #include "ui/views/widget/widget_delegate.h" | |
89 #include "ui/wm/core/window_animations.h" | |
90 #include "url/gurl.h" | |
91 | |
92 namespace { | |
93 | |
94 // Maximum delay for startup sound after 'loginPromptVisible' signal. | |
95 const int kStartupSoundMaxDelayMs = 2000; | |
96 | |
97 // URL which corresponds to the login WebUI. | |
98 const char kLoginURL[] = "chrome://oobe/login"; | |
99 | |
100 // URL which corresponds to the OOBE WebUI. | |
101 const char kOobeURL[] = "chrome://oobe/oobe"; | |
102 | |
103 // URL which corresponds to the user adding WebUI. | |
104 const char kUserAddingURL[] = "chrome://oobe/user-adding"; | |
105 | |
106 // URL which corresponds to the app launch splash WebUI. | |
107 const char kAppLaunchSplashURL[] = "chrome://oobe/app-launch-splash"; | |
108 | |
109 // Duration of sign-in transition animation. | |
110 const int kLoginFadeoutTransitionDurationMs = 700; | |
111 | |
112 // Number of times we try to reload OOBE/login WebUI if it crashes. | |
113 const int kCrashCountLimit = 5; | |
114 | |
115 // Whether to enable tnitializing WebUI in hidden state (see | |
116 // |initialize_webui_hidden_|) by default. | |
117 const bool kHiddenWebUIInitializationDefault = true; | |
118 | |
119 // Switch values that might be used to override WebUI init type. | |
120 const char kWebUIInitParallel[] = "parallel"; | |
121 const char kWebUIInitPostpone[] = "postpone"; | |
122 | |
123 // The delay of triggering initialization of the device policy subsystem | |
124 // after the login screen is initialized. This makes sure that device policy | |
125 // network requests are made while the system is idle waiting for user input. | |
126 const int64 kPolicyServiceInitializationDelayMilliseconds = 100; | |
127 | |
128 // Determines the hardware keyboard from the given locale code | |
129 // and the OEM layout information, and saves it to "Locale State". | |
130 // The information will be used in InputMethodUtil::GetHardwareInputMethodId(). | |
131 void DetermineAndSaveHardwareKeyboard(const std::string& locale, | |
132 const std::string& oem_layout) { | |
133 chromeos::input_method::InputMethodManager* manager = | |
134 chromeos::input_method::InputMethodManager::Get(); | |
135 std::string layout; | |
136 if (!oem_layout.empty()) { | |
137 // If the OEM layout information is provided, use it. | |
138 layout = oem_layout; | |
139 } else { | |
140 // Otherwise, determine the hardware keyboard from the locale. | |
141 std::vector<std::string> input_method_ids; | |
142 if (manager->GetInputMethodUtil()->GetInputMethodIdsFromLanguageCode( | |
143 locale, | |
144 chromeos::input_method::kKeyboardLayoutsOnly, | |
145 &input_method_ids)) { | |
146 // The output list |input_method_ids| is sorted by popularity, hence | |
147 // input_method_ids[0] now contains the most popular keyboard layout | |
148 // for the given locale. | |
149 layout = input_method_ids[0]; | |
150 } | |
151 } | |
152 | |
153 if (!layout.empty()) { | |
154 std::vector<std::string> layouts; | |
155 base::SplitString(layout, ',', &layouts); | |
156 manager->MigrateXkbInputMethods(&layouts); | |
157 | |
158 PrefService* prefs = g_browser_process->local_state(); | |
159 prefs->SetString(prefs::kHardwareKeyboardLayout, JoinString(layouts, ",")); | |
160 | |
161 // This asks the file thread to save the prefs (i.e. doesn't block). | |
162 // The latest values of Local State reside in memory so we can safely | |
163 // get the value of kHardwareKeyboardLayout even if the data is not | |
164 // yet saved to disk. | |
165 prefs->CommitPendingWrite(); | |
166 | |
167 manager->GetInputMethodUtil()->UpdateHardwareLayoutCache(); | |
168 manager->SetInputMethodLoginDefault(); | |
169 } | |
170 } | |
171 | |
172 // A class to observe an implicit animation and invokes the callback after the | |
173 // animation is completed. | |
174 class AnimationObserver : public ui::ImplicitAnimationObserver { | |
175 public: | |
176 explicit AnimationObserver(const base::Closure& callback) | |
177 : callback_(callback) {} | |
178 virtual ~AnimationObserver() {} | |
179 | |
180 private: | |
181 // ui::ImplicitAnimationObserver implementation: | |
182 virtual void OnImplicitAnimationsCompleted() OVERRIDE { | |
183 callback_.Run(); | |
184 delete this; | |
185 } | |
186 | |
187 base::Closure callback_; | |
188 | |
189 DISALLOW_COPY_AND_ASSIGN(AnimationObserver); | |
190 }; | |
191 | |
192 // ShowLoginWizard is split into two parts. This function is sometimes called | |
193 // from ShowLoginWizard(), and sometimes from OnLanguageSwitchedCallback() | |
194 // (if locale was updated). | |
195 void ShowLoginWizardFinish( | |
196 const std::string& first_screen_name, | |
197 const chromeos::StartupCustomizationDocument* startup_manifest, | |
198 chromeos::LoginDisplayHost* display_host) { | |
199 TRACE_EVENT0("chromeos", "ShowLoginWizard::ShowLoginWizardFinish"); | |
200 | |
201 scoped_ptr<base::DictionaryValue> params; | |
202 display_host->StartWizard(first_screen_name, params.Pass()); | |
203 | |
204 // Set initial timezone if specified by customization. | |
205 const std::string timezone_name = startup_manifest->initial_timezone(); | |
206 VLOG(1) << "Initial time zone: " << timezone_name; | |
207 // Apply locale customizations only once to preserve whatever locale | |
208 // user has changed to during OOBE. | |
209 if (!timezone_name.empty()) { | |
210 chromeos::system::TimezoneSettings::GetInstance()->SetTimezoneFromID( | |
211 base::UTF8ToUTF16(timezone_name)); | |
212 } | |
213 } | |
214 | |
215 struct ShowLoginWizardSwitchLanguageCallbackData { | |
216 explicit ShowLoginWizardSwitchLanguageCallbackData( | |
217 const std::string& first_screen_name, | |
218 const chromeos::StartupCustomizationDocument* startup_manifest, | |
219 chromeos::LoginDisplayHost* display_host) | |
220 : first_screen_name(first_screen_name), | |
221 startup_manifest(startup_manifest), | |
222 display_host(display_host) {} | |
223 | |
224 const std::string first_screen_name; | |
225 const chromeos::StartupCustomizationDocument* const startup_manifest; | |
226 chromeos::LoginDisplayHost* const display_host; | |
227 | |
228 // lock UI while resource bundle is being reloaded. | |
229 chromeos::InputEventsBlocker events_blocker; | |
230 }; | |
231 | |
232 void OnLanguageSwitchedCallback( | |
233 scoped_ptr<ShowLoginWizardSwitchLanguageCallbackData> self, | |
234 const std::string& locale, | |
235 const std::string& loaded_locale, | |
236 const bool success) { | |
237 if (!success) | |
238 LOG(WARNING) << "Locale could not be found for '" << locale << "'"; | |
239 | |
240 ShowLoginWizardFinish( | |
241 self->first_screen_name, self->startup_manifest, self->display_host); | |
242 } | |
243 | |
244 void EnableSystemSoundsForAccessibility() { | |
245 chromeos::AccessibilityManager::Get()->EnableSystemSounds(true); | |
246 } | |
247 | |
248 void AddToSetIfIsGaiaAuthIframe(std::set<content::RenderFrameHost*>* frame_set, | |
249 content::RenderFrameHost* frame) { | |
250 content::RenderFrameHost* parent = frame->GetParent(); | |
251 if (parent && parent->GetFrameName() == "signin-frame") | |
252 frame_set->insert(frame); | |
253 } | |
254 | |
255 // A login implementation of WidgetDelegate. | |
256 class LoginWidgetDelegate : public views::WidgetDelegate { | |
257 public: | |
258 explicit LoginWidgetDelegate(views::Widget* widget) : widget_(widget) { | |
259 } | |
260 virtual ~LoginWidgetDelegate() {} | |
261 | |
262 // Overridden from WidgetDelegate: | |
263 virtual void DeleteDelegate() OVERRIDE { | |
264 delete this; | |
265 } | |
266 virtual views::Widget* GetWidget() OVERRIDE { | |
267 return widget_; | |
268 } | |
269 virtual const views::Widget* GetWidget() const OVERRIDE { | |
270 return widget_; | |
271 } | |
272 virtual bool CanActivate() const OVERRIDE { | |
273 return true; | |
274 } | |
275 virtual bool ShouldAdvanceFocusToTopLevelWidget() const OVERRIDE { | |
276 return true; | |
277 } | |
278 | |
279 private: | |
280 views::Widget* widget_; | |
281 | |
282 DISALLOW_COPY_AND_ASSIGN(LoginWidgetDelegate); | |
283 }; | |
284 | |
285 } // namespace | |
286 | |
287 namespace chromeos { | |
288 | |
289 // static | |
290 LoginDisplayHost* LoginDisplayHostImpl::default_host_ = NULL; | |
291 | |
292 // static | |
293 const int LoginDisplayHostImpl::kShowLoginWebUIid = 0x1111; | |
294 | |
295 // static | |
296 content::RenderFrameHost* LoginDisplayHostImpl::GetGaiaAuthIframe( | |
297 content::WebContents* web_contents) { | |
298 std::set<content::RenderFrameHost*> frame_set; | |
299 web_contents->ForEachFrame( | |
300 base::Bind(&AddToSetIfIsGaiaAuthIframe, &frame_set)); | |
301 DCHECK_EQ(1U, frame_set.size()); | |
302 return *frame_set.begin(); | |
303 } | |
304 | |
305 //////////////////////////////////////////////////////////////////////////////// | |
306 // LoginDisplayHostImpl, public | |
307 | |
308 LoginDisplayHostImpl::LoginDisplayHostImpl(const gfx::Rect& background_bounds) | |
309 : background_bounds_(background_bounds), | |
310 pointer_factory_(this), | |
311 shutting_down_(false), | |
312 oobe_progress_bar_visible_(false), | |
313 session_starting_(false), | |
314 login_window_(NULL), | |
315 login_view_(NULL), | |
316 webui_login_display_(NULL), | |
317 is_showing_login_(false), | |
318 is_wallpaper_loaded_(false), | |
319 status_area_saved_visibility_(false), | |
320 crash_count_(0), | |
321 restore_path_(RESTORE_UNKNOWN), | |
322 finalize_animation_type_(ANIMATION_WORKSPACE), | |
323 animation_weak_ptr_factory_(this), | |
324 startup_sound_played_(false), | |
325 startup_sound_honors_spoken_feedback_(false), | |
326 is_observing_keyboard_(false) { | |
327 DBusThreadManager::Get()->GetSessionManagerClient()->AddObserver(this); | |
328 CrasAudioHandler::Get()->AddAudioObserver(this); | |
329 if (keyboard::KeyboardController::GetInstance()) { | |
330 keyboard::KeyboardController::GetInstance()->AddObserver(this); | |
331 is_observing_keyboard_ = true; | |
332 } | |
333 | |
334 ash::Shell::GetInstance()->delegate()->AddVirtualKeyboardStateObserver(this); | |
335 | |
336 // We need to listen to CLOSE_ALL_BROWSERS_REQUEST but not APP_TERMINATING | |
337 // because/ APP_TERMINATING will never be fired as long as this keeps | |
338 // ref-count. CLOSE_ALL_BROWSERS_REQUEST is safe here because there will be no | |
339 // browser instance that will block the shutdown. | |
340 registrar_.Add(this, | |
341 chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST, | |
342 content::NotificationService::AllSources()); | |
343 | |
344 // NOTIFICATION_BROWSER_OPENED is issued after browser is created, but | |
345 // not shown yet. Lock window has to be closed at this point so that | |
346 // a browser window exists and the window can acquire input focus. | |
347 registrar_.Add(this, | |
348 chrome::NOTIFICATION_BROWSER_OPENED, | |
349 content::NotificationService::AllSources()); | |
350 | |
351 // Login screen is moved to lock screen container when user logs in. | |
352 registrar_.Add(this, | |
353 chrome::NOTIFICATION_LOGIN_USER_CHANGED, | |
354 content::NotificationService::AllSources()); | |
355 | |
356 DCHECK(default_host_ == NULL); | |
357 default_host_ = this; | |
358 | |
359 // Make sure chrome won't exit while we are at login/oobe screen. | |
360 chrome::IncrementKeepAliveCount(); | |
361 | |
362 bool is_registered = StartupUtils::IsDeviceRegistered(); | |
363 bool zero_delay_enabled = WizardController::IsZeroDelayEnabled(); | |
364 bool disable_boot_animation = CommandLine::ForCurrentProcess()->HasSwitch( | |
365 switches::kDisableBootAnimation); | |
366 | |
367 waiting_for_wallpaper_load_ = !zero_delay_enabled && | |
368 (!is_registered || !disable_boot_animation); | |
369 | |
370 // For slower hardware we have boot animation disabled so | |
371 // we'll be initializing WebUI hidden, waiting for user pods to load and then | |
372 // show WebUI at once. | |
373 waiting_for_user_pods_ = !zero_delay_enabled && !waiting_for_wallpaper_load_; | |
374 | |
375 initialize_webui_hidden_ = | |
376 kHiddenWebUIInitializationDefault && !zero_delay_enabled; | |
377 | |
378 // Check if WebUI init type is overriden. | |
379 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshWebUIInit)) { | |
380 const std::string override_type = | |
381 CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | |
382 switches::kAshWebUIInit); | |
383 if (override_type == kWebUIInitParallel) | |
384 initialize_webui_hidden_ = true; | |
385 else if (override_type == kWebUIInitPostpone) | |
386 initialize_webui_hidden_ = false; | |
387 } | |
388 | |
389 // Always postpone WebUI initialization on first boot, otherwise we miss | |
390 // initial animation. | |
391 if (!StartupUtils::IsOobeCompleted()) | |
392 initialize_webui_hidden_ = false; | |
393 | |
394 // There is no wallpaper for KioskMode, don't initialize the webui hidden. | |
395 if (chromeos::KioskModeSettings::Get()->IsKioskModeEnabled()) | |
396 initialize_webui_hidden_ = false; | |
397 | |
398 if (waiting_for_wallpaper_load_) { | |
399 registrar_.Add(this, | |
400 chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED, | |
401 content::NotificationService::AllSources()); | |
402 } | |
403 | |
404 // When we wait for WebUI to be initialized we wait for one of | |
405 // these notifications. | |
406 if ((waiting_for_user_pods_ || waiting_for_wallpaper_load_) && | |
407 initialize_webui_hidden_) { | |
408 registrar_.Add(this, | |
409 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE, | |
410 content::NotificationService::AllSources()); | |
411 registrar_.Add(this, | |
412 chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN, | |
413 content::NotificationService::AllSources()); | |
414 } | |
415 LOG(WARNING) << "Login WebUI >> " | |
416 << "zero_delay: " << zero_delay_enabled | |
417 << " wait_for_wp_load_: " << waiting_for_wallpaper_load_ | |
418 << " wait_for_pods_: " << waiting_for_user_pods_ | |
419 << " init_webui_hidden_: " << initialize_webui_hidden_; | |
420 | |
421 media::SoundsManager* manager = media::SoundsManager::Get(); | |
422 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); | |
423 manager->Initialize(chromeos::SOUND_STARTUP, | |
424 bundle.GetRawDataResource(IDR_SOUND_STARTUP_WAV)); | |
425 } | |
426 | |
427 LoginDisplayHostImpl::~LoginDisplayHostImpl() { | |
428 DBusThreadManager::Get()->GetSessionManagerClient()->RemoveObserver(this); | |
429 CrasAudioHandler::Get()->RemoveAudioObserver(this); | |
430 if (keyboard::KeyboardController::GetInstance() && is_observing_keyboard_) { | |
431 keyboard::KeyboardController::GetInstance()->RemoveObserver(this); | |
432 is_observing_keyboard_ = false; | |
433 } | |
434 | |
435 ash::Shell::GetInstance()->delegate()-> | |
436 RemoveVirtualKeyboardStateObserver(this); | |
437 | |
438 views::FocusManager::set_arrow_key_traversal_enabled(false); | |
439 ResetLoginWindowAndView(); | |
440 | |
441 // Let chrome process exit after login/oobe screen if needed. | |
442 chrome::DecrementKeepAliveCount(); | |
443 | |
444 default_host_ = NULL; | |
445 // TODO(tengs): This should be refactored. See crbug.com/314934. | |
446 if (UserManager::Get()->IsCurrentUserNew()) { | |
447 // DriveOptInController will delete itself when finished. | |
448 (new DriveFirstRunController( | |
449 ProfileManager::GetActiveUserProfile()))->EnableOfflineMode(); | |
450 } | |
451 } | |
452 | |
453 //////////////////////////////////////////////////////////////////////////////// | |
454 // LoginDisplayHostImpl, LoginDisplayHost implementation: | |
455 | |
456 LoginDisplay* LoginDisplayHostImpl::CreateLoginDisplay( | |
457 LoginDisplay::Delegate* delegate) { | |
458 webui_login_display_ = new WebUILoginDisplay(delegate); | |
459 webui_login_display_->set_background_bounds(background_bounds()); | |
460 return webui_login_display_; | |
461 } | |
462 | |
463 gfx::NativeWindow LoginDisplayHostImpl::GetNativeWindow() const { | |
464 return login_window_ ? login_window_->GetNativeWindow() : NULL; | |
465 } | |
466 | |
467 WebUILoginView* LoginDisplayHostImpl::GetWebUILoginView() const { | |
468 return login_view_; | |
469 } | |
470 | |
471 void LoginDisplayHostImpl::BeforeSessionStart() { | |
472 session_starting_ = true; | |
473 } | |
474 | |
475 void LoginDisplayHostImpl::Finalize() { | |
476 DVLOG(1) << "Session starting"; | |
477 if (ash::Shell::HasInstance()) { | |
478 ash::Shell::GetInstance()-> | |
479 desktop_background_controller()->MoveDesktopToUnlockedContainer(); | |
480 } | |
481 if (wizard_controller_.get()) | |
482 wizard_controller_->OnSessionStart(); | |
483 | |
484 switch (finalize_animation_type_) { | |
485 case ANIMATION_NONE: | |
486 ShutdownDisplayHost(false); | |
487 break; | |
488 case ANIMATION_WORKSPACE: | |
489 if (ash::Shell::HasInstance()) | |
490 ScheduleWorkspaceAnimation(); | |
491 | |
492 ShutdownDisplayHost(false); | |
493 break; | |
494 case ANIMATION_FADE_OUT: | |
495 // Display host is deleted once animation is completed | |
496 // since sign in screen widget has to stay alive. | |
497 ScheduleFadeOutAnimation(); | |
498 break; | |
499 } | |
500 } | |
501 | |
502 void LoginDisplayHostImpl::OnCompleteLogin() { | |
503 if (auto_enrollment_controller_) | |
504 auto_enrollment_controller_->Cancel(); | |
505 } | |
506 | |
507 void LoginDisplayHostImpl::OpenProxySettings() { | |
508 if (login_view_) | |
509 login_view_->OpenProxySettings(); | |
510 } | |
511 | |
512 void LoginDisplayHostImpl::SetStatusAreaVisible(bool visible) { | |
513 if (initialize_webui_hidden_) | |
514 status_area_saved_visibility_ = visible; | |
515 else if (login_view_) | |
516 login_view_->SetStatusAreaVisible(visible); | |
517 } | |
518 | |
519 AutoEnrollmentController* LoginDisplayHostImpl::GetAutoEnrollmentController() { | |
520 if (!auto_enrollment_controller_) { | |
521 auto_enrollment_controller_.reset(new AutoEnrollmentController()); | |
522 auto_enrollment_progress_subscription_ = | |
523 auto_enrollment_controller_->RegisterProgressCallback( | |
524 base::Bind(&LoginDisplayHostImpl::OnAutoEnrollmentProgress, | |
525 base::Unretained(this))); | |
526 } | |
527 return auto_enrollment_controller_.get(); | |
528 } | |
529 | |
530 void LoginDisplayHostImpl::StartWizard( | |
531 const std::string& first_screen_name, | |
532 scoped_ptr<base::DictionaryValue> screen_parameters) { | |
533 startup_sound_honors_spoken_feedback_ = true; | |
534 TryToPlayStartupSound(); | |
535 | |
536 // Keep parameters to restore if renderer crashes. | |
537 restore_path_ = RESTORE_WIZARD; | |
538 wizard_first_screen_name_ = first_screen_name; | |
539 if (screen_parameters.get()) | |
540 wizard_screen_parameters_.reset(screen_parameters->DeepCopy()); | |
541 else | |
542 wizard_screen_parameters_.reset(); | |
543 is_showing_login_ = false; | |
544 | |
545 if (waiting_for_wallpaper_load_ && !initialize_webui_hidden_) { | |
546 LOG(WARNING) << "Login WebUI >> wizard postponed"; | |
547 return; | |
548 } | |
549 LOG(WARNING) << "Login WebUI >> wizard"; | |
550 | |
551 if (!login_window_) | |
552 LoadURL(GURL(kOobeURL)); | |
553 | |
554 DVLOG(1) << "Starting wizard, first_screen_name: " << first_screen_name; | |
555 // Create and show the wizard. | |
556 // Note, dtor of the old WizardController should be called before ctor of the | |
557 // new one, because "default_controller()" is updated there. So pure "reset()" | |
558 // is done before new controller creation. | |
559 wizard_controller_.reset(); | |
560 wizard_controller_.reset(CreateWizardController()); | |
561 | |
562 oobe_progress_bar_visible_ = !StartupUtils::IsDeviceRegistered(); | |
563 SetOobeProgressBarVisible(oobe_progress_bar_visible_); | |
564 wizard_controller_->Init(first_screen_name, screen_parameters.Pass()); | |
565 } | |
566 | |
567 WizardController* LoginDisplayHostImpl::GetWizardController() { | |
568 return wizard_controller_.get(); | |
569 } | |
570 | |
571 AppLaunchController* LoginDisplayHostImpl::GetAppLaunchController() { | |
572 return app_launch_controller_.get(); | |
573 } | |
574 | |
575 void LoginDisplayHostImpl::StartUserAdding( | |
576 const base::Closure& completion_callback) { | |
577 restore_path_ = RESTORE_ADD_USER_INTO_SESSION; | |
578 completion_callback_ = completion_callback; | |
579 finalize_animation_type_ = ANIMATION_NONE; | |
580 LOG(WARNING) << "Login WebUI >> user adding"; | |
581 if (!login_window_) | |
582 LoadURL(GURL(kUserAddingURL)); | |
583 // We should emit this signal only at login screen (after reboot or sign out). | |
584 login_view_->set_should_emit_login_prompt_visible(false); | |
585 | |
586 // Lock container can be transparent after lock screen animation. | |
587 aura::Window* lock_container = ash::Shell::GetContainer( | |
588 ash::Shell::GetPrimaryRootWindow(), | |
589 ash::kShellWindowId_LockScreenContainersContainer); | |
590 lock_container->layer()->SetOpacity(1.0); | |
591 | |
592 ash::Shell::GetInstance()-> | |
593 desktop_background_controller()->MoveDesktopToLockedContainer(); | |
594 | |
595 sign_in_controller_.reset(); // Only one controller in a time. | |
596 sign_in_controller_.reset(new chromeos::ExistingUserController(this)); | |
597 SetOobeProgressBarVisible(oobe_progress_bar_visible_ = false); | |
598 SetStatusAreaVisible(true); | |
599 sign_in_controller_->Init( | |
600 chromeos::UserManager::Get()->GetUsersAdmittedForMultiProfile()); | |
601 CHECK(webui_login_display_); | |
602 GetOobeUI()->ShowSigninScreen(LoginScreenContext(), | |
603 webui_login_display_, | |
604 webui_login_display_); | |
605 } | |
606 | |
607 void LoginDisplayHostImpl::StartSignInScreen( | |
608 const LoginScreenContext& context) { | |
609 startup_sound_honors_spoken_feedback_ = true; | |
610 TryToPlayStartupSound(); | |
611 | |
612 restore_path_ = RESTORE_SIGN_IN; | |
613 is_showing_login_ = true; | |
614 finalize_animation_type_ = ANIMATION_WORKSPACE; | |
615 | |
616 PrewarmAuthentication(); | |
617 | |
618 if (waiting_for_wallpaper_load_ && !initialize_webui_hidden_) { | |
619 LOG(WARNING) << "Login WebUI >> sign in postponed"; | |
620 return; | |
621 } | |
622 LOG(WARNING) << "Login WebUI >> sign in"; | |
623 | |
624 if (!login_window_) { | |
625 TRACE_EVENT_ASYNC_BEGIN0("ui", "ShowLoginWebUI", kShowLoginWebUIid); | |
626 TRACE_EVENT_ASYNC_STEP_INTO0( | |
627 "ui", "ShowLoginWebUI", kShowLoginWebUIid, "StartSignInScreen"); | |
628 BootTimesLoader::Get()->RecordCurrentStats("login-start-signin-screen"); | |
629 LoadURL(GURL(kLoginURL)); | |
630 } | |
631 | |
632 DVLOG(1) << "Starting sign in screen"; | |
633 const chromeos::UserList& users = chromeos::UserManager::Get()->GetUsers(); | |
634 | |
635 // Fix for users who updated device and thus never passed register screen. | |
636 // If we already have users, we assume that it is not a second part of | |
637 // OOBE. See http://crosbug.com/6289 | |
638 if (!StartupUtils::IsDeviceRegistered() && !users.empty()) { | |
639 VLOG(1) << "Mark device registered because there are remembered users: " | |
640 << users.size(); | |
641 StartupUtils::MarkDeviceRegistered(); | |
642 } | |
643 | |
644 sign_in_controller_.reset(); // Only one controller in a time. | |
645 sign_in_controller_.reset(new chromeos::ExistingUserController(this)); | |
646 oobe_progress_bar_visible_ = !StartupUtils::IsDeviceRegistered(); | |
647 SetOobeProgressBarVisible(oobe_progress_bar_visible_); | |
648 SetStatusAreaVisible(true); | |
649 sign_in_controller_->Init(users); | |
650 | |
651 // We might be here after a reboot that was triggered after OOBE was complete, | |
652 // so check for auto-enrollment again. This might catch a cached decision from | |
653 // a previous oobe flow, or might start a new check with the server. | |
654 if (GetAutoEnrollmentController()->ShouldEnrollSilently()) | |
655 sign_in_controller_->DoAutoEnrollment(); | |
656 else | |
657 GetAutoEnrollmentController()->Start(); | |
658 | |
659 // Initiate mobile config load. | |
660 MobileConfig::GetInstance(); | |
661 | |
662 // Initiate device policy fetching. | |
663 policy::BrowserPolicyConnectorChromeOS* connector = | |
664 g_browser_process->platform_part()->browser_policy_connector_chromeos(); | |
665 connector->ScheduleServiceInitialization( | |
666 kPolicyServiceInitializationDelayMilliseconds); | |
667 | |
668 CHECK(webui_login_display_); | |
669 GetOobeUI()->ShowSigninScreen(context, | |
670 webui_login_display_, | |
671 webui_login_display_); | |
672 if (chromeos::KioskModeSettings::Get()->IsKioskModeEnabled()) | |
673 SetStatusAreaVisible(false); | |
674 TRACE_EVENT_ASYNC_STEP_INTO0("ui", | |
675 "ShowLoginWebUI", | |
676 kShowLoginWebUIid, | |
677 "WaitForScreenStateInitialize"); | |
678 BootTimesLoader::Get()->RecordCurrentStats( | |
679 "login-wait-for-signin-state-initialize"); | |
680 } | |
681 | |
682 void LoginDisplayHostImpl::ResumeSignInScreen() { | |
683 // We only get here after a previous call the StartSignInScreen. That sign-in | |
684 // was successful but was interrupted by an auto-enrollment execution; once | |
685 // auto-enrollment is complete we resume the normal login flow from here. | |
686 DVLOG(1) << "Resuming sign in screen"; | |
687 CHECK(sign_in_controller_.get()); | |
688 SetOobeProgressBarVisible(oobe_progress_bar_visible_); | |
689 SetStatusAreaVisible(true); | |
690 sign_in_controller_->ResumeLogin(); | |
691 } | |
692 | |
693 | |
694 void LoginDisplayHostImpl::OnPreferencesChanged() { | |
695 if (is_showing_login_) | |
696 webui_login_display_->OnPreferencesChanged(); | |
697 } | |
698 | |
699 void LoginDisplayHostImpl::PrewarmAuthentication() { | |
700 auth_prewarmer_.reset(new AuthPrewarmer()); | |
701 auth_prewarmer_->PrewarmAuthentication( | |
702 base::Bind(&LoginDisplayHostImpl::OnAuthPrewarmDone, | |
703 pointer_factory_.GetWeakPtr())); | |
704 } | |
705 | |
706 void LoginDisplayHostImpl::StartDemoAppLaunch() { | |
707 LOG(WARNING) << "Login WebUI >> starting demo app."; | |
708 SetStatusAreaVisible(false); | |
709 | |
710 demo_app_launcher_.reset(new DemoAppLauncher()); | |
711 demo_app_launcher_->StartDemoAppLaunch(); | |
712 } | |
713 | |
714 void LoginDisplayHostImpl::StartAppLaunch(const std::string& app_id, | |
715 bool diagnostic_mode) { | |
716 LOG(WARNING) << "Login WebUI >> start app launch."; | |
717 SetStatusAreaVisible(false); | |
718 finalize_animation_type_ = ANIMATION_FADE_OUT; | |
719 if (!login_window_) | |
720 LoadURL(GURL(kAppLaunchSplashURL)); | |
721 | |
722 login_view_->set_should_emit_login_prompt_visible(false); | |
723 | |
724 app_launch_controller_.reset(new AppLaunchController( | |
725 app_id, diagnostic_mode, this, GetOobeUI())); | |
726 | |
727 app_launch_controller_->StartAppLaunch(); | |
728 } | |
729 | |
730 //////////////////////////////////////////////////////////////////////////////// | |
731 // LoginDisplayHostImpl, public | |
732 | |
733 WizardController* LoginDisplayHostImpl::CreateWizardController() { | |
734 // TODO(altimofeev): ensure that WebUI is ready. | |
735 OobeDisplay* oobe_display = GetOobeUI(); | |
736 return new WizardController(this, oobe_display); | |
737 } | |
738 | |
739 void LoginDisplayHostImpl::OnBrowserCreated() { | |
740 // Close lock window now so that the launched browser can receive focus. | |
741 ResetLoginWindowAndView(); | |
742 } | |
743 | |
744 OobeUI* LoginDisplayHostImpl::GetOobeUI() const { | |
745 if (!login_view_) | |
746 return NULL; | |
747 return static_cast<OobeUI*>(login_view_->GetWebUI()->GetController()); | |
748 } | |
749 | |
750 //////////////////////////////////////////////////////////////////////////////// | |
751 // LoginDisplayHostImpl, content:NotificationObserver implementation: | |
752 | |
753 void LoginDisplayHostImpl::Observe( | |
754 int type, | |
755 const content::NotificationSource& source, | |
756 const content::NotificationDetails& details) { | |
757 if (chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED == type) { | |
758 LOG(WARNING) << "Login WebUI >> wp animation done"; | |
759 is_wallpaper_loaded_ = true; | |
760 ash::Shell::GetInstance()->user_wallpaper_delegate() | |
761 ->OnWallpaperBootAnimationFinished(); | |
762 if (waiting_for_wallpaper_load_) { | |
763 // StartWizard / StartSignInScreen could be called multiple times through | |
764 // the lifetime of host. | |
765 // Make sure that subsequent calls are not postponed. | |
766 waiting_for_wallpaper_load_ = false; | |
767 if (initialize_webui_hidden_) | |
768 ShowWebUI(); | |
769 else | |
770 StartPostponedWebUI(); | |
771 } | |
772 registrar_.Remove(this, | |
773 chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED, | |
774 content::NotificationService::AllSources()); | |
775 } else if (chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE == type || | |
776 chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN == type) { | |
777 LOG(WARNING) << "Login WebUI >> WEBUI_VISIBLE"; | |
778 if (waiting_for_user_pods_ && initialize_webui_hidden_) { | |
779 waiting_for_user_pods_ = false; | |
780 ShowWebUI(); | |
781 } else if (waiting_for_wallpaper_load_ && initialize_webui_hidden_) { | |
782 // Reduce time till login UI is shown - show it as soon as possible. | |
783 waiting_for_wallpaper_load_ = false; | |
784 ShowWebUI(); | |
785 } | |
786 registrar_.Remove(this, | |
787 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE, | |
788 content::NotificationService::AllSources()); | |
789 registrar_.Remove(this, | |
790 chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN, | |
791 content::NotificationService::AllSources()); | |
792 } else if (type == chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST) { | |
793 ShutdownDisplayHost(true); | |
794 } else if (type == chrome::NOTIFICATION_BROWSER_OPENED && session_starting_) { | |
795 // Browsers created before session start (windows opened by extensions, for | |
796 // example) are ignored. | |
797 OnBrowserCreated(); | |
798 registrar_.Remove(this, | |
799 chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST, | |
800 content::NotificationService::AllSources()); | |
801 registrar_.Remove(this, | |
802 chrome::NOTIFICATION_BROWSER_OPENED, | |
803 content::NotificationService::AllSources()); | |
804 } else if (type == chrome::NOTIFICATION_LOGIN_USER_CHANGED && | |
805 chromeos::UserManager::Get()->IsCurrentUserNew()) { | |
806 // For new user, move desktop to locker container so that windows created | |
807 // during the user image picker step are below it. | |
808 ash::Shell::GetInstance()-> | |
809 desktop_background_controller()->MoveDesktopToLockedContainer(); | |
810 registrar_.Remove(this, | |
811 chrome::NOTIFICATION_LOGIN_USER_CHANGED, | |
812 content::NotificationService::AllSources()); | |
813 } | |
814 } | |
815 | |
816 //////////////////////////////////////////////////////////////////////////////// | |
817 // LoginDisplayHostImpl, WebContentsObserver implementation: | |
818 | |
819 void LoginDisplayHostImpl::RenderProcessGone(base::TerminationStatus status) { | |
820 // Do not try to restore on shutdown | |
821 if (browser_shutdown::GetShutdownType() != browser_shutdown::NOT_VALID) | |
822 return; | |
823 | |
824 crash_count_++; | |
825 if (crash_count_ > kCrashCountLimit) | |
826 return; | |
827 | |
828 if (status != base::TERMINATION_STATUS_NORMAL_TERMINATION) { | |
829 // Render with login screen crashed. Let's crash browser process to let | |
830 // session manager restart it properly. It is hard to reload the page | |
831 // and get to controlled state that is fully functional. | |
832 // If you see check, search for renderer crash for the same client. | |
833 LOG(FATAL) << "Renderer crash on login window"; | |
834 } | |
835 } | |
836 | |
837 //////////////////////////////////////////////////////////////////////////////// | |
838 // LoginDisplayHostImpl, chromeos::SessionManagerClient::Observer | |
839 // implementation: | |
840 | |
841 void LoginDisplayHostImpl::EmitLoginPromptVisibleCalled() { | |
842 OnLoginPromptVisible(); | |
843 } | |
844 | |
845 //////////////////////////////////////////////////////////////////////////////// | |
846 // LoginDisplayHostImpl, chromeos::CrasAudioHandler::AudioObserver | |
847 // implementation: | |
848 | |
849 void LoginDisplayHostImpl::OnActiveOutputNodeChanged() { | |
850 TryToPlayStartupSound(); | |
851 } | |
852 | |
853 //////////////////////////////////////////////////////////////////////////////// | |
854 // LoginDisplayHostImpl, ash::KeyboardStateObserver: | |
855 // implementation: | |
856 | |
857 void LoginDisplayHostImpl::OnVirtualKeyboardStateChanged(bool activated) { | |
858 if (keyboard::KeyboardController::GetInstance()) { | |
859 if (activated) { | |
860 if (!is_observing_keyboard_) { | |
861 keyboard::KeyboardController::GetInstance()->AddObserver(this); | |
862 is_observing_keyboard_ = true; | |
863 } | |
864 } else { | |
865 keyboard::KeyboardController::GetInstance()->RemoveObserver(this); | |
866 is_observing_keyboard_ = false; | |
867 } | |
868 } | |
869 } | |
870 | |
871 //////////////////////////////////////////////////////////////////////////////// | |
872 // LoginDisplayHostImpl, keyboard::KeyboardControllerObserver: | |
873 // implementation: | |
874 | |
875 void LoginDisplayHostImpl::OnKeyboardBoundsChanging( | |
876 const gfx::Rect& new_bounds) { | |
877 if (new_bounds.IsEmpty() && !keyboard_bounds_.IsEmpty()) { | |
878 // Keyboard has been hidden. | |
879 if (webui_login_display_) | |
880 webui_login_display_->ShowControlBar(true); | |
881 } else if (!new_bounds.IsEmpty() && keyboard_bounds_.IsEmpty()) { | |
882 // Keyboard has been shown. | |
883 if (webui_login_display_) | |
884 webui_login_display_->ShowControlBar(false); | |
885 } | |
886 | |
887 keyboard_bounds_ = new_bounds; | |
888 } | |
889 | |
890 //////////////////////////////////////////////////////////////////////////////// | |
891 // LoginDisplayHostImpl, private | |
892 | |
893 void LoginDisplayHostImpl::ShutdownDisplayHost(bool post_quit_task) { | |
894 if (shutting_down_) | |
895 return; | |
896 | |
897 shutting_down_ = true; | |
898 registrar_.RemoveAll(); | |
899 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); | |
900 if (post_quit_task) | |
901 base::MessageLoop::current()->Quit(); | |
902 | |
903 if (!completion_callback_.is_null()) | |
904 completion_callback_.Run(); | |
905 } | |
906 | |
907 void LoginDisplayHostImpl::ScheduleWorkspaceAnimation() { | |
908 if (ash::Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(), | |
909 ash::kShellWindowId_DesktopBackgroundContainer) | |
910 ->children() | |
911 .empty()) { | |
912 // If there is no background window, don't perform any animation on the | |
913 // default and background layer because there is nothing behind it. | |
914 return; | |
915 } | |
916 | |
917 if (!CommandLine::ForCurrentProcess()->HasSwitch( | |
918 switches::kDisableLoginAnimations)) | |
919 ash::Shell::GetInstance()->DoInitialWorkspaceAnimation(); | |
920 } | |
921 | |
922 void LoginDisplayHostImpl::ScheduleFadeOutAnimation() { | |
923 ui::Layer* layer = login_window_->GetLayer(); | |
924 ui::ScopedLayerAnimationSettings animation(layer->GetAnimator()); | |
925 animation.AddObserver(new AnimationObserver( | |
926 base::Bind(&LoginDisplayHostImpl::ShutdownDisplayHost, | |
927 animation_weak_ptr_factory_.GetWeakPtr(), | |
928 false))); | |
929 layer->SetOpacity(0); | |
930 } | |
931 | |
932 void LoginDisplayHostImpl::OnAutoEnrollmentProgress( | |
933 policy::AutoEnrollmentState state) { | |
934 VLOG(1) << "OnAutoEnrollmentProgress, state " << state; | |
935 | |
936 if (sign_in_controller_ && | |
937 auto_enrollment_controller_->ShouldEnrollSilently()) { | |
938 sign_in_controller_->DoAutoEnrollment(); | |
939 } | |
940 } | |
941 | |
942 void LoginDisplayHostImpl::LoadURL(const GURL& url) { | |
943 InitLoginWindowAndView(); | |
944 // Subscribe to crash events. | |
945 content::WebContentsObserver::Observe(login_view_->GetWebContents()); | |
946 login_view_->LoadURL(url); | |
947 | |
948 // LoadURL could be called after the spring charger dialog shows, and | |
949 // take away the focus from it. Set the focus back to the charger dialog | |
950 // if it is visible. | |
951 // See crbug.com/328538. | |
952 ChargerReplacementDialog::SetFocusOnChargerDialogIfVisible(); | |
953 } | |
954 | |
955 void LoginDisplayHostImpl::ShowWebUI() { | |
956 if (!login_window_ || !login_view_) { | |
957 NOTREACHED(); | |
958 return; | |
959 } | |
960 LOG(WARNING) << "Login WebUI >> Show already initialized UI"; | |
961 login_window_->Show(); | |
962 login_view_->GetWebContents()->Focus(); | |
963 login_view_->SetStatusAreaVisible(status_area_saved_visibility_); | |
964 login_view_->OnPostponedShow(); | |
965 | |
966 // Login window could be shown after the spring charger dialog shows, and | |
967 // take away the focus from it. Set the focus back to the charger dialog | |
968 // if it is visible. | |
969 // See crbug.com/328538. | |
970 ChargerReplacementDialog::SetFocusOnChargerDialogIfVisible(); | |
971 | |
972 // We should reset this flag to allow changing of status area visibility. | |
973 initialize_webui_hidden_ = false; | |
974 } | |
975 | |
976 void LoginDisplayHostImpl::StartPostponedWebUI() { | |
977 if (!is_wallpaper_loaded_) { | |
978 NOTREACHED(); | |
979 return; | |
980 } | |
981 LOG(WARNING) << "Login WebUI >> Init postponed WebUI"; | |
982 | |
983 // Wallpaper has finished loading before StartWizard/StartSignInScreen has | |
984 // been called. In general this should not happen. | |
985 // Let go through normal code path when one of those will be called. | |
986 if (restore_path_ == RESTORE_UNKNOWN) { | |
987 NOTREACHED(); | |
988 return; | |
989 } | |
990 | |
991 switch (restore_path_) { | |
992 case RESTORE_WIZARD: | |
993 StartWizard(wizard_first_screen_name_, | |
994 wizard_screen_parameters_.Pass()); | |
995 break; | |
996 case RESTORE_SIGN_IN: | |
997 StartSignInScreen(LoginScreenContext()); | |
998 break; | |
999 case RESTORE_ADD_USER_INTO_SESSION: | |
1000 StartUserAdding(completion_callback_); | |
1001 break; | |
1002 default: | |
1003 NOTREACHED(); | |
1004 break; | |
1005 } | |
1006 } | |
1007 | |
1008 void LoginDisplayHostImpl::InitLoginWindowAndView() { | |
1009 if (login_window_) | |
1010 return; | |
1011 | |
1012 if (system::InputDeviceSettings::Get()->ForceKeyboardDrivenUINavigation()) { | |
1013 views::FocusManager::set_arrow_key_traversal_enabled(true); | |
1014 | |
1015 focus_ring_controller_.reset(new FocusRingController); | |
1016 focus_ring_controller_->SetVisible(true); | |
1017 | |
1018 keyboard_driven_oobe_key_handler_.reset(new KeyboardDrivenOobeKeyHandler); | |
1019 } | |
1020 | |
1021 views::Widget::InitParams params( | |
1022 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); | |
1023 params.bounds = background_bounds(); | |
1024 params.show_state = ui::SHOW_STATE_MAXIMIZED; | |
1025 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; | |
1026 params.parent = | |
1027 ash::Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(), | |
1028 ash::kShellWindowId_LockScreenContainer); | |
1029 | |
1030 login_window_ = new views::Widget; | |
1031 params.delegate = new LoginWidgetDelegate(login_window_); | |
1032 login_window_->Init(params); | |
1033 | |
1034 login_view_ = new WebUILoginView(); | |
1035 login_view_->Init(); | |
1036 if (login_view_->webui_visible()) | |
1037 OnLoginPromptVisible(); | |
1038 | |
1039 wm::SetWindowVisibilityAnimationDuration( | |
1040 login_window_->GetNativeView(), | |
1041 base::TimeDelta::FromMilliseconds(kLoginFadeoutTransitionDurationMs)); | |
1042 wm::SetWindowVisibilityAnimationTransition( | |
1043 login_window_->GetNativeView(), | |
1044 wm::ANIMATE_HIDE); | |
1045 | |
1046 login_window_->SetContentsView(login_view_); | |
1047 | |
1048 // If WebUI is initialized in hidden state, show it only if we're no | |
1049 // longer waiting for wallpaper animation/user images loading. Otherwise, | |
1050 // always show it. | |
1051 if (!initialize_webui_hidden_ || | |
1052 (!waiting_for_wallpaper_load_ && !waiting_for_user_pods_)) { | |
1053 LOG(WARNING) << "Login WebUI >> show login wnd on create"; | |
1054 login_window_->Show(); | |
1055 } else { | |
1056 LOG(WARNING) << "Login WebUI >> login wnd is hidden on create"; | |
1057 login_view_->set_is_hidden(true); | |
1058 } | |
1059 login_window_->GetNativeView()->SetName("WebUILoginView"); | |
1060 } | |
1061 | |
1062 void LoginDisplayHostImpl::ResetLoginWindowAndView() { | |
1063 if (!login_window_) | |
1064 return; | |
1065 login_window_->Close(); | |
1066 login_window_ = NULL; | |
1067 login_view_ = NULL; | |
1068 } | |
1069 | |
1070 void LoginDisplayHostImpl::OnAuthPrewarmDone() { | |
1071 auth_prewarmer_.reset(); | |
1072 } | |
1073 | |
1074 void LoginDisplayHostImpl::SetOobeProgressBarVisible(bool visible) { | |
1075 GetOobeUI()->ShowOobeUI(visible); | |
1076 } | |
1077 | |
1078 void LoginDisplayHostImpl::TryToPlayStartupSound() { | |
1079 if (startup_sound_played_ || login_prompt_visible_time_.is_null() || | |
1080 !CrasAudioHandler::Get()->GetActiveOutputNode()) { | |
1081 return; | |
1082 } | |
1083 | |
1084 startup_sound_played_ = true; | |
1085 | |
1086 // Don't try play startup sound if login prompt is already visible | |
1087 // for a long time or can't be played. | |
1088 if (base::TimeTicks::Now() - login_prompt_visible_time_ > | |
1089 base::TimeDelta::FromMilliseconds(kStartupSoundMaxDelayMs)) { | |
1090 EnableSystemSoundsForAccessibility(); | |
1091 return; | |
1092 } | |
1093 | |
1094 if (!startup_sound_honors_spoken_feedback_ && | |
1095 !ash::PlaySystemSoundAlways(SOUND_STARTUP)) { | |
1096 EnableSystemSoundsForAccessibility(); | |
1097 return; | |
1098 } | |
1099 | |
1100 if (startup_sound_honors_spoken_feedback_ && | |
1101 !ash::PlaySystemSoundIfSpokenFeedback(SOUND_STARTUP)) { | |
1102 EnableSystemSoundsForAccessibility(); | |
1103 return; | |
1104 } | |
1105 | |
1106 base::MessageLoop::current()->PostDelayedTask( | |
1107 FROM_HERE, | |
1108 base::Bind(&EnableSystemSoundsForAccessibility), | |
1109 media::SoundsManager::Get()->GetDuration(SOUND_STARTUP)); | |
1110 } | |
1111 | |
1112 void LoginDisplayHostImpl::OnLoginPromptVisible() { | |
1113 if (!login_prompt_visible_time_.is_null()) | |
1114 return; | |
1115 login_prompt_visible_time_ = base::TimeTicks::Now(); | |
1116 TryToPlayStartupSound(); | |
1117 } | |
1118 | |
1119 //////////////////////////////////////////////////////////////////////////////// | |
1120 // external | |
1121 | |
1122 // Declared in login_wizard.h so that others don't need to depend on our .h. | |
1123 // TODO(nkostylev): Split this into a smaller functions. | |
1124 void ShowLoginWizard(const std::string& first_screen_name) { | |
1125 if (browser_shutdown::IsTryingToQuit()) | |
1126 return; | |
1127 | |
1128 VLOG(1) << "Showing OOBE screen: " << first_screen_name; | |
1129 | |
1130 chromeos::input_method::InputMethodManager* manager = | |
1131 chromeos::input_method::InputMethodManager::Get(); | |
1132 | |
1133 // Set up keyboards. For example, when |locale| is "en-US", enable US qwerty | |
1134 // and US dvorak keyboard layouts. | |
1135 if (g_browser_process && g_browser_process->local_state()) { | |
1136 manager->SetInputMethodLoginDefault(); | |
1137 | |
1138 PrefService* prefs = g_browser_process->local_state(); | |
1139 // Apply owner preferences for tap-to-click and mouse buttons swap for | |
1140 // login screen. | |
1141 system::InputDeviceSettings::Get()->SetPrimaryButtonRight( | |
1142 prefs->GetBoolean(prefs::kOwnerPrimaryMouseButtonRight)); | |
1143 system::InputDeviceSettings::Get()->SetTapToClick( | |
1144 prefs->GetBoolean(prefs::kOwnerTapToClickEnabled)); | |
1145 } | |
1146 system::InputDeviceSettings::Get()->SetNaturalScroll( | |
1147 CommandLine::ForCurrentProcess()->HasSwitch( | |
1148 switches::kNaturalScrollDefault)); | |
1149 | |
1150 gfx::Rect screen_bounds(chromeos::CalculateScreenBounds(gfx::Size())); | |
1151 | |
1152 // Check whether we need to execute OOBE process. | |
1153 bool oobe_complete = chromeos::StartupUtils::IsOobeCompleted(); | |
1154 if (!oobe_complete) { | |
1155 LoginState::Get()->SetLoggedInState( | |
1156 LoginState::LOGGED_IN_OOBE, LoginState::LOGGED_IN_USER_NONE); | |
1157 } else { | |
1158 LoginState::Get()->SetLoggedInState( | |
1159 LoginState::LOGGED_IN_NONE, LoginState::LOGGED_IN_USER_NONE); | |
1160 } | |
1161 | |
1162 LoginDisplayHost* display_host = new LoginDisplayHostImpl(screen_bounds); | |
1163 | |
1164 bool show_app_launch_splash_screen = (first_screen_name == | |
1165 chromeos::WizardController::kAppLaunchSplashScreenName); | |
1166 if (show_app_launch_splash_screen) { | |
1167 const std::string& auto_launch_app_id = | |
1168 chromeos::KioskAppManager::Get()->GetAutoLaunchApp(); | |
1169 display_host->StartAppLaunch(auto_launch_app_id, | |
1170 false /* diagnostic_mode */); | |
1171 return; | |
1172 } | |
1173 | |
1174 policy::BrowserPolicyConnectorChromeOS* connector = | |
1175 g_browser_process->platform_part()->browser_policy_connector_chromeos(); | |
1176 bool should_show_enrollment_screen = | |
1177 first_screen_name.empty() && oobe_complete && | |
1178 chromeos::WizardController::ShouldAutoStartEnrollment() && | |
1179 !connector->IsEnterpriseManaged(); | |
1180 if (should_show_enrollment_screen) { | |
1181 // Shows networks screen instead of enrollment screen to resume the | |
1182 // interrupted auto start enrollment flow because enrollment screen does | |
1183 // not handle flaky network. See http://crbug.com/332572 | |
1184 display_host->StartWizard(chromeos::WizardController::kNetworkScreenName, | |
1185 scoped_ptr<base::DictionaryValue>()); | |
1186 return; | |
1187 } | |
1188 | |
1189 if (StartupUtils::IsEulaAccepted()) { | |
1190 DelayNetworkCall( | |
1191 ServicesCustomizationDocument::GetInstance() | |
1192 ->EnsureCustomizationAppliedClosure(), | |
1193 base::TimeDelta::FromMilliseconds(kDefaultNetworkRetryDelayMS)); | |
1194 } | |
1195 | |
1196 bool show_login_screen = | |
1197 (first_screen_name.empty() && oobe_complete) || | |
1198 first_screen_name == chromeos::WizardController::kLoginScreenName; | |
1199 | |
1200 if (show_login_screen) { | |
1201 // R11 > R12 migration fix. See http://crosbug.com/p/4898. | |
1202 // If user has manually changed locale during R11 OOBE, locale will be set. | |
1203 // On R12 > R12|R13 etc. this fix won't get activated since | |
1204 // OOBE process has set kApplicationLocale to non-default value. | |
1205 PrefService* prefs = g_browser_process->local_state(); | |
1206 if (!prefs->HasPrefPath(prefs::kApplicationLocale)) { | |
1207 std::string locale = chromeos::StartupUtils::GetInitialLocale(); | |
1208 prefs->SetString(prefs::kApplicationLocale, locale); | |
1209 manager->EnableLoginLayouts( | |
1210 locale, | |
1211 manager->GetInputMethodUtil()->GetHardwareInputMethodIds()); | |
1212 base::ThreadRestrictions::ScopedAllowIO allow_io; | |
1213 const std::string loaded_locale = | |
1214 ResourceBundle::GetSharedInstance().ReloadLocaleResources(locale); | |
1215 g_browser_process->SetApplicationLocale(loaded_locale); | |
1216 } | |
1217 display_host->StartSignInScreen(LoginScreenContext()); | |
1218 return; | |
1219 } | |
1220 | |
1221 // Load startup manifest. | |
1222 const chromeos::StartupCustomizationDocument* startup_manifest = | |
1223 chromeos::StartupCustomizationDocument::GetInstance(); | |
1224 | |
1225 // Switch to initial locale if specified by customization | |
1226 // and has not been set yet. We cannot call | |
1227 // chromeos::LanguageSwitchMenu::SwitchLanguage here before | |
1228 // EmitLoginPromptReady. | |
1229 PrefService* prefs = g_browser_process->local_state(); | |
1230 const std::string current_locale = | |
1231 prefs->GetString(prefs::kApplicationLocale); | |
1232 VLOG(1) << "Current locale: " << current_locale; | |
1233 std::string locale = startup_manifest->initial_locale_default(); | |
1234 | |
1235 std::string layout = startup_manifest->keyboard_layout(); | |
1236 VLOG(1) << "Initial locale: " << locale << "keyboard layout " << layout; | |
1237 | |
1238 // Determine keyboard layout from OEM customization (if provided) or | |
1239 // initial locale and save it in preferences. | |
1240 DetermineAndSaveHardwareKeyboard(locale, layout); | |
1241 | |
1242 if (!current_locale.empty() || locale.empty()) { | |
1243 ShowLoginWizardFinish(first_screen_name, startup_manifest, display_host); | |
1244 return; | |
1245 } | |
1246 | |
1247 // Save initial locale from VPD/customization manifest as current | |
1248 // Chrome locale. Otherwise it will be lost if Chrome restarts. | |
1249 // Don't need to schedule pref save because setting initial local | |
1250 // will enforce preference saving. | |
1251 prefs->SetString(prefs::kApplicationLocale, locale); | |
1252 chromeos::StartupUtils::SetInitialLocale(locale); | |
1253 | |
1254 scoped_ptr<ShowLoginWizardSwitchLanguageCallbackData> data( | |
1255 new ShowLoginWizardSwitchLanguageCallbackData( | |
1256 first_screen_name, startup_manifest, display_host)); | |
1257 | |
1258 scoped_ptr<locale_util::SwitchLanguageCallback> callback( | |
1259 new locale_util::SwitchLanguageCallback( | |
1260 base::Bind(&OnLanguageSwitchedCallback, base::Passed(data.Pass())))); | |
1261 | |
1262 // Load locale keyboards here. Hardware layout would be automatically enabled. | |
1263 locale_util::SwitchLanguage( | |
1264 locale, true, true /* login_layouts_only */, callback.Pass()); | |
1265 } | |
1266 | |
1267 } // namespace chromeos | |
OLD | NEW |