1 // Copyright (c) 2012 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/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/screen_locker.h" 19 #include "chrome/browser/chromeos/login/user_manager.h" 20 #include "chrome/browser/chromeos/login/webui_login_display.h" 21 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" 22 #include "chrome/common/url_constants.h" 23 #include "chromeos/dbus/dbus_thread_manager.h" 24 #include "content/public/browser/browser_thread.h" 25 #include "content/public/browser/notification_service.h" 26 #include "content/public/browser/notification_types.h" 27 #include "content/public/browser/render_widget_host_view.h" 28 #include "content/public/browser/web_ui.h" 29 #include "ui/aura/client/capture_client.h" 30 #include "ui/base/l10n/l10n_util.h" 31 #include "ui/base/x/x11_util.h" 32 #include "ui/gfx/screen.h" 33 #include "ui/views/controls/webview/webview.h" 34 35 namespace { 36 37 // URL which corresponds to the login WebUI. 38 const char kLoginURL[] = "chrome://oobe/login#lock"; 39 40 } // namespace 41 42 namespace chromeos { 43 44 //////////////////////////////////////////////////////////////////////////////// 45 // WebUIScreenLocker implementation. 46 47 WebUIScreenLocker::WebUIScreenLocker(ScreenLocker* screen_locker) 48 : ScreenLockerDelegate(screen_locker), 49 lock_ready_(false), 50 webui_ready_(false), 51 network_state_helper_(new login::NetworkStateHelper), 52 weak_factory_(this) { 53 set_should_emit_login_prompt_visible(false); 54 ash::Shell::GetInstance()->lock_state_controller()->AddObserver(this); 55 DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this); 56 } 57 58 void WebUIScreenLocker::LockScreen() { 59 gfx::Rect bounds(ash::Shell::GetScreen()->GetPrimaryDisplay().bounds()); 60 61 lock_time_ = base::TimeTicks::Now(); 62 LockWindow* lock_window = LockWindow::Create(); 63 lock_window->set_observer(this); 64 lock_window_ = lock_window->GetWidget(); 65 lock_window_->AddObserver(this); 66 WebUILoginView::Init(lock_window_); 67 lock_window_->SetContentsView(this); 68 lock_window_->Show(); 69 OnWindowCreated(); 70 LoadURL(GURL(kLoginURL)); 71 lock_window->Grab(); 72 73 // Subscribe to crash events. 74 content::WebContentsObserver::Observe(GetWebContents()); 75 76 login_display_.reset(new WebUILoginDisplay(this)); 77 login_display_->set_background_bounds(bounds); 78 login_display_->set_parent_window(GetNativeWindow()); 79 login_display_->Init(screen_locker()->users(), false, true, false); 80 81 static_cast<OobeUI*>(GetWebUI()->GetController())->ShowSigninScreen( 82 login_display_.get(), login_display_.get()); 83 84 registrar_.Add(this, 85 chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED, 86 content::NotificationService::AllSources()); 87 registrar_.Add(this, 88 chrome::NOTIFICATION_LOCK_WEBUI_READY, 89 content::NotificationService::AllSources()); 90 registrar_.Add(this, 91 chrome::NOTIFICATION_LOCK_BACKGROUND_DISPLAYED, 92 content::NotificationService::AllSources()); 93 } 94 95 void WebUIScreenLocker::ScreenLockReady() { 96 UMA_HISTOGRAM_TIMES("LockScreen.LockReady", 97 base::TimeTicks::Now() - lock_time_); 98 ScreenLockerDelegate::ScreenLockReady(); 99 SetInputEnabled(true); 100 } 101 102 void WebUIScreenLocker::OnAuthenticate() { 103 } 104 105 void WebUIScreenLocker::SetInputEnabled(bool enabled) { 106 login_display_->SetUIEnabled(enabled); 107 } 108 109 void WebUIScreenLocker::ShowErrorMessage( 110 int error_msg_id, 111 HelpAppLauncher::HelpTopic help_topic_id) { 112 login_display_->ShowError(error_msg_id, 113 0 /* login_attempts */, 114 help_topic_id); 115 } 116 117 void WebUIScreenLocker::AnimateAuthenticationSuccess() { 118 GetWebUI()->CallJavascriptFunction("cr.ui.Oobe.animateAuthenticationSuccess"); 119 } 120 121 void WebUIScreenLocker::ClearErrors() { 122 GetWebUI()->CallJavascriptFunction("cr.ui.Oobe.clearErrors"); 123 } 124 125 gfx::NativeWindow WebUIScreenLocker::GetNativeWindow() const { 126 return lock_window_->GetNativeWindow(); 127 } 128 129 content::WebUI* WebUIScreenLocker::GetAssociatedWebUI() { 130 return GetWebUI(); 131 } 132 133 void WebUIScreenLocker::FocusUserPod() { 134 if (!webui_ready_) 135 return; 136 webui_login_->RequestFocus(); 137 GetWebUI()->CallJavascriptFunction("cr.ui.Oobe.forceLockedUserPodFocus"); 138 } 139 140 WebUIScreenLocker::~WebUIScreenLocker() { 141 DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this); 142 ash::Shell::GetInstance()-> 143 lock_state_controller()->RemoveObserver(this); 144 // In case of shutdown, lock_window_ may be deleted before WebUIScreenLocker. 145 if (lock_window_) { 146 lock_window_->RemoveObserver(this); 147 lock_window_->Close(); 148 } 149 // If LockScreen() was called, we need to clear the signin screen handler 150 // delegate set in ShowSigninScreen so that it no longer points to us. 151 if (login_display_.get()) { 152 static_cast<OobeUI*>(GetWebUI()->GetController())-> 153 ResetSigninScreenHandlerDelegate(); 154 } 155 } 156 157 //////////////////////////////////////////////////////////////////////////////// 158 // WebUIScreenLocker, content::NotificationObserver implementation: 159 160 void WebUIScreenLocker::Observe( 161 int type, 162 const content::NotificationSource& source, 163 const content::NotificationDetails& details) { 164 switch (type) { 165 case chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED: { 166 const User& user = *content::Details<User>(details).ptr(); 167 login_display_->OnUserImageChanged(user); 168 break; 169 } 170 case chrome::NOTIFICATION_LOCK_WEBUI_READY: { 171 VLOG(1) << "WebUI ready; lock window is " 172 << (lock_ready_ ? "too" : "not"); 173 webui_ready_ = true; 174 if (lock_ready_) 175 ScreenLockReady(); 176 break; 177 } 178 case chrome::NOTIFICATION_LOCK_BACKGROUND_DISPLAYED: { 179 UMA_HISTOGRAM_TIMES("LockScreen.BackgroundReady", 180 base::TimeTicks::Now() - lock_time_); 181 break; 182 } 183 default: 184 WebUILoginView::Observe(type, source, details); 185 } 186 } 187 188 //////////////////////////////////////////////////////////////////////////////// 189 // WebUIScreenLocker, LoginDisplay::Delegate implementation: 190 191 void WebUIScreenLocker::CancelPasswordChangedFlow() { 192 NOTREACHED(); 193 } 194 195 void WebUIScreenLocker::CreateAccount() { 196 NOTREACHED(); 197 } 198 199 void WebUIScreenLocker::CompleteLogin(const UserContext& user_context) { 200 NOTREACHED(); 201 } 202 203 string16 WebUIScreenLocker::GetConnectedNetworkName() { 204 return network_state_helper_->GetCurrentNetworkName(); 205 } 206 207 bool WebUIScreenLocker::IsSigninInProgress() const { 208 // The way how screen locker is implemented right now there's no 209 // GAIA sign in in progress in any case. 210 return false; 211 } 212 213 void WebUIScreenLocker::Login(const UserContext& user_context) { 214 chromeos::ScreenLocker::default_screen_locker()->Authenticate(user_context); 215 } 216 217 void WebUIScreenLocker::LoginAsRetailModeUser() { 218 NOTREACHED(); 219 } 220 221 void WebUIScreenLocker::LoginAsGuest() { 222 NOTREACHED(); 223 } 224 225 void WebUIScreenLocker::MigrateUserData(const std::string& old_password) { 226 NOTREACHED(); 227 } 228 229 void WebUIScreenLocker::LoginAsPublicAccount(const std::string& username) { 230 NOTREACHED(); 231 } 232 233 void WebUIScreenLocker::OnSigninScreenReady() { 234 } 235 236 void WebUIScreenLocker::OnUserSelected(const std::string& username) { 237 } 238 239 void WebUIScreenLocker::OnStartEnterpriseEnrollment() { 240 NOTREACHED(); 241 } 242 243 void WebUIScreenLocker::OnStartKioskEnableScreen() { 244 NOTREACHED(); 245 } 246 247 void WebUIScreenLocker::OnStartDeviceReset() { 248 NOTREACHED(); 249 } 250 251 void WebUIScreenLocker::OnStartKioskAutolaunchScreen() { 252 NOTREACHED(); 253 } 254 255 void WebUIScreenLocker::ShowWrongHWIDScreen() { 256 NOTREACHED(); 257 } 258 259 void WebUIScreenLocker::ResetPublicSessionAutoLoginTimer() { 260 } 261 262 void WebUIScreenLocker::ResyncUserData() { 263 NOTREACHED(); 264 } 265 266 void WebUIScreenLocker::SetDisplayEmail(const std::string& email) { 267 NOTREACHED(); 268 } 269 270 void WebUIScreenLocker::Signout() { 271 chromeos::ScreenLocker::default_screen_locker()->Signout(); 272 } 273 274 //////////////////////////////////////////////////////////////////////////////// 275 // LockWindow::Observer implementation: 276 277 void WebUIScreenLocker::OnLockWindowReady() { 278 VLOG(1) << "Lock window ready; WebUI is " << (webui_ready_ ? "too" : "not"); 279 lock_ready_ = true; 280 if (webui_ready_) 281 ScreenLockReady(); 282 } 283 284 //////////////////////////////////////////////////////////////////////////////// 285 // SessionLockStateObserver override. 286 287 void WebUIScreenLocker::OnLockStateEvent( 288 ash::LockStateObserver::EventType event) { 289 if (event == ash::LockStateObserver::EVENT_LOCK_ANIMATION_FINISHED) { 290 // Release capture if any. 291 aura::client::GetCaptureClient(GetNativeWindow()->GetRootWindow())-> 292 SetCapture(NULL); 293 GetWebUI()->CallJavascriptFunction("cr.ui.Oobe.animateOnceFullyDisplayed"); 294 } 295 } 296 297 //////////////////////////////////////////////////////////////////////////////// 298 // WidgetObserver override. 299 300 void WebUIScreenLocker::OnWidgetDestroying(views::Widget* widget) { 301 lock_window_->RemoveObserver(this); 302 lock_window_ = NULL; 303 } 304 305 //////////////////////////////////////////////////////////////////////////////// 306 // PowerManagerClient::Observer overrides. 307 308 void WebUIScreenLocker::LidEventReceived(bool open, 309 const base::TimeTicks& time) { 310 content::BrowserThread::PostTask( 311 content::BrowserThread::UI, 312 FROM_HERE, 313 base::Bind(&WebUIScreenLocker::FocusUserPod, weak_factory_.GetWeakPtr())); 314 } 315 316 void WebUIScreenLocker::SystemResumed(const base::TimeDelta& sleep_duration) { 317 content::BrowserThread::PostTask( 318 content::BrowserThread::UI, 319 FROM_HERE, 320 base::Bind(&WebUIScreenLocker::FocusUserPod, weak_factory_.GetWeakPtr())); 321 } 322 323 void WebUIScreenLocker::RenderProcessGone(base::TerminationStatus status) { 324 if (browser_shutdown::GetShutdownType() == browser_shutdown::NOT_VALID && 325 status != base::TERMINATION_STATUS_NORMAL_TERMINATION) { 326 LOG(ERROR) << "Renderer crash on lock screen"; 327 Signout(); 328 } 329 } 330 331 } // namespace chromeos 332