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 38namespace { 39 40// URL which corresponds to the login WebUI. 41const 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. 45void DisableKeyboardOverscroll() { 46 keyboard::SetKeyboardOverscrollOverride( 47 keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_DISABLED); 48} 49 50void ResetKeyboardOverscrollOverride() { 51 keyboard::SetKeyboardOverscrollOverride( 52 keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_NONE); 53} 54 55} // namespace 56 57namespace chromeos { 58 59//////////////////////////////////////////////////////////////////////////////// 60// WebUIScreenLocker implementation. 61 62WebUIScreenLocker::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 81void 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 112void WebUIScreenLocker::ScreenLockReady() { 113 UMA_HISTOGRAM_TIMES("LockScreen.LockReady", 114 base::TimeTicks::Now() - lock_time_); 115 ScreenLockerDelegate::ScreenLockReady(); 116 SetInputEnabled(true); 117} 118 119void WebUIScreenLocker::OnAuthenticate() { 120} 121 122void WebUIScreenLocker::SetInputEnabled(bool enabled) { 123 login_display_->SetUIEnabled(enabled); 124} 125 126void 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 134void WebUIScreenLocker::AnimateAuthenticationSuccess() { 135 GetWebUI()->CallJavascriptFunction("cr.ui.Oobe.animateAuthenticationSuccess"); 136} 137 138void WebUIScreenLocker::ClearErrors() { 139 GetWebUI()->CallJavascriptFunction("cr.ui.Oobe.clearErrors"); 140} 141 142gfx::NativeWindow WebUIScreenLocker::GetNativeWindow() const { 143 return lock_window_->GetNativeWindow(); 144} 145 146content::WebUI* WebUIScreenLocker::GetAssociatedWebUI() { 147 return GetWebUI(); 148} 149 150void WebUIScreenLocker::FocusUserPod() { 151 if (!webui_ready_) 152 return; 153 webui_login_->RequestFocus(); 154 GetWebUI()->CallJavascriptFunction("cr.ui.Oobe.forceLockedUserPodFocus"); 155} 156 157WebUIScreenLocker::~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 185void 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 193void WebUIScreenLocker::OnLockBackgroundDisplayed() { 194 UMA_HISTOGRAM_TIMES("LockScreen.BackgroundReady", 195 base::TimeTicks::Now() - lock_time_); 196} 197 198OobeUI* WebUIScreenLocker::GetOobeUI() { 199 return static_cast<OobeUI*>(GetWebUI()->GetController()); 200} 201 202//////////////////////////////////////////////////////////////////////////////// 203// WebUIScreenLocker, content::NotificationObserver implementation: 204 205void 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 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 const SigninSpecifics& specifics) { 248 chromeos::ScreenLocker::default_screen_locker()->Authenticate(user_context); 249} 250 251void WebUIScreenLocker::MigrateUserData(const std::string& old_password) { 252 NOTREACHED(); 253} 254 255void WebUIScreenLocker::OnSigninScreenReady() { 256} 257 258void WebUIScreenLocker::OnStartEnterpriseEnrollment() { 259 NOTREACHED(); 260} 261 262void WebUIScreenLocker::OnStartKioskEnableScreen() { 263 NOTREACHED(); 264} 265 266void WebUIScreenLocker::OnStartKioskAutolaunchScreen() { 267 NOTREACHED(); 268} 269 270void WebUIScreenLocker::ShowWrongHWIDScreen() { 271 NOTREACHED(); 272} 273 274void WebUIScreenLocker::ResetPublicSessionAutoLoginTimer() { 275} 276 277void WebUIScreenLocker::ResyncUserData() { 278 NOTREACHED(); 279} 280 281void WebUIScreenLocker::SetDisplayEmail(const std::string& email) { 282 NOTREACHED(); 283} 284 285void WebUIScreenLocker::Signout() { 286 chromeos::ScreenLocker::default_screen_locker()->Signout(); 287} 288 289//////////////////////////////////////////////////////////////////////////////// 290// LockWindow::Observer implementation: 291 292void 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 302void 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 315void WebUIScreenLocker::OnWidgetDestroying(views::Widget* widget) { 316 lock_window_->RemoveObserver(this); 317 lock_window_ = NULL; 318} 319 320//////////////////////////////////////////////////////////////////////////////// 321// PowerManagerClient::Observer overrides. 322 323void 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 331void 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 338void 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 349void 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 366void 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