| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/chromeos/login/ui/login_display_host_webui.h" |
| |
| #include <utility> |
| #include <vector> |
| |
| #include "ash/accessibility/focus_ring_controller.h" |
| #include "ash/public/cpp/ash_features.h" |
| #include "ash/public/cpp/ash_pref_names.h" |
| #include "ash/public/cpp/shell_window_ids.h" |
| #include "ash/shell.h" |
| #include "ash/system/tray/system_tray.h" |
| #include "base/bind.h" |
| #include "base/command_line.h" |
| #include "base/location.h" |
| #include "base/logging.h" |
| #include "base/macros.h" |
| #include "base/single_thread_task_runner.h" |
| #include "base/strings/string_split.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/threading/thread_restrictions.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "base/time/time.h" |
| #include "base/trace_event/trace_event.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/chrome_notification_types.h" |
| #include "chrome/browser/chromeos/accessibility/accessibility_manager.h" |
| #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h" |
| #include "chrome/browser/chromeos/base/locale_util.h" |
| #include "chrome/browser/chromeos/boot_times_recorder.h" |
| #include "chrome/browser/chromeos/first_run/drive_first_run_controller.h" |
| #include "chrome/browser/chromeos/first_run/first_run.h" |
| #include "chrome/browser/chromeos/language_preferences.h" |
| #include "chrome/browser/chromeos/login/existing_user_controller.h" |
| #include "chrome/browser/chromeos/login/helper.h" |
| #include "chrome/browser/chromeos/login/login_wizard.h" |
| #include "chrome/browser/chromeos/login/screens/core_oobe_view.h" |
| #include "chrome/browser/chromeos/login/screens/gaia_view.h" |
| #include "chrome/browser/chromeos/login/startup_utils.h" |
| #include "chrome/browser/chromeos/login/ui/input_events_blocker.h" |
| #include "chrome/browser/chromeos/login/ui/login_display_host_mojo.h" |
| #include "chrome/browser/chromeos/login/ui/login_display_webui.h" |
| #include "chrome/browser/chromeos/login/ui/webui_login_view.h" |
| #include "chrome/browser/chromeos/login/wizard_controller.h" |
| #include "chrome/browser/chromeos/net/delay_network_call.h" |
| #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" |
| #include "chrome/browser/chromeos/policy/enrollment_config.h" |
| #include "chrome/browser/chromeos/profiles/profile_helper.h" |
| #include "chrome/browser/chromeos/settings/cros_settings.h" |
| #include "chrome/browser/chromeos/system/input_device_settings.h" |
| #include "chrome/browser/chromeos/system/timezone_resolver_manager.h" |
| #include "chrome/browser/chromeos/system/timezone_util.h" |
| #include "chrome/browser/lifetime/browser_shutdown.h" |
| #include "chrome/browser/profiles/profile_manager.h" |
| #include "chrome/browser/ui/ash/system_tray_client.h" |
| #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" |
| #include "chrome/common/chrome_constants.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "chrome/common/pref_names.h" |
| #include "chrome/grit/browser_resources.h" |
| #include "chromeos/audio/chromeos_sounds.h" |
| #include "chromeos/chromeos_constants.h" |
| #include "chromeos/chromeos_switches.h" |
| #include "chromeos/dbus/dbus_thread_manager.h" |
| #include "chromeos/dbus/session_manager_client.h" |
| #include "chromeos/login/login_state.h" |
| #include "chromeos/settings/cros_settings_names.h" |
| #include "chromeos/settings/cros_settings_provider.h" |
| #include "chromeos/settings/timezone_settings.h" |
| #include "chromeos/timezone/timezone_resolver.h" |
| #include "components/account_id/account_id.h" |
| #include "components/language/core/browser/pref_names.h" |
| #include "components/language/core/common/locale_util.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/session_manager/core/session_manager.h" |
| #include "components/user_manager/user.h" |
| #include "components/user_manager/user_manager.h" |
| #include "content/public/browser/notification_service.h" |
| #include "content/public/browser/notification_types.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/browser/web_ui.h" |
| #include "media/audio/sounds/sounds_manager.h" |
| #include "services/ui/public/cpp/property_type_converters.h" |
| #include "services/ui/public/interfaces/window_manager.mojom.h" |
| #include "ui/aura/window.h" |
| #include "ui/base/ime/chromeos/extension_ime_util.h" |
| #include "ui/base/ime/chromeos/input_method_manager.h" |
| #include "ui/base/ime/chromeos/input_method_util.h" |
| #include "ui/base/resource/resource_bundle.h" |
| #include "ui/base/ui_base_features.h" |
| #include "ui/compositor/compositor_observer.h" |
| #include "ui/compositor/layer.h" |
| #include "ui/compositor/layer_animation_observer.h" |
| #include "ui/compositor/scoped_layer_animation_settings.h" |
| #include "ui/display/display.h" |
| #include "ui/display/screen.h" |
| #include "ui/events/devices/input_device_manager.h" |
| #include "ui/events/event_handler.h" |
| #include "ui/events/event_utils.h" |
| #include "ui/gfx/geometry/rect.h" |
| #include "ui/gfx/geometry/size.h" |
| #include "ui/gfx/transform.h" |
| #include "ui/keyboard/keyboard_controller.h" |
| #include "ui/keyboard/keyboard_util.h" |
| #include "ui/views/focus/focus_manager.h" |
| #include "ui/views/widget/widget.h" |
| #include "ui/views/widget/widget_delegate.h" |
| #include "url/gurl.h" |
| |
| namespace { |
| |
| // Maximum delay for startup sound after 'loginPromptVisible' signal. |
| const int kStartupSoundMaxDelayMs = 2000; |
| |
| // URL which corresponds to the login WebUI. |
| const char kLoginURL[] = "chrome://oobe/login"; |
| |
| // URL which corresponds to the OOBE WebUI. |
| const char kOobeURL[] = "chrome://oobe/oobe"; |
| |
| // URL which corresponds to the user adding WebUI. |
| const char kUserAddingURL[] = "chrome://oobe/user-adding"; |
| |
| // URL which corresponds to the app launch splash WebUI. |
| const char kAppLaunchSplashURL[] = "chrome://oobe/app-launch-splash"; |
| |
| // URL which corresponds to the ARC kiosk splash WebUI. |
| const char kArcKioskSplashURL[] = "chrome://oobe/arc-kiosk-splash"; |
| |
| // Duration of sign-in transition animation. |
| const int kLoginFadeoutTransitionDurationMs = 700; |
| |
| // Number of times we try to reload OOBE/login WebUI if it crashes. |
| const int kCrashCountLimit = 5; |
| |
| // The default fade out animation time in ms. |
| const int kDefaultFadeTimeMs = 200; |
| |
| // Whether to enable tnitializing WebUI in hidden state (see |
| // |initialize_webui_hidden_|) by default. |
| const bool kHiddenWebUIInitializationDefault = true; |
| |
| // Switch values that might be used to override WebUI init type. |
| const char kWebUIInitParallel[] = "parallel"; |
| const char kWebUIInitPostpone[] = "postpone"; |
| |
| // A class to observe an implicit animation and invokes the callback after the |
| // animation is completed. |
| class AnimationObserver : public ui::ImplicitAnimationObserver { |
| public: |
| explicit AnimationObserver(const base::Closure& callback) |
| : callback_(callback) {} |
| ~AnimationObserver() override {} |
| |
| private: |
| // ui::ImplicitAnimationObserver implementation: |
| void OnImplicitAnimationsCompleted() override { |
| callback_.Run(); |
| delete this; |
| } |
| |
| base::Closure callback_; |
| |
| DISALLOW_COPY_AND_ASSIGN(AnimationObserver); |
| }; |
| |
| // Even if oobe is complete we may still want to show it, for example, if there |
| // are no users registered then the user may want to enterprise enroll. |
| bool IsOobeComplete() { |
| policy::BrowserPolicyConnectorChromeOS* connector = |
| g_browser_process->platform_part()->browser_policy_connector_chromeos(); |
| |
| // Oobe is completed and we have a user or we are enterprise enrolled. |
| return chromeos::StartupUtils::IsOobeCompleted() && |
| (!user_manager::UserManager::Get()->GetUsers().empty() || |
| connector->IsEnterpriseManaged()); |
| } |
| |
| // Returns true if signin (not oobe) should be displayed. |
| bool ShouldShowSigninScreen(chromeos::OobeScreen first_screen) { |
| return (first_screen == chromeos::OobeScreen::SCREEN_UNKNOWN && |
| IsOobeComplete()) || |
| first_screen == chromeos::OobeScreen::SCREEN_SPECIAL_LOGIN; |
| } |
| |
| // ShowLoginWizard is split into two parts. This function is sometimes called |
| // from TriggerShowLoginWizardFinish() directly, and sometimes from |
| // OnLanguageSwitchedCallback() |
| // (if locale was updated). |
| void ShowLoginWizardFinish( |
| chromeos::OobeScreen first_screen, |
| const chromeos::StartupCustomizationDocument* startup_manifest) { |
| TRACE_EVENT0("chromeos", "ShowLoginWizard::ShowLoginWizardFinish"); |
| |
| // TODO(crbug.com/781402): Move LoginDisplayHost creation out of |
| // LoginDisplayHostWebUI, it is not specific to a particular implementation. |
| |
| // Create the LoginDisplayHost. Use the views-based implementation only for |
| // the sign-in screen. |
| chromeos::LoginDisplayHost* display_host = nullptr; |
| if (chromeos::LoginDisplayHost::default_host()) { |
| // Tests may have already allocated an instance for us to use. |
| display_host = chromeos::LoginDisplayHost::default_host(); |
| } else if (ash::features::IsViewsLoginEnabled() && |
| ShouldShowSigninScreen(first_screen)) { |
| display_host = new chromeos::LoginDisplayHostMojo(); |
| } else { |
| display_host = new chromeos::LoginDisplayHostWebUI(); |
| } |
| |
| // Restore system timezone. |
| std::string timezone; |
| if (chromeos::system::PerUserTimezoneEnabled()) { |
| timezone = g_browser_process->local_state()->GetString( |
| prefs::kSigninScreenTimezone); |
| } |
| |
| if (ShouldShowSigninScreen(first_screen)) { |
| display_host->StartSignInScreen(chromeos::LoginScreenContext()); |
| } else { |
| display_host->StartWizard(first_screen); |
| |
| // Set initial timezone if specified by customization. |
| const std::string customization_timezone = |
| startup_manifest->initial_timezone(); |
| VLOG(1) << "Initial time zone: " << customization_timezone; |
| // Apply locale customizations only once to preserve whatever locale |
| // user has changed to during OOBE. |
| if (!customization_timezone.empty()) |
| timezone = customization_timezone; |
| } |
| if (!timezone.empty()) { |
| chromeos::system::SetSystemAndSigninScreenTimezone(timezone); |
| } |
| } |
| |
| struct ShowLoginWizardSwitchLanguageCallbackData { |
| explicit ShowLoginWizardSwitchLanguageCallbackData( |
| chromeos::OobeScreen first_screen, |
| const chromeos::StartupCustomizationDocument* startup_manifest) |
| : first_screen(first_screen), startup_manifest(startup_manifest) {} |
| |
| const chromeos::OobeScreen first_screen; |
| const chromeos::StartupCustomizationDocument* const startup_manifest; |
| |
| // lock UI while resource bundle is being reloaded. |
| chromeos::InputEventsBlocker events_blocker; |
| }; |
| |
| void OnLanguageSwitchedCallback( |
| std::unique_ptr<ShowLoginWizardSwitchLanguageCallbackData> self, |
| const chromeos::locale_util::LanguageSwitchResult& result) { |
| if (!result.success) |
| LOG(WARNING) << "Locale could not be found for '" << result.requested_locale |
| << "'"; |
| |
| ShowLoginWizardFinish(self->first_screen, self->startup_manifest); |
| } |
| |
| // Triggers ShowLoginWizardFinish directly if no locale switch is required |
| // (|switch_locale| is empty) or after a locale switch otherwise. |
| void TriggerShowLoginWizardFinish( |
| std::string switch_locale, |
| std::unique_ptr<ShowLoginWizardSwitchLanguageCallbackData> data) { |
| if (switch_locale.empty()) { |
| ShowLoginWizardFinish(data->first_screen, data->startup_manifest); |
| } else { |
| chromeos::locale_util::SwitchLanguageCallback callback( |
| base::Bind(&OnLanguageSwitchedCallback, base::Passed(std::move(data)))); |
| |
| // Load locale keyboards here. Hardware layout would be automatically |
| // enabled. |
| chromeos::locale_util::SwitchLanguage( |
| switch_locale, true, true /* login_layouts_only */, callback, |
| ProfileManager::GetActiveUserProfile()); |
| } |
| } |
| |
| // Returns the login screen locale mandated by device policy, or an empty string |
| // if no policy-specified locale is set. |
| std::string GetManagedLoginScreenLocale() { |
| chromeos::CrosSettings* cros_settings = chromeos::CrosSettings::Get(); |
| const base::ListValue* login_screen_locales = nullptr; |
| if (!cros_settings->GetList(chromeos::kDeviceLoginScreenLocales, |
| &login_screen_locales)) |
| return std::string(); |
| |
| // Currently, only the first element is used. The setting is a list for future |
| // compatibility, if dynamically switching locales on the login screen will be |
| // implemented. |
| std::string login_screen_locale; |
| if (login_screen_locales->empty() || |
| !login_screen_locales->GetString(0, &login_screen_locale)) |
| return std::string(); |
| |
| return login_screen_locale; |
| } |
| |
| // Disables virtual keyboard overscroll. Login UI will scroll user pods |
| // into view on JS side when virtual keyboard is shown. |
| void DisableKeyboardOverscroll() { |
| keyboard::SetKeyboardOverscrollOverride( |
| keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_DISABLED); |
| } |
| |
| void ResetKeyboardOverscrollOverride() { |
| keyboard::SetKeyboardOverscrollOverride( |
| keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_NONE); |
| } |
| |
| class CloseAfterCommit : public ui::CompositorObserver, |
| public views::WidgetObserver { |
| public: |
| explicit CloseAfterCommit(views::Widget* widget) : widget_(widget) { |
| widget->GetCompositor()->AddObserver(this); |
| widget_->AddObserver(this); |
| } |
| ~CloseAfterCommit() override { |
| widget_->RemoveObserver(this); |
| widget_->GetCompositor()->RemoveObserver(this); |
| } |
| |
| // ui::CompositorObserver: |
| void OnCompositingDidCommit(ui::Compositor* compositor) override { |
| DCHECK_EQ(widget_->GetCompositor(), compositor); |
| widget_->Close(); |
| } |
| |
| void OnCompositingStarted(ui::Compositor* compositor, |
| base::TimeTicks start_time) override {} |
| void OnCompositingEnded(ui::Compositor* compositor) override {} |
| void OnCompositingLockStateChanged(ui::Compositor* compositor) override {} |
| void OnCompositingChildResizing(ui::Compositor* compositor) override {} |
| void OnCompositingShuttingDown(ui::Compositor* compositor) override {} |
| |
| // views::WidgetObserver: |
| void OnWidgetDestroying(views::Widget* widget) override { |
| DCHECK_EQ(widget, widget_); |
| delete this; |
| } |
| |
| private: |
| views::Widget* const widget_; |
| |
| DISALLOW_COPY_AND_ASSIGN(CloseAfterCommit); |
| }; |
| |
| } // namespace |
| |
| namespace chromeos { |
| |
| // static |
| const int LoginDisplayHostWebUI::kShowLoginWebUIid = 0x1111; |
| |
| // A class to handle special menu key for keyboard driven OOBE. |
| class LoginDisplayHostWebUI::KeyboardDrivenOobeKeyHandler |
| : public ui::EventHandler { |
| public: |
| KeyboardDrivenOobeKeyHandler() { |
| ash::Shell::Get()->AddPreTargetHandler(this); |
| } |
| ~KeyboardDrivenOobeKeyHandler() override { |
| ash::Shell::Get()->RemovePreTargetHandler(this); |
| } |
| |
| private: |
| // ui::EventHandler |
| void OnKeyEvent(ui::KeyEvent* event) override { |
| if (event->key_code() == ui::VKEY_F6) { |
| SystemTrayClient::Get()->SetPrimaryTrayVisible(false); |
| event->StopPropagation(); |
| } |
| } |
| |
| DISALLOW_COPY_AND_ASSIGN(KeyboardDrivenOobeKeyHandler); |
| }; |
| |
| // A login implementation of WidgetDelegate. |
| class LoginDisplayHostWebUI::LoginWidgetDelegate |
| : public views::WidgetDelegate { |
| public: |
| LoginWidgetDelegate(views::Widget* widget, LoginDisplayHostWebUI* host) |
| : widget_(widget), login_display_host_(host) { |
| DCHECK(widget_); |
| DCHECK(login_display_host_); |
| } |
| ~LoginWidgetDelegate() override {} |
| |
| void LoginDisplayHostDestroyed() { login_display_host_ = nullptr; } |
| |
| // Overridden from WidgetDelegate: |
| void WindowClosing() override { |
| // Reset the cached Widget and View pointers. The Widget may close due to: |
| // * Login completion |
| // * Ash crash at the login screen on mustash |
| // In the latter case the mash root process will trigger a clean restart |
| // of content_browser. |
| if (!features::IsAshInBrowserProcess() && login_display_host_) |
| login_display_host_->ResetLoginWindowAndView(); |
| } |
| void DeleteDelegate() override { delete this; } |
| views::Widget* GetWidget() override { return widget_; } |
| const views::Widget* GetWidget() const override { return widget_; } |
| bool CanActivate() const override { return true; } |
| bool ShouldAdvanceFocusToTopLevelWidget() const override { return true; } |
| |
| private: |
| views::Widget* widget_; |
| // Set to null if LoginDisplayHostWebUI is destroyed before us. |
| LoginDisplayHostWebUI* login_display_host_; |
| |
| DISALLOW_COPY_AND_ASSIGN(LoginWidgetDelegate); |
| }; |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // LoginDisplayHostWebUI, public |
| |
| LoginDisplayHostWebUI::LoginDisplayHostWebUI() |
| : oobe_startup_sound_played_(StartupUtils::IsOobeCompleted()), |
| weak_factory_(this) { |
| if (!features::IsAshInBrowserProcess()) { |
| // Animation, and initializing hidden, are not currently supported for Mash. |
| finalize_animation_type_ = ANIMATION_NONE; |
| initialize_webui_hidden_ = false; |
| } |
| |
| DBusThreadManager::Get()->GetSessionManagerClient()->AddObserver(this); |
| CrasAudioHandler::Get()->AddAudioObserver(this); |
| |
| display::Screen::GetScreen()->AddObserver(this); |
| |
| ui::InputDeviceManager::GetInstance()->AddObserver(this); |
| |
| // Login screen is moved to lock screen container when user logs in. |
| registrar_.Add(this, chrome::NOTIFICATION_LOGIN_USER_CHANGED, |
| content::NotificationService::AllSources()); |
| |
| bool zero_delay_enabled = WizardController::IsZeroDelayEnabled(); |
| // Mash always runs login screen with zero delay |
| if (!features::IsAshInBrowserProcess()) |
| zero_delay_enabled = true; |
| |
| waiting_for_wallpaper_load_ = !zero_delay_enabled; |
| |
| // Initializing hidden is not supported in Mash |
| if (features::IsAshInBrowserProcess()) { |
| initialize_webui_hidden_ = |
| kHiddenWebUIInitializationDefault && !zero_delay_enabled; |
| } |
| |
| // Check if WebUI init type is overriden. Not supported in Mash. |
| if (features::IsAshInBrowserProcess() && |
| base::CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kAshWebUIInit)) { |
| const std::string override_type = |
| base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
| switches::kAshWebUIInit); |
| if (override_type == kWebUIInitParallel) |
| initialize_webui_hidden_ = true; |
| else if (override_type == kWebUIInitPostpone) |
| initialize_webui_hidden_ = false; |
| } |
| |
| // Always postpone WebUI initialization on first boot, otherwise we miss |
| // initial animation. |
| if (!StartupUtils::IsOobeCompleted()) |
| initialize_webui_hidden_ = false; |
| |
| if (waiting_for_wallpaper_load_) { |
| registrar_.Add(this, chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED, |
| content::NotificationService::AllSources()); |
| } |
| |
| // When we wait for WebUI to be initialized we wait for one of |
| // these notifications. |
| if (waiting_for_wallpaper_load_ && initialize_webui_hidden_) { |
| registrar_.Add(this, chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE, |
| content::NotificationService::AllSources()); |
| registrar_.Add(this, chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN, |
| content::NotificationService::AllSources()); |
| } |
| VLOG(1) << "Login WebUI >> " |
| << "zero_delay: " << zero_delay_enabled |
| << " wait_for_wp_load_: " << waiting_for_wallpaper_load_ |
| << " init_webui_hidden_: " << initialize_webui_hidden_; |
| |
| media::SoundsManager* manager = media::SoundsManager::Get(); |
| ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); |
| manager->Initialize(SOUND_STARTUP, |
| bundle.GetRawDataResource(IDR_SOUND_STARTUP_WAV)); |
| |
| login_display_ = std::make_unique<LoginDisplayWebUI>(); |
| } |
| |
| LoginDisplayHostWebUI::~LoginDisplayHostWebUI() { |
| DBusThreadManager::Get()->GetSessionManagerClient()->RemoveObserver(this); |
| CrasAudioHandler::Get()->RemoveAudioObserver(this); |
| display::Screen::GetScreen()->RemoveObserver(this); |
| |
| ui::InputDeviceManager::GetInstance()->RemoveObserver(this); |
| |
| if (login_view_ && login_window_) |
| login_window_->RemoveRemovalsObserver(this); |
| |
| if (login_window_delegate_) |
| login_window_delegate_->LoginDisplayHostDestroyed(); |
| |
| MultiUserWindowManager* window_manager = |
| MultiUserWindowManager::GetInstance(); |
| // MultiUserWindowManager instance might be null if no user is logged in - or |
| // in a unit test. |
| if (window_manager) |
| window_manager->RemoveObserver(this); |
| |
| ResetKeyboardOverscrollOverride(); |
| |
| views::FocusManager::set_arrow_key_traversal_enabled(false); |
| ResetLoginWindowAndView(); |
| |
| // TODO(tengs): This should be refactored. See crbug.com/314934. |
| if (user_manager::UserManager::Get()->IsCurrentUserNew()) { |
| // DriveOptInController will delete itself when finished. |
| (new DriveFirstRunController(ProfileManager::GetActiveUserProfile())) |
| ->EnableOfflineMode(); |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // LoginDisplayHostWebUI, LoginDisplayHost: |
| |
| LoginDisplay* LoginDisplayHostWebUI::GetLoginDisplay() { |
| return login_display_.get(); |
| } |
| |
| gfx::NativeWindow LoginDisplayHostWebUI::GetNativeWindow() const { |
| return login_window_ ? login_window_->GetNativeWindow() : nullptr; |
| } |
| |
| WebUILoginView* LoginDisplayHostWebUI::GetWebUILoginView() const { |
| return login_view_; |
| } |
| |
| void LoginDisplayHostWebUI::OnFinalize() { |
| DVLOG(1) << "Finalizing LoginDisplayHost. User session starting"; |
| |
| switch (finalize_animation_type_) { |
| case ANIMATION_NONE: |
| ShutdownDisplayHost(); |
| break; |
| case ANIMATION_WORKSPACE: |
| if (ash::Shell::HasInstance()) |
| ScheduleWorkspaceAnimation(); |
| |
| ShutdownDisplayHost(); |
| break; |
| case ANIMATION_FADE_OUT: |
| // Display host is deleted once animation is completed |
| // since sign in screen widget has to stay alive. |
| ScheduleFadeOutAnimation(kDefaultFadeTimeMs); |
| break; |
| case ANIMATION_ADD_USER: |
| // Defer the deletion of LoginDisplayHost instance until the user adding |
| // animation (which is done by UserSwitchAnimatorChromeOS) is finished. |
| // This is to guarantee OnUserSwitchAnimationFinished() is called before |
| // LoginDisplayHost deletes itself. |
| // See crbug.com/541864. |
| break; |
| default: |
| break; |
| } |
| } |
| |
| void LoginDisplayHostWebUI::SetStatusAreaVisible(bool visible) { |
| if (initialize_webui_hidden_) |
| status_area_saved_visibility_ = visible; |
| else if (login_view_) |
| login_view_->SetStatusAreaVisible(visible); |
| } |
| |
| void LoginDisplayHostWebUI::StartWizard(OobeScreen first_screen) { |
| DisableKeyboardOverscroll(); |
| |
| TryToPlayOobeStartupSound(); |
| |
| // Keep parameters to restore if renderer crashes. |
| restore_path_ = RESTORE_WIZARD; |
| first_screen_ = first_screen; |
| is_showing_login_ = false; |
| |
| if (waiting_for_wallpaper_load_ && !initialize_webui_hidden_) { |
| VLOG(1) << "Login WebUI >> wizard postponed"; |
| return; |
| } |
| VLOG(1) << "Login WebUI >> wizard"; |
| |
| if (!login_window_) |
| LoadURL(GURL(kOobeURL)); |
| |
| DVLOG(1) << "Starting wizard, first_screen: " |
| << GetOobeScreenName(first_screen); |
| // Create and show the wizard. |
| // Note, dtor of the old WizardController should be called before ctor of the |
| // new one, because "default_controller()" is updated there. So pure "reset()" |
| // is done before new controller creation. |
| wizard_controller_.reset(); |
| wizard_controller_.reset(CreateWizardController()); |
| |
| oobe_progress_bar_visible_ = !StartupUtils::IsDeviceRegistered(); |
| SetOobeProgressBarVisible(oobe_progress_bar_visible_); |
| wizard_controller_->Init(first_screen); |
| } |
| |
| WizardController* LoginDisplayHostWebUI::GetWizardController() { |
| return wizard_controller_.get(); |
| } |
| |
| void LoginDisplayHostWebUI::OnStartUserAdding() { |
| DisableKeyboardOverscroll(); |
| |
| restore_path_ = RESTORE_ADD_USER_INTO_SESSION; |
| // Animation is not supported in Mash |
| if (features::IsAshInBrowserProcess()) |
| finalize_animation_type_ = ANIMATION_ADD_USER; |
| // Observe the user switch animation and defer the deletion of itself only |
| // after the animation is finished. |
| MultiUserWindowManager* window_manager = |
| MultiUserWindowManager::GetInstance(); |
| // MultiUserWindowManager instance might be nullptr in a unit test. |
| if (window_manager) |
| window_manager->AddObserver(this); |
| |
| VLOG(1) << "Login WebUI >> user adding"; |
| if (!login_window_) |
| LoadURL(GURL(kUserAddingURL)); |
| // We should emit this signal only at login screen (after reboot or sign out). |
| login_view_->set_should_emit_login_prompt_visible(false); |
| |
| if (features::IsAshInBrowserProcess()) { |
| // Lock container can be transparent after lock screen animation. |
| aura::Window* lock_container = ash::Shell::GetContainer( |
| ash::Shell::GetPrimaryRootWindow(), |
| ash::kShellWindowId_LockScreenContainersContainer); |
| lock_container->layer()->SetOpacity(1.0); |
| } else { |
| NOTIMPLEMENTED(); |
| } |
| |
| CreateExistingUserController(); |
| |
| if (!signin_screen_controller_.get()) { |
| signin_screen_controller_.reset(new SignInScreenController(GetOobeUI())); |
| } |
| |
| SetOobeProgressBarVisible(oobe_progress_bar_visible_ = false); |
| SetStatusAreaVisible(true); |
| existing_user_controller_->Init( |
| user_manager::UserManager::Get()->GetUsersAllowedForMultiProfile()); |
| CHECK(login_display_); |
| GetOobeUI()->ShowSigninScreen(LoginScreenContext(), login_display_.get(), |
| login_display_.get()); |
| } |
| |
| void LoginDisplayHostWebUI::CancelUserAdding() { |
| // ANIMATION_ADD_USER observes UserSwitchAnimatorChromeOS to shutdown the |
| // login display host. However, the animation does not run when user adding is |
| // canceled. Changing to ANIMATION_NONE so that Finalize() shuts down the host |
| // immediately. |
| finalize_animation_type_ = ANIMATION_NONE; |
| Finalize(base::OnceClosure()); |
| } |
| |
| void LoginDisplayHostWebUI::OnStartSignInScreen( |
| const LoginScreenContext& context) { |
| DisableKeyboardOverscroll(); |
| |
| restore_path_ = RESTORE_SIGN_IN; |
| is_showing_login_ = true; |
| // Animation is not supported in Mash |
| if (features::IsAshInBrowserProcess()) |
| finalize_animation_type_ = ANIMATION_WORKSPACE; |
| |
| if (waiting_for_wallpaper_load_ && !initialize_webui_hidden_) { |
| VLOG(1) << "Login WebUI >> sign in postponed"; |
| return; |
| } |
| VLOG(1) << "Login WebUI >> sign in"; |
| |
| // TODO(crbug.com/784495): Make sure this is ported to views. |
| if (!login_window_) { |
| TRACE_EVENT_ASYNC_BEGIN0("ui", "ShowLoginWebUI", kShowLoginWebUIid); |
| TRACE_EVENT_ASYNC_STEP_INTO0("ui", "ShowLoginWebUI", kShowLoginWebUIid, |
| "StartSignInScreen"); |
| BootTimesRecorder::Get()->RecordCurrentStats("login-start-signin-screen"); |
| LoadURL(GURL(kLoginURL)); |
| } |
| |
| DVLOG(1) << "Starting sign in screen"; |
| CreateExistingUserController(); |
| |
| if (!signin_screen_controller_.get()) { |
| signin_screen_controller_.reset(new SignInScreenController(GetOobeUI())); |
| } |
| |
| // TODO(crbug.com/784495): This is always false, since |
| // LoginDisplayHost::StartSignInScreen marks the device as registered. |
| oobe_progress_bar_visible_ = !StartupUtils::IsDeviceRegistered(); |
| SetOobeProgressBarVisible(oobe_progress_bar_visible_); |
| existing_user_controller_->Init(user_manager::UserManager::Get()->GetUsers()); |
| |
| CHECK(login_display_); |
| GetOobeUI()->ShowSigninScreen(context, login_display_.get(), |
| login_display_.get()); |
| TRACE_EVENT_ASYNC_STEP_INTO0("ui", "ShowLoginWebUI", kShowLoginWebUIid, |
| "WaitForScreenStateInitialize"); |
| |
| // TODO(crbug.com/784495): Make sure this is ported to views. |
| BootTimesRecorder::Get()->RecordCurrentStats( |
| "login-wait-for-signin-state-initialize"); |
| } |
| |
| void LoginDisplayHostWebUI::OnPreferencesChanged() { |
| if (is_showing_login_) |
| login_display_->OnPreferencesChanged(); |
| } |
| |
| void LoginDisplayHostWebUI::OnStartAppLaunch() { |
| // Animation is not supported in Mash. |
| if (features::IsAshInBrowserProcess()) |
| finalize_animation_type_ = ANIMATION_FADE_OUT; |
| if (!login_window_) |
| LoadURL(GURL(kAppLaunchSplashURL)); |
| |
| login_view_->set_should_emit_login_prompt_visible(false); |
| } |
| |
| void LoginDisplayHostWebUI::OnStartArcKiosk() { |
| // Animation is not supported in Mash. |
| if (features::IsAshInBrowserProcess()) |
| finalize_animation_type_ = ANIMATION_FADE_OUT; |
| if (!login_window_) { |
| LoadURL(GURL(kAppLaunchSplashURL)); |
| LoadURL(GURL(kArcKioskSplashURL)); |
| } |
| |
| login_view_->set_should_emit_login_prompt_visible(false); |
| } |
| |
| bool LoginDisplayHostWebUI::IsVoiceInteractionOobe() { |
| return is_voice_interaction_oobe_; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // LoginDisplayHostWebUI, public |
| |
| WizardController* LoginDisplayHostWebUI::CreateWizardController() { |
| // TODO(altimofeev): ensure that WebUI is ready. |
| OobeUI* oobe_ui = GetOobeUI(); |
| return new WizardController(this, oobe_ui); |
| } |
| |
| void LoginDisplayHostWebUI::OnBrowserCreated() { |
| // Close lock window now so that the launched browser can receive focus. |
| ResetLoginWindowAndView(); |
| } |
| |
| OobeUI* LoginDisplayHostWebUI::GetOobeUI() const { |
| if (!login_view_) |
| return nullptr; |
| return login_view_->GetOobeUI(); |
| } |
| |
| content::WebContents* LoginDisplayHostWebUI::GetOobeWebContents() const { |
| if (!login_view_) |
| return nullptr; |
| return login_view_->GetWebContents(); |
| } |
| //////////////////////////////////////////////////////////////////////////////// |
| // LoginDisplayHostWebUI, content:NotificationObserver: |
| |
| void LoginDisplayHostWebUI::Observe( |
| int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| LoginDisplayHostCommon::Observe(type, source, details); |
| |
| if (chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE == type || |
| chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN == type) { |
| VLOG(1) << "Login WebUI >> WEBUI_VISIBLE"; |
| if (waiting_for_wallpaper_load_ && initialize_webui_hidden_) { |
| // Reduce time till login UI is shown - show it as soon as possible. |
| waiting_for_wallpaper_load_ = false; |
| ShowWebUI(); |
| } |
| registrar_.Remove(this, chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE, |
| content::NotificationService::AllSources()); |
| registrar_.Remove(this, chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN, |
| content::NotificationService::AllSources()); |
| } else if (type == chrome::NOTIFICATION_LOGIN_USER_CHANGED && |
| user_manager::UserManager::Get()->IsCurrentUserNew()) { |
| registrar_.Remove(this, chrome::NOTIFICATION_LOGIN_USER_CHANGED, |
| content::NotificationService::AllSources()); |
| } else if (chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED == type) { |
| VLOG(1) << "Login WebUI >> wp animation done"; |
| is_wallpaper_loaded_ = true; |
| if (waiting_for_wallpaper_load_) { |
| // StartWizard / StartSignInScreen could be called multiple times through |
| // the lifetime of host. |
| // Make sure that subsequent calls are not postponed. |
| waiting_for_wallpaper_load_ = false; |
| if (initialize_webui_hidden_) { |
| // If we're in the process of switching locale, the wallpaper might |
| // have finished loading before the locale switch was completed. |
| // Only show the UI if it already exists. |
| if (login_window_ && login_view_) |
| ShowWebUI(); |
| } else { |
| StartPostponedWebUI(); |
| } |
| } |
| registrar_.Remove(this, chrome::NOTIFICATION_WALLPAPER_ANIMATION_FINISHED, |
| content::NotificationService::AllSources()); |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // LoginDisplayHostWebUI, WebContentsObserver: |
| |
| void LoginDisplayHostWebUI::RenderProcessGone(base::TerminationStatus status) { |
| // Do not try to restore on shutdown |
| if (browser_shutdown::GetShutdownType() != browser_shutdown::NOT_VALID) |
| return; |
| |
| crash_count_++; |
| if (crash_count_ > kCrashCountLimit) |
| return; |
| |
| if (status != base::TERMINATION_STATUS_NORMAL_TERMINATION) { |
| // Render with login screen crashed. Let's crash browser process to let |
| // session manager restart it properly. It is hard to reload the page |
| // and get to controlled state that is fully functional. |
| // If you see check, search for renderer crash for the same client. |
| LOG(FATAL) << "Renderer crash on login window"; |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // LoginDisplayHostWebUI, chromeos::SessionManagerClient::Observer: |
| |
| void LoginDisplayHostWebUI::EmitLoginPromptVisibleCalled() { |
| OnLoginPromptVisible(); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // LoginDisplayHostWebUI, chromeos::CrasAudioHandler::AudioObserver: |
| |
| void LoginDisplayHostWebUI::OnActiveOutputNodeChanged() { |
| TryToPlayOobeStartupSound(); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // LoginDisplayHostWebUI, display::DisplayObserver: |
| |
| void LoginDisplayHostWebUI::OnDisplayAdded( |
| const display::Display& new_display) { |
| if (GetOobeUI()) |
| GetOobeUI()->OnDisplayConfigurationChanged(); |
| } |
| |
| void LoginDisplayHostWebUI::OnDisplayMetricsChanged( |
| const display::Display& display, |
| uint32_t changed_metrics) { |
| const display::Display primary_display = |
| display::Screen::GetScreen()->GetPrimaryDisplay(); |
| if (display.id() != primary_display.id() || |
| !(changed_metrics & DISPLAY_METRIC_BOUNDS)) { |
| return; |
| } |
| |
| if (GetOobeUI()) { |
| // Reset widget size for voice interaction OOBE, since the screen rotation |
| // will break the widget size if it is not full screen. |
| if (is_voice_interaction_oobe_) |
| login_window_->SetSize(primary_display.work_area_size()); |
| |
| const gfx::Size& size = primary_display.size(); |
| GetOobeUI()->GetCoreOobeView()->SetClientAreaSize(size.width(), |
| size.height()); |
| |
| if (changed_metrics & DISPLAY_METRIC_PRIMARY) |
| GetOobeUI()->OnDisplayConfigurationChanged(); |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // LoginDisplayHostWebUI, ui::InputDeviceEventObserver |
| void LoginDisplayHostWebUI::OnTouchscreenDeviceConfigurationChanged() { |
| if (GetOobeUI()) |
| GetOobeUI()->OnDisplayConfigurationChanged(); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // LoginDisplayHostWebUI, views::WidgetRemovalsObserver: |
| void LoginDisplayHostWebUI::OnWillRemoveView(views::Widget* widget, |
| views::View* view) { |
| if (view != static_cast<views::View*>(login_view_)) |
| return; |
| login_view_ = nullptr; |
| widget->RemoveRemovalsObserver(this); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // LoginDisplayHostWebUI, MultiUserWindowManager::Observer: |
| void LoginDisplayHostWebUI::OnUserSwitchAnimationFinished() { |
| ShutdownDisplayHost(); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // LoginDisplayHostWebUI, private |
| |
| void LoginDisplayHostWebUI::ScheduleWorkspaceAnimation() { |
| if (!features::IsAshInBrowserProcess()) { |
| NOTIMPLEMENTED(); |
| return; |
| } |
| |
| if (!base::CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kDisableLoginAnimations)) { |
| ash::Shell::Get()->DoInitialWorkspaceAnimation(); |
| } |
| } |
| |
| void LoginDisplayHostWebUI::ScheduleFadeOutAnimation(int animation_speed_ms) { |
| // login window might have been closed by OnBrowserCreated() at this moment. |
| // This may happen when adding another user into the session, and a browser |
| // is created before session start, which triggers the close of the login |
| // window. In this case, we should shut down the display host directly. |
| if (!login_window_) { |
| ShutdownDisplayHost(); |
| return; |
| } |
| ui::Layer* layer = login_window_->GetLayer(); |
| ui::ScopedLayerAnimationSettings animation(layer->GetAnimator()); |
| animation.AddObserver(new AnimationObserver( |
| base::Bind(&LoginDisplayHostWebUI::ShutdownDisplayHost, |
| weak_factory_.GetWeakPtr()))); |
| animation.SetTransitionDuration( |
| base::TimeDelta::FromMilliseconds(animation_speed_ms)); |
| layer->SetOpacity(0); |
| } |
| |
| void LoginDisplayHostWebUI::LoadURL(const GURL& url) { |
| InitLoginWindowAndView(); |
| // Subscribe to crash events. |
| content::WebContentsObserver::Observe(login_view_->GetWebContents()); |
| login_view_->LoadURL(url); |
| } |
| |
| void LoginDisplayHostWebUI::ShowWebUI() { |
| if (!login_window_ || !login_view_) { |
| NOTREACHED(); |
| return; |
| } |
| VLOG(1) << "Login WebUI >> Show already initialized UI"; |
| login_window_->Show(); |
| login_view_->GetWebContents()->Focus(); |
| login_view_->SetStatusAreaVisible(status_area_saved_visibility_); |
| login_view_->OnPostponedShow(); |
| |
| // We should reset this flag to allow changing of status area visibility. |
| initialize_webui_hidden_ = false; |
| } |
| |
| void LoginDisplayHostWebUI::StartPostponedWebUI() { |
| if (!is_wallpaper_loaded_) { |
| NOTREACHED(); |
| return; |
| } |
| VLOG(1) << "Login WebUI >> Init postponed WebUI"; |
| |
| // Wallpaper has finished loading before StartWizard/StartSignInScreen has |
| // been called. In general this should not happen. |
| // Let go through normal code path when one of those will be called. |
| if (restore_path_ == RESTORE_UNKNOWN) { |
| NOTREACHED(); |
| return; |
| } |
| |
| switch (restore_path_) { |
| case RESTORE_WIZARD: |
| StartWizard(first_screen_); |
| break; |
| case RESTORE_SIGN_IN: |
| StartSignInScreen(LoginScreenContext()); |
| break; |
| case RESTORE_ADD_USER_INTO_SESSION: |
| StartUserAdding(base::OnceClosure()); |
| break; |
| default: |
| NOTREACHED(); |
| break; |
| } |
| } |
| |
| void LoginDisplayHostWebUI::InitLoginWindowAndView() { |
| if (login_window_) |
| return; |
| |
| if (system::InputDeviceSettings::Get()->ForceKeyboardDrivenUINavigation()) { |
| views::FocusManager::set_arrow_key_traversal_enabled(true); |
| // crbug.com/405859 |
| focus_ring_controller_ = std::make_unique<ash::FocusRingController>(); |
| focus_ring_controller_->SetVisible(true); |
| |
| keyboard_driven_oobe_key_handler_.reset(new KeyboardDrivenOobeKeyHandler); |
| } |
| |
| views::Widget::InitParams params( |
| views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); |
| params.bounds = CalculateScreenBounds(gfx::Size()); |
| // Disable fullscreen state for voice interaction OOBE since the shelf should |
| // be visible. |
| if (!is_voice_interaction_oobe_) |
| params.show_state = ui::SHOW_STATE_FULLSCREEN; |
| params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; |
| |
| // Put the voice interaction oobe inside AlwaysOnTop container instead of |
| // LockScreenContainer. |
| ash::ShellWindowId container = is_voice_interaction_oobe_ |
| ? ash::kShellWindowId_AlwaysOnTopContainer |
| : ash::kShellWindowId_LockScreenContainer; |
| // The ash::Shell containers are not available in Mash |
| if (features::IsAshInBrowserProcess()) { |
| params.parent = |
| ash::Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(), container); |
| } else { |
| using ui::mojom::WindowManager; |
| params.mus_properties[WindowManager::kContainerId_InitProperty] = |
| mojo::ConvertTo<std::vector<uint8_t>>(static_cast<int32_t>(container)); |
| } |
| login_window_ = new views::Widget; |
| params.delegate = login_window_delegate_ = |
| new LoginWidgetDelegate(login_window_, this); |
| login_window_->Init(params); |
| |
| login_view_ = new WebUILoginView(WebUILoginView::WebViewSettings()); |
| login_view_->Init(); |
| if (login_view_->webui_visible()) |
| OnLoginPromptVisible(); |
| |
| // Animations are not available in Mash. |
| // For voice interaction OOBE, we do not want the animation here. |
| if (features::IsAshInBrowserProcess() && !is_voice_interaction_oobe_) { |
| login_window_->SetVisibilityAnimationDuration( |
| base::TimeDelta::FromMilliseconds(kLoginFadeoutTransitionDurationMs)); |
| login_window_->SetVisibilityAnimationTransition( |
| views::Widget::ANIMATE_HIDE); |
| } |
| |
| login_window_->AddRemovalsObserver(this); |
| login_window_->SetContentsView(login_view_); |
| |
| // If WebUI is initialized in hidden state, show it only if we're no |
| // longer waiting for wallpaper animation/user images loading. Otherwise, |
| // always show it. |
| if (!initialize_webui_hidden_ || !waiting_for_wallpaper_load_) { |
| VLOG(1) << "Login WebUI >> show login wnd on create"; |
| login_window_->Show(); |
| } else { |
| VLOG(1) << "Login WebUI >> login wnd is hidden on create"; |
| login_view_->set_is_hidden(true); |
| } |
| login_window_->GetNativeView()->SetName("WebUILoginView"); |
| } |
| |
| void LoginDisplayHostWebUI::ResetLoginWindowAndView() { |
| // Make sure to reset the |login_view_| pointer first; it is owned by |
| // |login_window_|. Closing |login_window_| could immediately invalidate the |
| // |login_view_| pointer. |
| if (login_view_) { |
| login_view_->SetUIEnabled(true); |
| login_view_ = nullptr; |
| } |
| |
| if (login_window_) { |
| if (!features::IsAshInBrowserProcess()) { |
| login_window_->Close(); |
| } else { |
| login_window_->Hide(); |
| // This CompositorObserver becomes "owned" by login_window_ after |
| // construction and will delete itself once login_window_ is destroyed. |
| new CloseAfterCommit(login_window_); |
| } |
| login_window_->RemoveRemovalsObserver(this); |
| login_window_ = nullptr; |
| login_window_delegate_ = nullptr; |
| } |
| |
| // Release wizard controller with the webui and hosting window so that it |
| // does not find missing webui handlers in surprise. |
| wizard_controller_.reset(); |
| } |
| |
| void LoginDisplayHostWebUI::SetOobeProgressBarVisible(bool visible) { |
| GetOobeUI()->ShowOobeUI(visible); |
| } |
| |
| void LoginDisplayHostWebUI::TryToPlayOobeStartupSound() { |
| if (is_voice_interaction_oobe_) |
| return; |
| |
| if (oobe_startup_sound_played_ || login_prompt_visible_time_.is_null() || |
| !CrasAudioHandler::Get()->GetPrimaryActiveOutputNode()) { |
| return; |
| } |
| |
| oobe_startup_sound_played_ = true; |
| |
| // Don't try play startup sound if login prompt is already visible |
| // for a long time or can't be played. |
| if (base::TimeTicks::Now() - login_prompt_visible_time_ > |
| base::TimeDelta::FromMilliseconds(kStartupSoundMaxDelayMs)) { |
| return; |
| } |
| |
| AccessibilityManager::Get()->PlayEarcon(SOUND_STARTUP, |
| PlaySoundOption::ALWAYS); |
| } |
| |
| void LoginDisplayHostWebUI::OnLoginPromptVisible() { |
| if (!login_prompt_visible_time_.is_null()) |
| return; |
| login_prompt_visible_time_ = base::TimeTicks::Now(); |
| TryToPlayOobeStartupSound(); |
| } |
| |
| void LoginDisplayHostWebUI::CreateExistingUserController() { |
| // There can only be one |ExistingUserController| instance at a time. |
| existing_user_controller_.reset(); |
| existing_user_controller_.reset(new ExistingUserController(this)); |
| login_display_->set_delegate(existing_user_controller_.get()); |
| } |
| |
| // static |
| void LoginDisplayHostWebUI::DisableRestrictiveProxyCheckForTest() { |
| default_host() |
| ->GetOobeUI() |
| ->GetGaiaScreenView() |
| ->DisableRestrictiveProxyCheckForTest(); |
| } |
| |
| void LoginDisplayHostWebUI::StartVoiceInteractionOobe() { |
| is_voice_interaction_oobe_ = true; |
| finalize_animation_type_ = ANIMATION_NONE; |
| StartWizard(OobeScreen::SCREEN_VOICE_INTERACTION_VALUE_PROP); |
| // We should emit this signal only at login screen (after reboot or sign out). |
| login_view_->set_should_emit_login_prompt_visible(false); |
| } |
| |
| void LoginDisplayHostWebUI::ShowGaiaDialog( |
| bool can_close, |
| const base::Optional<AccountId>& prefilled_account) { |
| NOTREACHED(); |
| } |
| |
| void LoginDisplayHostWebUI::HideOobeDialog() { |
| NOTREACHED(); |
| } |
| |
| void LoginDisplayHostWebUI::UpdateOobeDialogSize(int width, int height) { |
| NOTREACHED(); |
| } |
| |
| const user_manager::UserList LoginDisplayHostWebUI::GetUsers() { |
| return user_manager::UserList(); |
| } |
| |
| void LoginDisplayHostWebUI::ShowFeedback() { |
| NOTREACHED(); |
| } |
| |
| void LoginDisplayHostWebUI::OnCancelPasswordChangedFlow() {} |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // external |
| |
| // Declared in login_wizard.h so that others don't need to depend on our .h. |
| // TODO(nkostylev): Split this into a smaller functions. |
| void ShowLoginWizard(OobeScreen first_screen) { |
| if (browser_shutdown::IsTryingToQuit()) |
| return; |
| |
| VLOG(1) << "Showing OOBE screen: " << GetOobeScreenName(first_screen); |
| |
| input_method::InputMethodManager* manager = |
| input_method::InputMethodManager::Get(); |
| |
| // Set up keyboards. For example, when |locale| is "en-US", enable US qwerty |
| // and US dvorak keyboard layouts. |
| if (g_browser_process && g_browser_process->local_state()) { |
| manager->GetActiveIMEState()->SetInputMethodLoginDefault(); |
| |
| PrefService* prefs = g_browser_process->local_state(); |
| // Apply owner preferences for tap-to-click and mouse buttons swap for |
| // login screen. |
| system::InputDeviceSettings::Get()->SetPrimaryButtonRight( |
| prefs->GetBoolean(prefs::kOwnerPrimaryMouseButtonRight)); |
| // TODO(jamescook): move to ash in OnLocalStatePrefServiceInitialized() once |
| // user session info could distinguish between owner and non-owner |
| // (http://crbug.com/857103). |
| system::InputDeviceSettings::Get()->SetTapToClick( |
| prefs->GetBoolean(ash::prefs::kOwnerTapToClickEnabled)); |
| } |
| system::InputDeviceSettings::Get()->SetNaturalScroll( |
| base::CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kNaturalScrollDefault)); |
| |
| auto session_state = session_manager::SessionState::OOBE; |
| if (IsOobeComplete() || first_screen == OobeScreen::SCREEN_SPECIAL_LOGIN) |
| session_state = session_manager::SessionState::LOGIN_PRIMARY; |
| session_manager::SessionManager::Get()->SetSessionState(session_state); |
| |
| bool show_app_launch_splash_screen = |
| (first_screen == OobeScreen::SCREEN_APP_LAUNCH_SPLASH); |
| if (show_app_launch_splash_screen) { |
| const std::string& auto_launch_app_id = |
| KioskAppManager::Get()->GetAutoLaunchApp(); |
| const bool diagnostic_mode = false; |
| const bool auto_launch = true; |
| // Manages its own lifetime. See ShutdownDisplayHost(). |
| auto* display_host = new LoginDisplayHostWebUI(); |
| display_host->StartAppLaunch(auto_launch_app_id, diagnostic_mode, |
| auto_launch); |
| return; |
| } |
| |
| // Check whether we need to execute OOBE flow. |
| const policy::EnrollmentConfig enrollment_config = |
| g_browser_process->platform_part() |
| ->browser_policy_connector_chromeos() |
| ->GetPrescribedEnrollmentConfig(); |
| if (enrollment_config.should_enroll() && |
| first_screen == OobeScreen::SCREEN_UNKNOWN) { |
| // Manages its own lifetime. See ShutdownDisplayHost(). |
| auto* display_host = new LoginDisplayHostWebUI(); |
| // Shows networks screen instead of enrollment screen to resume the |
| // interrupted auto start enrollment flow because enrollment screen does |
| // not handle flaky network. See http://crbug.com/332572 |
| display_host->StartWizard(OobeScreen::SCREEN_OOBE_WELCOME); |
| return; |
| } |
| |
| if (StartupUtils::IsEulaAccepted()) { |
| DelayNetworkCall( |
| base::TimeDelta::FromMilliseconds(kDefaultNetworkRetryDelayMS), |
| ServicesCustomizationDocument::GetInstance() |
| ->EnsureCustomizationAppliedClosure()); |
| |
| g_browser_process->platform_part() |
| ->GetTimezoneResolverManager() |
| ->UpdateTimezoneResolver(); |
| } |
| |
| PrefService* prefs = g_browser_process->local_state(); |
| std::string current_locale = |
| prefs->GetString(language::prefs::kApplicationLocale); |
| language::ConvertToActualUILocale(¤t_locale); |
| VLOG(1) << "Current locale: " << current_locale; |
| |
| if (ShouldShowSigninScreen(first_screen)) { |
| std::string switch_locale = GetManagedLoginScreenLocale(); |
| if (switch_locale == current_locale) |
| switch_locale.clear(); |
| |
| std::unique_ptr<ShowLoginWizardSwitchLanguageCallbackData> data = |
| std::make_unique<ShowLoginWizardSwitchLanguageCallbackData>( |
| first_screen, nullptr); |
| TriggerShowLoginWizardFinish(switch_locale, std::move(data)); |
| return; |
| } |
| |
| // Load startup manifest. |
| const StartupCustomizationDocument* startup_manifest = |
| StartupCustomizationDocument::GetInstance(); |
| |
| // Switch to initial locale if specified by customization |
| // and has not been set yet. We cannot call |
| // LanguageSwitchMenu::SwitchLanguage here before |
| // EmitLoginPromptReady. |
| const std::string& locale = startup_manifest->initial_locale_default(); |
| |
| const std::string& layout = startup_manifest->keyboard_layout(); |
| VLOG(1) << "Initial locale: " << locale << "keyboard layout " << layout; |
| |
| // Determine keyboard layout from OEM customization (if provided) or |
| // initial locale and save it in preferences. |
| manager->GetActiveIMEState()->SetInputMethodLoginDefaultFromVPD(locale, |
| layout); |
| |
| std::unique_ptr<ShowLoginWizardSwitchLanguageCallbackData> data( |
| new ShowLoginWizardSwitchLanguageCallbackData(first_screen, |
| startup_manifest)); |
| |
| if (!current_locale.empty() || locale.empty()) { |
| TriggerShowLoginWizardFinish(std::string(), std::move(data)); |
| return; |
| } |
| |
| // Save initial locale from VPD/customization manifest as current |
| // Chrome locale. Otherwise it will be lost if Chrome restarts. |
| // Don't need to schedule pref save because setting initial local |
| // will enforce preference saving. |
| prefs->SetString(language::prefs::kApplicationLocale, locale); |
| StartupUtils::SetInitialLocale(locale); |
| |
| TriggerShowLoginWizardFinish(locale, std::move(data)); |
| } |
| |
| } // namespace chromeos |