Home | History | Annotate | Download | only in lock
      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