1 // Copyright 2014 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.
5 #include "chrome/browser/chromeos/login/lock/webui_screen_locker.h"
8 #include "ash/system/chromeos/power/power_event_observer.h"
9 #include "ash/wm/lock_state_controller.h"
10 #include "ash/wm/lock_state_observer.h"
11 #include "base/command_line.h"
12 #include "base/metrics/histogram.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/values.h"
15 #include "chrome/browser/browser_shutdown.h"
16 #include "chrome/browser/chrome_notification_types.h"
17 #include "chrome/browser/chromeos/accessibility/accessibility_util.h"
18 #include "chrome/browser/chromeos/login/helper.h"
19 #include "chrome/browser/chromeos/login/lock/screen_locker.h"
20 #include "chrome/browser/chromeos/login/ui/webui_login_display.h"
21 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
22 #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
23 #include "chrome/common/url_constants.h"
24 #include "chromeos/dbus/dbus_thread_manager.h"
25 #include "components/user_manager/user.h"
26 #include "content/public/browser/browser_thread.h"
27 #include "content/public/browser/notification_service.h"
28 #include "content/public/browser/notification_types.h"
29 #include "content/public/browser/render_widget_host_view.h"
30 #include "content/public/browser/web_ui.h"
31 #include "ui/aura/client/capture_client.h"
32 #include "ui/aura/window_event_dispatcher.h"
33 #include "ui/base/x/x11_util.h"
34 #include "ui/gfx/screen.h"
35 #include "ui/keyboard/keyboard_controller.h"
36 #include "ui/keyboard/keyboard_util.h"
37 #include "ui/views/controls/webview/webview.h"
41 // URL which corresponds to the login WebUI.
42 const char kLoginURL
[] = "chrome://oobe/lock";
44 // Disables virtual keyboard overscroll. Login UI will scroll user pods
45 // into view on JS side when virtual keyboard is shown.
46 void DisableKeyboardOverscroll() {
47 keyboard::SetKeyboardOverscrollOverride(
48 keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_DISABLED
);
51 void ResetKeyboardOverscrollOverride() {
52 keyboard::SetKeyboardOverscrollOverride(
53 keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_NONE
);
60 ////////////////////////////////////////////////////////////////////////////////
61 // WebUIScreenLocker implementation.
63 WebUIScreenLocker::WebUIScreenLocker(ScreenLocker
* screen_locker
)
64 : ScreenLockerDelegate(screen_locker
),
67 network_state_helper_(new login::NetworkStateHelper
),
68 is_observing_keyboard_(false),
70 set_should_emit_login_prompt_visible(false);
71 ash::Shell::GetInstance()->lock_state_controller()->AddObserver(this);
72 ash::Shell::GetInstance()->delegate()->AddVirtualKeyboardStateObserver(this);
73 ash::Shell::GetScreen()->AddObserver(this);
74 DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this);
76 if (keyboard::KeyboardController::GetInstance()) {
77 keyboard::KeyboardController::GetInstance()->AddObserver(this);
78 is_observing_keyboard_
= true;
82 void WebUIScreenLocker::LockScreen() {
84 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().bounds();
86 lock_time_
= base::TimeTicks::Now();
87 LockWindow
* lock_window
= LockWindow::Create();
88 lock_window
->set_observer(this);
89 lock_window
->set_initially_focused_view(this);
90 lock_window_
= lock_window
->GetWidget();
91 lock_window_
->AddObserver(this);
92 WebUILoginView::Init();
93 lock_window_
->SetContentsView(this);
94 lock_window_
->SetBounds(bounds
);
96 LoadURL(GURL(kLoginURL
));
99 signin_screen_controller_
.reset(
100 new SignInScreenController(GetOobeUI(), this));
102 login_display_
.reset(new WebUILoginDisplay(this));
103 login_display_
->set_background_bounds(bounds
);
104 login_display_
->set_parent_window(GetNativeWindow());
105 login_display_
->Init(screen_locker()->users(), false, true, false);
107 GetOobeUI()->ShowSigninScreen(
108 LoginScreenContext(), login_display_
.get(), login_display_
.get());
110 DisableKeyboardOverscroll();
113 void WebUIScreenLocker::ScreenLockReady() {
114 UMA_HISTOGRAM_TIMES("LockScreen.LockReady",
115 base::TimeTicks::Now() - lock_time_
);
116 ScreenLockerDelegate::ScreenLockReady();
117 SetInputEnabled(true);
120 void WebUIScreenLocker::OnAuthenticate() {
123 void WebUIScreenLocker::SetInputEnabled(bool enabled
) {
124 login_display_
->SetUIEnabled(enabled
);
127 void WebUIScreenLocker::ShowErrorMessage(
129 HelpAppLauncher::HelpTopic help_topic_id
) {
130 login_display_
->ShowError(error_msg_id
,
131 0 /* login_attempts */,
135 void WebUIScreenLocker::AnimateAuthenticationSuccess() {
136 GetWebUI()->CallJavascriptFunction("cr.ui.Oobe.animateAuthenticationSuccess");
139 void WebUIScreenLocker::ClearErrors() {
140 GetWebUI()->CallJavascriptFunction("cr.ui.Oobe.clearErrors");
143 gfx::NativeWindow
WebUIScreenLocker::GetNativeWindow() const {
144 return lock_window_
->GetNativeWindow();
147 content::WebUI
* WebUIScreenLocker::GetAssociatedWebUI() {
151 void WebUIScreenLocker::FocusUserPod() {
154 webui_login_
->RequestFocus();
155 GetWebUI()->CallJavascriptFunction("cr.ui.Oobe.forceLockedUserPodFocus");
158 void WebUIScreenLocker::ResetAndFocusUserPod() {
161 GetWebUI()->CallJavascriptFunction("cr.ui.Oobe.clearUserPodPassword");
165 WebUIScreenLocker::~WebUIScreenLocker() {
166 DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this);
167 ash::Shell::GetScreen()->RemoveObserver(this);
168 ash::Shell::GetInstance()->
169 lock_state_controller()->RemoveObserver(this);
171 ash::Shell::GetInstance()->delegate()->
172 RemoveVirtualKeyboardStateObserver(this);
173 // In case of shutdown, lock_window_ may be deleted before WebUIScreenLocker.
175 lock_window_
->RemoveObserver(this);
176 lock_window_
->Close();
178 // If LockScreen() was called, we need to clear the signin screen handler
179 // delegate set in ShowSigninScreen so that it no longer points to us.
180 if (login_display_
.get()) {
181 static_cast<OobeUI
*>(GetWebUI()->GetController())->
182 ResetSigninScreenHandlerDelegate();
185 if (keyboard::KeyboardController::GetInstance() && is_observing_keyboard_
) {
186 keyboard::KeyboardController::GetInstance()->RemoveObserver(this);
187 is_observing_keyboard_
= false;
190 ResetKeyboardOverscrollOverride();
193 void WebUIScreenLocker::OnLockWebUIReady() {
194 VLOG(1) << "WebUI ready; lock window is "
195 << (lock_ready_
? "too" : "not");
201 void WebUIScreenLocker::OnLockBackgroundDisplayed() {
202 UMA_HISTOGRAM_TIMES("LockScreen.BackgroundReady",
203 base::TimeTicks::Now() - lock_time_
);
206 void WebUIScreenLocker::OnHeaderBarVisible() {
207 DCHECK(ash::Shell::HasInstance());
209 ash::Shell::GetInstance()->power_event_observer()->OnLockAnimationsComplete();
212 OobeUI
* WebUIScreenLocker::GetOobeUI() {
213 return static_cast<OobeUI
*>(GetWebUI()->GetController());
216 ////////////////////////////////////////////////////////////////////////////////
217 // WebUIScreenLocker, LoginDisplay::Delegate:
219 void WebUIScreenLocker::CancelPasswordChangedFlow() {
223 void WebUIScreenLocker::CreateAccount() {
227 void WebUIScreenLocker::CompleteLogin(const UserContext
& user_context
) {
231 base::string16
WebUIScreenLocker::GetConnectedNetworkName() {
232 return network_state_helper_
->GetCurrentNetworkName();
235 bool WebUIScreenLocker::IsSigninInProgress() const {
236 // The way how screen locker is implemented right now there's no
237 // GAIA sign in in progress in any case.
241 void WebUIScreenLocker::Login(const UserContext
& user_context
,
242 const SigninSpecifics
& specifics
) {
243 chromeos::ScreenLocker::default_screen_locker()->Authenticate(user_context
);
246 void WebUIScreenLocker::MigrateUserData(const std::string
& old_password
) {
250 void WebUIScreenLocker::OnSigninScreenReady() {
253 void WebUIScreenLocker::OnStartEnterpriseEnrollment() {
257 void WebUIScreenLocker::OnStartEnableDebuggingScreen() {
261 void WebUIScreenLocker::OnStartKioskEnableScreen() {
265 void WebUIScreenLocker::OnStartKioskAutolaunchScreen() {
269 void WebUIScreenLocker::ShowWrongHWIDScreen() {
273 void WebUIScreenLocker::ResetPublicSessionAutoLoginTimer() {
276 void WebUIScreenLocker::ResyncUserData() {
280 void WebUIScreenLocker::SetDisplayEmail(const std::string
& email
) {
284 void WebUIScreenLocker::Signout() {
285 chromeos::ScreenLocker::default_screen_locker()->Signout();
288 bool WebUIScreenLocker::IsUserWhitelisted(const std::string
& user_id
) {
292 ////////////////////////////////////////////////////////////////////////////////
293 // LockWindow::Observer:
295 void WebUIScreenLocker::OnLockWindowReady() {
296 VLOG(1) << "Lock window ready; WebUI is " << (webui_ready_
? "too" : "not");
302 ////////////////////////////////////////////////////////////////////////////////
303 // SessionLockStateObserver:
305 void WebUIScreenLocker::OnLockStateEvent(
306 ash::LockStateObserver::EventType event
) {
307 if (event
== ash::LockStateObserver::EVENT_LOCK_ANIMATION_FINISHED
) {
308 // Release capture if any.
309 aura::client::GetCaptureClient(GetNativeWindow()->GetRootWindow())->
311 GetWebUI()->CallJavascriptFunction("cr.ui.Oobe.animateOnceFullyDisplayed");
315 ////////////////////////////////////////////////////////////////////////////////
318 void WebUIScreenLocker::OnWidgetDestroying(views::Widget
* widget
) {
319 lock_window_
->RemoveObserver(this);
323 ////////////////////////////////////////////////////////////////////////////////
324 // PowerManagerClient::Observer:
326 void WebUIScreenLocker::LidEventReceived(bool open
,
327 const base::TimeTicks
& time
) {
329 content::BrowserThread::PostTask(
330 content::BrowserThread::UI
, FROM_HERE
,
331 base::Bind(&WebUIScreenLocker::FocusUserPod
,
332 weak_factory_
.GetWeakPtr()));
336 void WebUIScreenLocker::SuspendImminent() {
337 content::BrowserThread::PostTask(
338 content::BrowserThread::UI
, FROM_HERE
,
339 base::Bind(&WebUIScreenLocker::ResetAndFocusUserPod
,
340 weak_factory_
.GetWeakPtr()));
343 void WebUIScreenLocker::SuspendDone(const base::TimeDelta
& sleep_duration
) {
344 content::BrowserThread::PostTask(
345 content::BrowserThread::UI
,
347 base::Bind(&WebUIScreenLocker::FocusUserPod
, weak_factory_
.GetWeakPtr()));
350 void WebUIScreenLocker::RenderProcessGone(base::TerminationStatus status
) {
351 if (browser_shutdown::GetShutdownType() == browser_shutdown::NOT_VALID
&&
352 status
!= base::TERMINATION_STATUS_NORMAL_TERMINATION
) {
353 LOG(ERROR
) << "Renderer crash on lock screen";
358 ////////////////////////////////////////////////////////////////////////////////
359 // ash::KeyboardStateObserver overrides.
361 void WebUIScreenLocker::OnVirtualKeyboardStateChanged(bool activated
) {
362 if (keyboard::KeyboardController::GetInstance()) {
364 if (!is_observing_keyboard_
) {
365 keyboard::KeyboardController::GetInstance()->AddObserver(this);
366 is_observing_keyboard_
= true;
369 keyboard::KeyboardController::GetInstance()->RemoveObserver(this);
370 is_observing_keyboard_
= false;
375 ////////////////////////////////////////////////////////////////////////////////
376 // keyboard::KeyboardControllerObserver:
378 void WebUIScreenLocker::OnKeyboardBoundsChanging(
379 const gfx::Rect
& new_bounds
) {
380 if (new_bounds
.IsEmpty()) {
381 // Keyboard has been hidden.
383 GetOobeUI()->GetCoreOobeActor()->ShowControlBar(true);
385 // Keyboard has been shown.
387 GetOobeUI()->GetCoreOobeActor()->ShowControlBar(false);
391 ////////////////////////////////////////////////////////////////////////////////
392 // gfx::DisplayObserver:
394 void WebUIScreenLocker::OnDisplayAdded(const gfx::Display
& new_display
) {
397 void WebUIScreenLocker::OnDisplayRemoved(const gfx::Display
& old_display
) {
400 void WebUIScreenLocker::OnDisplayMetricsChanged(const gfx::Display
& display
,
401 uint32_t changed_metrics
) {
402 gfx::Display primary_display
=
403 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
404 if (display
.id() != primary_display
.id() ||
405 !(changed_metrics
& DISPLAY_METRIC_BOUNDS
)) {
410 const gfx::Size
& size
= primary_display
.size();
411 GetOobeUI()->GetCoreOobeActor()->SetClientAreaSize(size
.width(),
416 } // namespace chromeos