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 if (login::LoginScrollIntoViewEnabled())
111 DisableKeyboardOverscroll();
114 void WebUIScreenLocker::ScreenLockReady() {
115 UMA_HISTOGRAM_TIMES("LockScreen.LockReady",
116 base::TimeTicks::Now() - lock_time_
);
117 ScreenLockerDelegate::ScreenLockReady();
118 SetInputEnabled(true);
121 void WebUIScreenLocker::OnAuthenticate() {
124 void WebUIScreenLocker::SetInputEnabled(bool enabled
) {
125 login_display_
->SetUIEnabled(enabled
);
128 void WebUIScreenLocker::ShowErrorMessage(
130 HelpAppLauncher::HelpTopic help_topic_id
) {
131 login_display_
->ShowError(error_msg_id
,
132 0 /* login_attempts */,
136 void WebUIScreenLocker::AnimateAuthenticationSuccess() {
137 GetWebUI()->CallJavascriptFunction("cr.ui.Oobe.animateAuthenticationSuccess");
140 void WebUIScreenLocker::ClearErrors() {
141 GetWebUI()->CallJavascriptFunction("cr.ui.Oobe.clearErrors");
144 gfx::NativeWindow
WebUIScreenLocker::GetNativeWindow() const {
145 return lock_window_
->GetNativeWindow();
148 content::WebUI
* WebUIScreenLocker::GetAssociatedWebUI() {
152 void WebUIScreenLocker::FocusUserPod() {
155 webui_login_
->RequestFocus();
156 GetWebUI()->CallJavascriptFunction("cr.ui.Oobe.forceLockedUserPodFocus");
159 void WebUIScreenLocker::ResetAndFocusUserPod() {
162 GetWebUI()->CallJavascriptFunction("cr.ui.Oobe.clearUserPodPassword");
166 WebUIScreenLocker::~WebUIScreenLocker() {
167 DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this);
168 ash::Shell::GetScreen()->RemoveObserver(this);
169 ash::Shell::GetInstance()->
170 lock_state_controller()->RemoveObserver(this);
172 ash::Shell::GetInstance()->delegate()->
173 RemoveVirtualKeyboardStateObserver(this);
174 // In case of shutdown, lock_window_ may be deleted before WebUIScreenLocker.
176 lock_window_
->RemoveObserver(this);
177 lock_window_
->Close();
179 // If LockScreen() was called, we need to clear the signin screen handler
180 // delegate set in ShowSigninScreen so that it no longer points to us.
181 if (login_display_
.get()) {
182 static_cast<OobeUI
*>(GetWebUI()->GetController())->
183 ResetSigninScreenHandlerDelegate();
186 if (keyboard::KeyboardController::GetInstance() && is_observing_keyboard_
) {
187 keyboard::KeyboardController::GetInstance()->RemoveObserver(this);
188 is_observing_keyboard_
= false;
191 if (login::LoginScrollIntoViewEnabled())
192 ResetKeyboardOverscrollOverride();
195 void WebUIScreenLocker::OnLockWebUIReady() {
196 VLOG(1) << "WebUI ready; lock window is "
197 << (lock_ready_
? "too" : "not");
203 void WebUIScreenLocker::OnLockBackgroundDisplayed() {
204 UMA_HISTOGRAM_TIMES("LockScreen.BackgroundReady",
205 base::TimeTicks::Now() - lock_time_
);
208 void WebUIScreenLocker::OnHeaderBarVisible() {
209 DCHECK(ash::Shell::HasInstance());
211 ash::Shell::GetInstance()->power_event_observer()->OnLockAnimationsComplete();
214 OobeUI
* WebUIScreenLocker::GetOobeUI() {
215 return static_cast<OobeUI
*>(GetWebUI()->GetController());
218 ////////////////////////////////////////////////////////////////////////////////
219 // WebUIScreenLocker, LoginDisplay::Delegate:
221 void WebUIScreenLocker::CancelPasswordChangedFlow() {
225 void WebUIScreenLocker::CreateAccount() {
229 void WebUIScreenLocker::CompleteLogin(const UserContext
& user_context
) {
233 base::string16
WebUIScreenLocker::GetConnectedNetworkName() {
234 return network_state_helper_
->GetCurrentNetworkName();
237 bool WebUIScreenLocker::IsSigninInProgress() const {
238 // The way how screen locker is implemented right now there's no
239 // GAIA sign in in progress in any case.
243 void WebUIScreenLocker::Login(const UserContext
& user_context
,
244 const SigninSpecifics
& specifics
) {
245 chromeos::ScreenLocker::default_screen_locker()->Authenticate(user_context
);
248 void WebUIScreenLocker::MigrateUserData(const std::string
& old_password
) {
252 void WebUIScreenLocker::OnSigninScreenReady() {
255 void WebUIScreenLocker::OnStartEnterpriseEnrollment() {
259 void WebUIScreenLocker::OnStartEnableDebuggingScreen() {
263 void WebUIScreenLocker::OnStartKioskEnableScreen() {
267 void WebUIScreenLocker::OnStartKioskAutolaunchScreen() {
271 void WebUIScreenLocker::ShowWrongHWIDScreen() {
275 void WebUIScreenLocker::ResetPublicSessionAutoLoginTimer() {
278 void WebUIScreenLocker::ResyncUserData() {
282 void WebUIScreenLocker::SetDisplayEmail(const std::string
& email
) {
286 void WebUIScreenLocker::Signout() {
287 chromeos::ScreenLocker::default_screen_locker()->Signout();
290 ////////////////////////////////////////////////////////////////////////////////
291 // LockWindow::Observer:
293 void WebUIScreenLocker::OnLockWindowReady() {
294 VLOG(1) << "Lock window ready; WebUI is " << (webui_ready_
? "too" : "not");
300 ////////////////////////////////////////////////////////////////////////////////
301 // SessionLockStateObserver:
303 void WebUIScreenLocker::OnLockStateEvent(
304 ash::LockStateObserver::EventType event
) {
305 if (event
== ash::LockStateObserver::EVENT_LOCK_ANIMATION_FINISHED
) {
306 // Release capture if any.
307 aura::client::GetCaptureClient(GetNativeWindow()->GetRootWindow())->
309 GetWebUI()->CallJavascriptFunction("cr.ui.Oobe.animateOnceFullyDisplayed");
313 ////////////////////////////////////////////////////////////////////////////////
316 void WebUIScreenLocker::OnWidgetDestroying(views::Widget
* widget
) {
317 lock_window_
->RemoveObserver(this);
321 ////////////////////////////////////////////////////////////////////////////////
322 // PowerManagerClient::Observer:
324 void WebUIScreenLocker::LidEventReceived(bool open
,
325 const base::TimeTicks
& time
) {
327 content::BrowserThread::PostTask(
328 content::BrowserThread::UI
, FROM_HERE
,
329 base::Bind(&WebUIScreenLocker::FocusUserPod
,
330 weak_factory_
.GetWeakPtr()));
334 void WebUIScreenLocker::SuspendImminent() {
335 content::BrowserThread::PostTask(
336 content::BrowserThread::UI
, FROM_HERE
,
337 base::Bind(&WebUIScreenLocker::ResetAndFocusUserPod
,
338 weak_factory_
.GetWeakPtr()));
341 void WebUIScreenLocker::SuspendDone(const base::TimeDelta
& sleep_duration
) {
342 content::BrowserThread::PostTask(
343 content::BrowserThread::UI
,
345 base::Bind(&WebUIScreenLocker::FocusUserPod
, weak_factory_
.GetWeakPtr()));
348 void WebUIScreenLocker::RenderProcessGone(base::TerminationStatus status
) {
349 if (browser_shutdown::GetShutdownType() == browser_shutdown::NOT_VALID
&&
350 status
!= base::TERMINATION_STATUS_NORMAL_TERMINATION
) {
351 LOG(ERROR
) << "Renderer crash on lock screen";
356 ////////////////////////////////////////////////////////////////////////////////
357 // ash::KeyboardStateObserver overrides.
359 void WebUIScreenLocker::OnVirtualKeyboardStateChanged(bool activated
) {
360 if (keyboard::KeyboardController::GetInstance()) {
362 if (!is_observing_keyboard_
) {
363 keyboard::KeyboardController::GetInstance()->AddObserver(this);
364 is_observing_keyboard_
= true;
367 keyboard::KeyboardController::GetInstance()->RemoveObserver(this);
368 is_observing_keyboard_
= false;
373 ////////////////////////////////////////////////////////////////////////////////
374 // keyboard::KeyboardControllerObserver:
376 void WebUIScreenLocker::OnKeyboardBoundsChanging(
377 const gfx::Rect
& new_bounds
) {
378 if (new_bounds
.IsEmpty() && !keyboard_bounds_
.IsEmpty()) {
379 // Keyboard has been hidden.
381 GetOobeUI()->GetCoreOobeActor()->ShowControlBar(true);
382 if (login::LoginScrollIntoViewEnabled())
383 GetOobeUI()->GetCoreOobeActor()->SetKeyboardState(false, new_bounds
);
385 } else if (!new_bounds
.IsEmpty() && keyboard_bounds_
.IsEmpty()) {
386 // Keyboard has been shown.
388 GetOobeUI()->GetCoreOobeActor()->ShowControlBar(false);
389 if (login::LoginScrollIntoViewEnabled())
390 GetOobeUI()->GetCoreOobeActor()->SetKeyboardState(true, new_bounds
);
394 keyboard_bounds_
= new_bounds
;
397 ////////////////////////////////////////////////////////////////////////////////
398 // gfx::DisplayObserver:
400 void WebUIScreenLocker::OnDisplayAdded(const gfx::Display
& new_display
) {
403 void WebUIScreenLocker::OnDisplayRemoved(const gfx::Display
& old_display
) {
406 void WebUIScreenLocker::OnDisplayMetricsChanged(const gfx::Display
& display
,
407 uint32_t changed_metrics
) {
408 gfx::Display primary_display
=
409 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
410 if (display
.id() != primary_display
.id() ||
411 !(changed_metrics
& DISPLAY_METRIC_BOUNDS
)) {
416 const gfx::Size
& size
= primary_display
.size();
417 GetOobeUI()->GetCoreOobeActor()->SetClientAreaSize(size
.width(),
422 } // namespace chromeos