| 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 |