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