• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "chrome/browser/chromeos/login/lock/webui_screen_locker.h"
6 
7 #include "ash/shell.h"
8 #include "ash/wm/lock_state_controller.h"
9 #include "ash/wm/lock_state_observer.h"
10 #include "base/command_line.h"
11 #include "base/metrics/histogram.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/values.h"
14 #include "chrome/browser/browser_shutdown.h"
15 #include "chrome/browser/chrome_notification_types.h"
16 #include "chrome/browser/chromeos/accessibility/accessibility_util.h"
17 #include "chrome/browser/chromeos/login/helper.h"
18 #include "chrome/browser/chromeos/login/lock/screen_locker.h"
19 #include "chrome/browser/chromeos/login/ui/webui_login_display.h"
20 #include "chrome/browser/chromeos/login/users/user.h"
21 #include "chrome/browser/chromeos/login/users/user_manager.h"
22 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
23 #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
24 #include "chrome/common/url_constants.h"
25 #include "chromeos/dbus/dbus_thread_manager.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/l10n/l10n_util.h"
34 #include "ui/base/x/x11_util.h"
35 #include "ui/gfx/screen.h"
36 #include "ui/keyboard/keyboard_controller.h"
37 #include "ui/keyboard/keyboard_util.h"
38 #include "ui/views/controls/webview/webview.h"
39 
40 namespace {
41 
42 // URL which corresponds to the login WebUI.
43 const char kLoginURL[] = "chrome://oobe/lock";
44 
45 // Disables virtual keyboard overscroll. Login UI will scroll user pods
46 // into view on JS side when virtual keyboard is shown.
DisableKeyboardOverscroll()47 void DisableKeyboardOverscroll() {
48   keyboard::SetKeyboardOverscrollOverride(
49       keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_DISABLED);
50 }
51 
ResetKeyboardOverscrollOverride()52 void ResetKeyboardOverscrollOverride() {
53   keyboard::SetKeyboardOverscrollOverride(
54       keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_NONE);
55 }
56 
57 }  // namespace
58 
59 namespace chromeos {
60 
61 ////////////////////////////////////////////////////////////////////////////////
62 // WebUIScreenLocker implementation.
63 
WebUIScreenLocker(ScreenLocker * screen_locker)64 WebUIScreenLocker::WebUIScreenLocker(ScreenLocker* screen_locker)
65     : ScreenLockerDelegate(screen_locker),
66       lock_ready_(false),
67       webui_ready_(false),
68       network_state_helper_(new login::NetworkStateHelper),
69       is_observing_keyboard_(false),
70       weak_factory_(this) {
71   set_should_emit_login_prompt_visible(false);
72   ash::Shell::GetInstance()->lock_state_controller()->AddObserver(this);
73   DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this);
74 
75   if (keyboard::KeyboardController::GetInstance()) {
76     keyboard::KeyboardController::GetInstance()->AddObserver(this);
77     is_observing_keyboard_ = true;
78   }
79 
80   ash::Shell::GetInstance()->delegate()->AddVirtualKeyboardStateObserver(this);
81 }
82 
LockScreen()83 void WebUIScreenLocker::LockScreen() {
84   gfx::Rect bounds(ash::Shell::GetScreen()->GetPrimaryDisplay().bounds());
85 
86   lock_time_ = base::TimeTicks::Now();
87   LockWindow* lock_window = LockWindow::Create();
88   lock_window->set_observer(this);
89   lock_window_ = lock_window->GetWidget();
90   lock_window_->AddObserver(this);
91   WebUILoginView::Init();
92   lock_window_->SetContentsView(this);
93   lock_window_->Show();
94   LoadURL(GURL(kLoginURL));
95   lock_window->Grab();
96 
97   login_display_.reset(new WebUILoginDisplay(this));
98   login_display_->set_background_bounds(bounds);
99   login_display_->set_parent_window(GetNativeWindow());
100   login_display_->Init(screen_locker()->users(), false, true, false);
101 
102   GetOobeUI()->ShowSigninScreen(
103       LoginScreenContext(), login_display_.get(), login_display_.get());
104 
105   registrar_.Add(this,
106                  chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED,
107                  content::NotificationService::AllSources());
108 
109   if (login::LoginScrollIntoViewEnabled())
110     DisableKeyboardOverscroll();
111 }
112 
ScreenLockReady()113 void WebUIScreenLocker::ScreenLockReady() {
114   UMA_HISTOGRAM_TIMES("LockScreen.LockReady",
115                       base::TimeTicks::Now() - lock_time_);
116   ScreenLockerDelegate::ScreenLockReady();
117   SetInputEnabled(true);
118 }
119 
OnAuthenticate()120 void WebUIScreenLocker::OnAuthenticate() {
121 }
122 
SetInputEnabled(bool enabled)123 void WebUIScreenLocker::SetInputEnabled(bool enabled) {
124   login_display_->SetUIEnabled(enabled);
125 }
126 
ShowErrorMessage(int error_msg_id,HelpAppLauncher::HelpTopic help_topic_id)127 void WebUIScreenLocker::ShowErrorMessage(
128     int error_msg_id,
129     HelpAppLauncher::HelpTopic help_topic_id) {
130   login_display_->ShowError(error_msg_id,
131                   0 /* login_attempts */,
132                   help_topic_id);
133 }
134 
AnimateAuthenticationSuccess()135 void WebUIScreenLocker::AnimateAuthenticationSuccess() {
136   GetWebUI()->CallJavascriptFunction("cr.ui.Oobe.animateAuthenticationSuccess");
137 }
138 
ClearErrors()139 void WebUIScreenLocker::ClearErrors() {
140   GetWebUI()->CallJavascriptFunction("cr.ui.Oobe.clearErrors");
141 }
142 
GetNativeWindow() const143 gfx::NativeWindow WebUIScreenLocker::GetNativeWindow() const {
144   return lock_window_->GetNativeWindow();
145 }
146 
GetAssociatedWebUI()147 content::WebUI* WebUIScreenLocker::GetAssociatedWebUI() {
148   return GetWebUI();
149 }
150 
FocusUserPod()151 void WebUIScreenLocker::FocusUserPod() {
152   if (!webui_ready_)
153     return;
154   webui_login_->RequestFocus();
155   GetWebUI()->CallJavascriptFunction("cr.ui.Oobe.forceLockedUserPodFocus");
156 }
157 
~WebUIScreenLocker()158 WebUIScreenLocker::~WebUIScreenLocker() {
159   DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this);
160   ash::Shell::GetInstance()->
161       lock_state_controller()->RemoveObserver(this);
162   // In case of shutdown, lock_window_ may be deleted before WebUIScreenLocker.
163   if (lock_window_) {
164     lock_window_->RemoveObserver(this);
165     lock_window_->Close();
166   }
167   // If LockScreen() was called, we need to clear the signin screen handler
168   // delegate set in ShowSigninScreen so that it no longer points to us.
169   if (login_display_.get()) {
170     static_cast<OobeUI*>(GetWebUI()->GetController())->
171         ResetSigninScreenHandlerDelegate();
172   }
173 
174   if (keyboard::KeyboardController::GetInstance() && is_observing_keyboard_) {
175     keyboard::KeyboardController::GetInstance()->RemoveObserver(this);
176     is_observing_keyboard_ = false;
177   }
178 
179   ash::Shell::GetInstance()->delegate()->
180       RemoveVirtualKeyboardStateObserver(this);
181 
182   if (login::LoginScrollIntoViewEnabled())
183     ResetKeyboardOverscrollOverride();
184 }
185 
OnLockWebUIReady()186 void WebUIScreenLocker::OnLockWebUIReady() {
187   VLOG(1) << "WebUI ready; lock window is "
188           << (lock_ready_ ? "too" : "not");
189   webui_ready_ = true;
190   if (lock_ready_)
191     ScreenLockReady();
192 }
193 
OnLockBackgroundDisplayed()194 void WebUIScreenLocker::OnLockBackgroundDisplayed() {
195   UMA_HISTOGRAM_TIMES("LockScreen.BackgroundReady",
196                       base::TimeTicks::Now() - lock_time_);
197 }
198 
GetOobeUI()199 OobeUI* WebUIScreenLocker::GetOobeUI() {
200   return static_cast<OobeUI*>(GetWebUI()->GetController());
201 }
202 
203 ////////////////////////////////////////////////////////////////////////////////
204 // WebUIScreenLocker, content::NotificationObserver implementation:
205 
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)206 void WebUIScreenLocker::Observe(
207     int type,
208     const content::NotificationSource& source,
209     const content::NotificationDetails& details) {
210   switch (type) {
211     case chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED: {
212       const User& user = *content::Details<User>(details).ptr();
213       login_display_->OnUserImageChanged(user);
214       break;
215     }
216     default:
217       WebUILoginView::Observe(type, source, details);
218   }
219 }
220 
221 ////////////////////////////////////////////////////////////////////////////////
222 // WebUIScreenLocker, LoginDisplay::Delegate implementation:
223 
CancelPasswordChangedFlow()224 void WebUIScreenLocker::CancelPasswordChangedFlow()  {
225   NOTREACHED();
226 }
227 
CreateAccount()228 void WebUIScreenLocker::CreateAccount() {
229   NOTREACHED();
230 }
231 
CompleteLogin(const UserContext & user_context)232 void WebUIScreenLocker::CompleteLogin(const UserContext& user_context) {
233   NOTREACHED();
234 }
235 
GetConnectedNetworkName()236 base::string16 WebUIScreenLocker::GetConnectedNetworkName() {
237   return network_state_helper_->GetCurrentNetworkName();
238 }
239 
IsSigninInProgress() const240 bool WebUIScreenLocker::IsSigninInProgress() const {
241   // The way how screen locker is implemented right now there's no
242   // GAIA sign in in progress in any case.
243   return false;
244 }
245 
Login(const UserContext & user_context)246 void WebUIScreenLocker::Login(const UserContext& user_context) {
247   chromeos::ScreenLocker::default_screen_locker()->Authenticate(user_context);
248 }
249 
LoginAsRetailModeUser()250 void WebUIScreenLocker::LoginAsRetailModeUser() {
251   NOTREACHED();
252 }
253 
LoginAsGuest()254 void WebUIScreenLocker::LoginAsGuest() {
255   NOTREACHED();
256 }
257 
MigrateUserData(const std::string & old_password)258 void WebUIScreenLocker::MigrateUserData(const std::string& old_password) {
259   NOTREACHED();
260 }
261 
LoginAsPublicAccount(const std::string & username)262 void WebUIScreenLocker::LoginAsPublicAccount(const std::string& username) {
263   NOTREACHED();
264 }
265 
OnSigninScreenReady()266 void WebUIScreenLocker::OnSigninScreenReady() {
267 }
268 
OnUserSelected(const std::string & username)269 void WebUIScreenLocker::OnUserSelected(const std::string& username) {
270 }
271 
OnStartEnterpriseEnrollment()272 void WebUIScreenLocker::OnStartEnterpriseEnrollment() {
273   NOTREACHED();
274 }
275 
OnStartKioskEnableScreen()276 void WebUIScreenLocker::OnStartKioskEnableScreen() {
277   NOTREACHED();
278 }
279 
OnStartKioskAutolaunchScreen()280 void WebUIScreenLocker::OnStartKioskAutolaunchScreen() {
281   NOTREACHED();
282 }
283 
ShowWrongHWIDScreen()284 void WebUIScreenLocker::ShowWrongHWIDScreen() {
285   NOTREACHED();
286 }
287 
ResetPublicSessionAutoLoginTimer()288 void WebUIScreenLocker::ResetPublicSessionAutoLoginTimer() {
289 }
290 
ResyncUserData()291 void WebUIScreenLocker::ResyncUserData() {
292   NOTREACHED();
293 }
294 
SetDisplayEmail(const std::string & email)295 void WebUIScreenLocker::SetDisplayEmail(const std::string& email) {
296   NOTREACHED();
297 }
298 
Signout()299 void WebUIScreenLocker::Signout() {
300   chromeos::ScreenLocker::default_screen_locker()->Signout();
301 }
302 
LoginAsKioskApp(const std::string & app_id,bool diagnostic_mode)303 void WebUIScreenLocker::LoginAsKioskApp(const std::string& app_id,
304                                         bool diagnostic_mode) {
305   NOTREACHED();
306 }
307 
308 ////////////////////////////////////////////////////////////////////////////////
309 // LockWindow::Observer implementation:
310 
OnLockWindowReady()311 void WebUIScreenLocker::OnLockWindowReady() {
312   VLOG(1) << "Lock window ready; WebUI is " << (webui_ready_ ? "too" : "not");
313   lock_ready_ = true;
314   if (webui_ready_)
315     ScreenLockReady();
316 }
317 
318 ////////////////////////////////////////////////////////////////////////////////
319 // SessionLockStateObserver override.
320 
OnLockStateEvent(ash::LockStateObserver::EventType event)321 void WebUIScreenLocker::OnLockStateEvent(
322     ash::LockStateObserver::EventType event) {
323   if (event == ash::LockStateObserver::EVENT_LOCK_ANIMATION_FINISHED) {
324     // Release capture if any.
325     aura::client::GetCaptureClient(GetNativeWindow()->GetRootWindow())->
326         SetCapture(NULL);
327     GetWebUI()->CallJavascriptFunction("cr.ui.Oobe.animateOnceFullyDisplayed");
328   }
329 }
330 
331 ////////////////////////////////////////////////////////////////////////////////
332 // WidgetObserver override.
333 
OnWidgetDestroying(views::Widget * widget)334 void WebUIScreenLocker::OnWidgetDestroying(views::Widget* widget) {
335   lock_window_->RemoveObserver(this);
336   lock_window_ = NULL;
337 }
338 
339 ////////////////////////////////////////////////////////////////////////////////
340 // PowerManagerClient::Observer overrides.
341 
LidEventReceived(bool open,const base::TimeTicks & time)342 void WebUIScreenLocker::LidEventReceived(bool open,
343                                          const base::TimeTicks& time) {
344   content::BrowserThread::PostTask(
345       content::BrowserThread::UI,
346       FROM_HERE,
347       base::Bind(&WebUIScreenLocker::FocusUserPod, weak_factory_.GetWeakPtr()));
348 }
349 
SuspendDone(const base::TimeDelta & sleep_duration)350 void WebUIScreenLocker::SuspendDone(const base::TimeDelta& sleep_duration) {
351   content::BrowserThread::PostTask(
352       content::BrowserThread::UI,
353       FROM_HERE,
354       base::Bind(&WebUIScreenLocker::FocusUserPod, weak_factory_.GetWeakPtr()));
355 }
356 
RenderProcessGone(base::TerminationStatus status)357 void WebUIScreenLocker::RenderProcessGone(base::TerminationStatus status) {
358   if (browser_shutdown::GetShutdownType() == browser_shutdown::NOT_VALID &&
359       status != base::TERMINATION_STATUS_NORMAL_TERMINATION) {
360     LOG(ERROR) << "Renderer crash on lock screen";
361     Signout();
362   }
363 }
364 
365 ////////////////////////////////////////////////////////////////////////////////
366 // ash::KeyboardStateObserver overrides.
367 
OnVirtualKeyboardStateChanged(bool activated)368 void WebUIScreenLocker::OnVirtualKeyboardStateChanged(bool activated) {
369   if (keyboard::KeyboardController::GetInstance()) {
370     if (activated) {
371       if (!is_observing_keyboard_) {
372         keyboard::KeyboardController::GetInstance()->AddObserver(this);
373         is_observing_keyboard_ = true;
374       }
375     } else {
376       keyboard::KeyboardController::GetInstance()->RemoveObserver(this);
377       is_observing_keyboard_ = false;
378     }
379   }
380 }
381 
382 ////////////////////////////////////////////////////////////////////////////////
383 // keyboard::KeyboardControllerObserver overrides.
384 
OnKeyboardBoundsChanging(const gfx::Rect & new_bounds)385 void WebUIScreenLocker::OnKeyboardBoundsChanging(
386     const gfx::Rect& new_bounds) {
387   if (new_bounds.IsEmpty() && !keyboard_bounds_.IsEmpty()) {
388     // Keyboard has been hidden.
389     if (GetOobeUI()) {
390       GetOobeUI()->GetCoreOobeActor()->ShowControlBar(true);
391       if (login::LoginScrollIntoViewEnabled())
392         GetOobeUI()->GetCoreOobeActor()->SetKeyboardState(false, new_bounds);
393     }
394   } else if (!new_bounds.IsEmpty() && keyboard_bounds_.IsEmpty()) {
395     // Keyboard has been shown.
396     if (GetOobeUI()) {
397       GetOobeUI()->GetCoreOobeActor()->ShowControlBar(false);
398       if (login::LoginScrollIntoViewEnabled())
399         GetOobeUI()->GetCoreOobeActor()->SetKeyboardState(true, new_bounds);
400     }
401   }
402 
403   keyboard_bounds_ = new_bounds;
404 }
405 
406 }  // namespace chromeos
407