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. 45 void DisableKeyboardOverscroll() { 46 keyboard::SetKeyboardOverscrollOverride( 47 keyboard::KEYBOARD_OVERSCROLL_OVERRIDE_DISABLED); 48 } 49 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 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 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 112 void WebUIScreenLocker::ScreenLockReady() { 113 UMA_HISTOGRAM_TIMES("LockScreen.LockReady", 114 base::TimeTicks::Now() - lock_time_); 115 ScreenLockerDelegate::ScreenLockReady(); 116 SetInputEnabled(true); 117 } 118 119 void WebUIScreenLocker::OnAuthenticate() { 120 } 121 122 void WebUIScreenLocker::SetInputEnabled(bool enabled) { 123 login_display_->SetUIEnabled(enabled); 124 } 125 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 134 void WebUIScreenLocker::AnimateAuthenticationSuccess() { 135 GetWebUI()->CallJavascriptFunction("cr.ui.Oobe.animateAuthenticationSuccess"); 136 } 137 138 void WebUIScreenLocker::ClearErrors() { 139 GetWebUI()->CallJavascriptFunction("cr.ui.Oobe.clearErrors"); 140 } 141 142 gfx::NativeWindow WebUIScreenLocker::GetNativeWindow() const { 143 return lock_window_->GetNativeWindow(); 144 } 145 146 content::WebUI* WebUIScreenLocker::GetAssociatedWebUI() { 147 return GetWebUI(); 148 } 149 150 void WebUIScreenLocker::FocusUserPod() { 151 if (!webui_ready_) 152 return; 153 webui_login_->RequestFocus(); 154 GetWebUI()->CallJavascriptFunction("cr.ui.Oobe.forceLockedUserPodFocus"); 155 } 156 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 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 193 void WebUIScreenLocker::OnLockBackgroundDisplayed() { 194 UMA_HISTOGRAM_TIMES("LockScreen.BackgroundReady", 195 base::TimeTicks::Now() - lock_time_); 196 } 197 198 OobeUI* WebUIScreenLocker::GetOobeUI() { 199 return static_cast<OobeUI*>(GetWebUI()->GetController()); 200 } 201 202 //////////////////////////////////////////////////////////////////////////////// 203 // WebUIScreenLocker, content::NotificationObserver implementation: 204 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 224 void WebUIScreenLocker::CancelPasswordChangedFlow() { 225 NOTREACHED(); 226 } 227 228 void WebUIScreenLocker::CreateAccount() { 229 NOTREACHED(); 230 } 231 232 void WebUIScreenLocker::CompleteLogin(const UserContext& user_context) { 233 NOTREACHED(); 234 } 235 236 base::string16 WebUIScreenLocker::GetConnectedNetworkName() { 237 return network_state_helper_->GetCurrentNetworkName(); 238 } 239 240 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 246 void WebUIScreenLocker::Login(const UserContext& user_context, 247 const SigninSpecifics& specifics) { 248 chromeos::ScreenLocker::default_screen_locker()->Authenticate(user_context); 249 } 250 251 void WebUIScreenLocker::MigrateUserData(const std::string& old_password) { 252 NOTREACHED(); 253 } 254 255 void WebUIScreenLocker::OnSigninScreenReady() { 256 } 257 258 void WebUIScreenLocker::OnStartEnterpriseEnrollment() { 259 NOTREACHED(); 260 } 261 262 void WebUIScreenLocker::OnStartKioskEnableScreen() { 263 NOTREACHED(); 264 } 265 266 void WebUIScreenLocker::OnStartKioskAutolaunchScreen() { 267 NOTREACHED(); 268 } 269 270 void WebUIScreenLocker::ShowWrongHWIDScreen() { 271 NOTREACHED(); 272 } 273 274 void WebUIScreenLocker::ResetPublicSessionAutoLoginTimer() { 275 } 276 277 void WebUIScreenLocker::ResyncUserData() { 278 NOTREACHED(); 279 } 280 281 void WebUIScreenLocker::SetDisplayEmail(const std::string& email) { 282 NOTREACHED(); 283 } 284 285 void WebUIScreenLocker::Signout() { 286 chromeos::ScreenLocker::default_screen_locker()->Signout(); 287 } 288 289 //////////////////////////////////////////////////////////////////////////////// 290 // LockWindow::Observer implementation: 291 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 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 315 void WebUIScreenLocker::OnWidgetDestroying(views::Widget* widget) { 316 lock_window_->RemoveObserver(this); 317 lock_window_ = NULL; 318 } 319 320 //////////////////////////////////////////////////////////////////////////////// 321 // PowerManagerClient::Observer overrides. 322 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 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 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 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 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