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_ = 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 113void WebUIScreenLocker::ScreenLockReady() { 114 UMA_HISTOGRAM_TIMES("LockScreen.LockReady", 115 base::TimeTicks::Now() - lock_time_); 116 ScreenLockerDelegate::ScreenLockReady(); 117 SetInputEnabled(true); 118} 119 120void WebUIScreenLocker::OnAuthenticate() { 121} 122 123void WebUIScreenLocker::SetInputEnabled(bool enabled) { 124 login_display_->SetUIEnabled(enabled); 125} 126 127void 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 135void WebUIScreenLocker::AnimateAuthenticationSuccess() { 136 GetWebUI()->CallJavascriptFunction("cr.ui.Oobe.animateAuthenticationSuccess"); 137} 138 139void WebUIScreenLocker::ClearErrors() { 140 GetWebUI()->CallJavascriptFunction("cr.ui.Oobe.clearErrors"); 141} 142 143gfx::NativeWindow WebUIScreenLocker::GetNativeWindow() const { 144 return lock_window_->GetNativeWindow(); 145} 146 147content::WebUI* WebUIScreenLocker::GetAssociatedWebUI() { 148 return GetWebUI(); 149} 150 151void WebUIScreenLocker::FocusUserPod() { 152 if (!webui_ready_) 153 return; 154 webui_login_->RequestFocus(); 155 GetWebUI()->CallJavascriptFunction("cr.ui.Oobe.forceLockedUserPodFocus"); 156} 157 158WebUIScreenLocker::~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 186void 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 194void WebUIScreenLocker::OnLockBackgroundDisplayed() { 195 UMA_HISTOGRAM_TIMES("LockScreen.BackgroundReady", 196 base::TimeTicks::Now() - lock_time_); 197} 198 199OobeUI* WebUIScreenLocker::GetOobeUI() { 200 return static_cast<OobeUI*>(GetWebUI()->GetController()); 201} 202 203//////////////////////////////////////////////////////////////////////////////// 204// WebUIScreenLocker, content::NotificationObserver implementation: 205 206void 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 224void WebUIScreenLocker::CancelPasswordChangedFlow() { 225 NOTREACHED(); 226} 227 228void WebUIScreenLocker::CreateAccount() { 229 NOTREACHED(); 230} 231 232void WebUIScreenLocker::CompleteLogin(const UserContext& user_context) { 233 NOTREACHED(); 234} 235 236base::string16 WebUIScreenLocker::GetConnectedNetworkName() { 237 return network_state_helper_->GetCurrentNetworkName(); 238} 239 240bool 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 246void WebUIScreenLocker::Login(const UserContext& user_context) { 247 chromeos::ScreenLocker::default_screen_locker()->Authenticate(user_context); 248} 249 250void WebUIScreenLocker::LoginAsRetailModeUser() { 251 NOTREACHED(); 252} 253 254void WebUIScreenLocker::LoginAsGuest() { 255 NOTREACHED(); 256} 257 258void WebUIScreenLocker::MigrateUserData(const std::string& old_password) { 259 NOTREACHED(); 260} 261 262void WebUIScreenLocker::LoginAsPublicAccount(const std::string& username) { 263 NOTREACHED(); 264} 265 266void WebUIScreenLocker::OnSigninScreenReady() { 267} 268 269void WebUIScreenLocker::OnUserSelected(const std::string& username) { 270} 271 272void WebUIScreenLocker::OnStartEnterpriseEnrollment() { 273 NOTREACHED(); 274} 275 276void WebUIScreenLocker::OnStartKioskEnableScreen() { 277 NOTREACHED(); 278} 279 280void WebUIScreenLocker::OnStartKioskAutolaunchScreen() { 281 NOTREACHED(); 282} 283 284void WebUIScreenLocker::ShowWrongHWIDScreen() { 285 NOTREACHED(); 286} 287 288void WebUIScreenLocker::ResetPublicSessionAutoLoginTimer() { 289} 290 291void WebUIScreenLocker::ResyncUserData() { 292 NOTREACHED(); 293} 294 295void WebUIScreenLocker::SetDisplayEmail(const std::string& email) { 296 NOTREACHED(); 297} 298 299void WebUIScreenLocker::Signout() { 300 chromeos::ScreenLocker::default_screen_locker()->Signout(); 301} 302 303void WebUIScreenLocker::LoginAsKioskApp(const std::string& app_id, 304 bool diagnostic_mode) { 305 NOTREACHED(); 306} 307 308//////////////////////////////////////////////////////////////////////////////// 309// LockWindow::Observer implementation: 310 311void 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 321void 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 334void WebUIScreenLocker::OnWidgetDestroying(views::Widget* widget) { 335 lock_window_->RemoveObserver(this); 336 lock_window_ = NULL; 337} 338 339//////////////////////////////////////////////////////////////////////////////// 340// PowerManagerClient::Observer overrides. 341 342void 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 350void 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 357void 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 368void 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 385void 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