webui_screen_locker.cc revision 116680a4aac90f2aa7413d9095a592090648e557
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 40namespace { 41 42// URL which corresponds to the login WebUI. 43const 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. 47void DisableKeyboardOverscroll() { 48 keyboard::SetKeyboardOverscrollOverride( 49 keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_DISABLED); 50} 51 52void ResetKeyboardOverscrollOverride() { 53 keyboard::SetKeyboardOverscrollOverride( 54 keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_NONE); 55} 56 57} // namespace 58 59namespace chromeos { 60 61//////////////////////////////////////////////////////////////////////////////// 62// WebUIScreenLocker implementation. 63 64WebUIScreenLocker::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 83void 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->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_->Show(); 95 LoadURL(GURL(kLoginURL)); 96 lock_window->Grab(); 97 98 login_display_.reset(new WebUILoginDisplay(this)); 99 login_display_->set_background_bounds(bounds); 100 login_display_->set_parent_window(GetNativeWindow()); 101 login_display_->Init(screen_locker()->users(), false, true, false); 102 103 GetOobeUI()->ShowSigninScreen( 104 LoginScreenContext(), login_display_.get(), login_display_.get()); 105 106 registrar_.Add(this, 107 chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED, 108 content::NotificationService::AllSources()); 109 110 if (login::LoginScrollIntoViewEnabled()) 111 DisableKeyboardOverscroll(); 112} 113 114void WebUIScreenLocker::ScreenLockReady() { 115 UMA_HISTOGRAM_TIMES("LockScreen.LockReady", 116 base::TimeTicks::Now() - lock_time_); 117 ScreenLockerDelegate::ScreenLockReady(); 118 SetInputEnabled(true); 119} 120 121void WebUIScreenLocker::OnAuthenticate() { 122} 123 124void WebUIScreenLocker::SetInputEnabled(bool enabled) { 125 login_display_->SetUIEnabled(enabled); 126} 127 128void WebUIScreenLocker::ShowErrorMessage( 129 int error_msg_id, 130 HelpAppLauncher::HelpTopic help_topic_id) { 131 login_display_->ShowError(error_msg_id, 132 0 /* login_attempts */, 133 help_topic_id); 134} 135 136void WebUIScreenLocker::AnimateAuthenticationSuccess() { 137 GetWebUI()->CallJavascriptFunction("cr.ui.Oobe.animateAuthenticationSuccess"); 138} 139 140void WebUIScreenLocker::ClearErrors() { 141 GetWebUI()->CallJavascriptFunction("cr.ui.Oobe.clearErrors"); 142} 143 144gfx::NativeWindow WebUIScreenLocker::GetNativeWindow() const { 145 return lock_window_->GetNativeWindow(); 146} 147 148content::WebUI* WebUIScreenLocker::GetAssociatedWebUI() { 149 return GetWebUI(); 150} 151 152void WebUIScreenLocker::FocusUserPod() { 153 if (!webui_ready_) 154 return; 155 webui_login_->RequestFocus(); 156 GetWebUI()->CallJavascriptFunction("cr.ui.Oobe.forceLockedUserPodFocus"); 157} 158 159WebUIScreenLocker::~WebUIScreenLocker() { 160 DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this); 161 ash::Shell::GetInstance()-> 162 lock_state_controller()->RemoveObserver(this); 163 // In case of shutdown, lock_window_ may be deleted before WebUIScreenLocker. 164 if (lock_window_) { 165 lock_window_->RemoveObserver(this); 166 lock_window_->Close(); 167 } 168 // If LockScreen() was called, we need to clear the signin screen handler 169 // delegate set in ShowSigninScreen so that it no longer points to us. 170 if (login_display_.get()) { 171 static_cast<OobeUI*>(GetWebUI()->GetController())-> 172 ResetSigninScreenHandlerDelegate(); 173 } 174 175 if (keyboard::KeyboardController::GetInstance() && is_observing_keyboard_) { 176 keyboard::KeyboardController::GetInstance()->RemoveObserver(this); 177 is_observing_keyboard_ = false; 178 } 179 180 ash::Shell::GetInstance()->delegate()-> 181 RemoveVirtualKeyboardStateObserver(this); 182 183 if (login::LoginScrollIntoViewEnabled()) 184 ResetKeyboardOverscrollOverride(); 185} 186 187void WebUIScreenLocker::OnLockWebUIReady() { 188 VLOG(1) << "WebUI ready; lock window is " 189 << (lock_ready_ ? "too" : "not"); 190 webui_ready_ = true; 191 if (lock_ready_) 192 ScreenLockReady(); 193} 194 195void WebUIScreenLocker::OnLockBackgroundDisplayed() { 196 UMA_HISTOGRAM_TIMES("LockScreen.BackgroundReady", 197 base::TimeTicks::Now() - lock_time_); 198} 199 200OobeUI* WebUIScreenLocker::GetOobeUI() { 201 return static_cast<OobeUI*>(GetWebUI()->GetController()); 202} 203 204//////////////////////////////////////////////////////////////////////////////// 205// WebUIScreenLocker, content::NotificationObserver implementation: 206 207void WebUIScreenLocker::Observe( 208 int type, 209 const content::NotificationSource& source, 210 const content::NotificationDetails& details) { 211 switch (type) { 212 case chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED: { 213 const User& user = *content::Details<User>(details).ptr(); 214 login_display_->OnUserImageChanged(user); 215 break; 216 } 217 default: 218 WebUILoginView::Observe(type, source, details); 219 } 220} 221 222//////////////////////////////////////////////////////////////////////////////// 223// WebUIScreenLocker, LoginDisplay::Delegate implementation: 224 225void WebUIScreenLocker::CancelPasswordChangedFlow() { 226 NOTREACHED(); 227} 228 229void WebUIScreenLocker::CreateAccount() { 230 NOTREACHED(); 231} 232 233void WebUIScreenLocker::CompleteLogin(const UserContext& user_context) { 234 NOTREACHED(); 235} 236 237base::string16 WebUIScreenLocker::GetConnectedNetworkName() { 238 return network_state_helper_->GetCurrentNetworkName(); 239} 240 241bool WebUIScreenLocker::IsSigninInProgress() const { 242 // The way how screen locker is implemented right now there's no 243 // GAIA sign in in progress in any case. 244 return false; 245} 246 247void WebUIScreenLocker::Login(const UserContext& user_context, 248 const SigninSpecifics& specifics) { 249 chromeos::ScreenLocker::default_screen_locker()->Authenticate(user_context); 250} 251 252void WebUIScreenLocker::MigrateUserData(const std::string& old_password) { 253 NOTREACHED(); 254} 255 256void WebUIScreenLocker::OnSigninScreenReady() { 257} 258 259void WebUIScreenLocker::OnStartEnterpriseEnrollment() { 260 NOTREACHED(); 261} 262 263void WebUIScreenLocker::OnStartKioskEnableScreen() { 264 NOTREACHED(); 265} 266 267void WebUIScreenLocker::OnStartKioskAutolaunchScreen() { 268 NOTREACHED(); 269} 270 271void WebUIScreenLocker::ShowWrongHWIDScreen() { 272 NOTREACHED(); 273} 274 275void WebUIScreenLocker::ResetPublicSessionAutoLoginTimer() { 276} 277 278void WebUIScreenLocker::ResyncUserData() { 279 NOTREACHED(); 280} 281 282void WebUIScreenLocker::SetDisplayEmail(const std::string& email) { 283 NOTREACHED(); 284} 285 286void WebUIScreenLocker::Signout() { 287 chromeos::ScreenLocker::default_screen_locker()->Signout(); 288} 289 290//////////////////////////////////////////////////////////////////////////////// 291// LockWindow::Observer implementation: 292 293void WebUIScreenLocker::OnLockWindowReady() { 294 VLOG(1) << "Lock window ready; WebUI is " << (webui_ready_ ? "too" : "not"); 295 lock_ready_ = true; 296 if (webui_ready_) 297 ScreenLockReady(); 298} 299 300//////////////////////////////////////////////////////////////////////////////// 301// SessionLockStateObserver override. 302 303void 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())-> 308 SetCapture(NULL); 309 GetWebUI()->CallJavascriptFunction("cr.ui.Oobe.animateOnceFullyDisplayed"); 310 } 311} 312 313//////////////////////////////////////////////////////////////////////////////// 314// WidgetObserver override. 315 316void WebUIScreenLocker::OnWidgetDestroying(views::Widget* widget) { 317 lock_window_->RemoveObserver(this); 318 lock_window_ = NULL; 319} 320 321//////////////////////////////////////////////////////////////////////////////// 322// PowerManagerClient::Observer overrides. 323 324void WebUIScreenLocker::LidEventReceived(bool open, 325 const base::TimeTicks& time) { 326 content::BrowserThread::PostTask( 327 content::BrowserThread::UI, 328 FROM_HERE, 329 base::Bind(&WebUIScreenLocker::FocusUserPod, weak_factory_.GetWeakPtr())); 330} 331 332void WebUIScreenLocker::SuspendDone(const base::TimeDelta& sleep_duration) { 333 content::BrowserThread::PostTask( 334 content::BrowserThread::UI, 335 FROM_HERE, 336 base::Bind(&WebUIScreenLocker::FocusUserPod, weak_factory_.GetWeakPtr())); 337} 338 339void WebUIScreenLocker::RenderProcessGone(base::TerminationStatus status) { 340 if (browser_shutdown::GetShutdownType() == browser_shutdown::NOT_VALID && 341 status != base::TERMINATION_STATUS_NORMAL_TERMINATION) { 342 LOG(ERROR) << "Renderer crash on lock screen"; 343 Signout(); 344 } 345} 346 347//////////////////////////////////////////////////////////////////////////////// 348// ash::KeyboardStateObserver overrides. 349 350void WebUIScreenLocker::OnVirtualKeyboardStateChanged(bool activated) { 351 if (keyboard::KeyboardController::GetInstance()) { 352 if (activated) { 353 if (!is_observing_keyboard_) { 354 keyboard::KeyboardController::GetInstance()->AddObserver(this); 355 is_observing_keyboard_ = true; 356 } 357 } else { 358 keyboard::KeyboardController::GetInstance()->RemoveObserver(this); 359 is_observing_keyboard_ = false; 360 } 361 } 362} 363 364//////////////////////////////////////////////////////////////////////////////// 365// keyboard::KeyboardControllerObserver overrides. 366 367void WebUIScreenLocker::OnKeyboardBoundsChanging( 368 const gfx::Rect& new_bounds) { 369 if (new_bounds.IsEmpty() && !keyboard_bounds_.IsEmpty()) { 370 // Keyboard has been hidden. 371 if (GetOobeUI()) { 372 GetOobeUI()->GetCoreOobeActor()->ShowControlBar(true); 373 if (login::LoginScrollIntoViewEnabled()) 374 GetOobeUI()->GetCoreOobeActor()->SetKeyboardState(false, new_bounds); 375 } 376 } else if (!new_bounds.IsEmpty() && keyboard_bounds_.IsEmpty()) { 377 // Keyboard has been shown. 378 if (GetOobeUI()) { 379 GetOobeUI()->GetCoreOobeActor()->ShowControlBar(false); 380 if (login::LoginScrollIntoViewEnabled()) 381 GetOobeUI()->GetCoreOobeActor()->SetKeyboardState(true, new_bounds); 382 } 383 } 384 385 keyboard_bounds_ = new_bounds; 386} 387 388} // namespace chromeos 389