Home | History | Annotate | Download | only in signin
      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/signin/easy_unlock_screenlock_state_handler.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/strings/string16.h"
      9 #include "base/strings/utf_string_conversions.h"
     10 #include "chrome/browser/browser_process.h"
     11 #include "chrome/browser/chromeos/chromeos_utils.h"
     12 #include "chrome/grit/generated_resources.h"
     13 #include "ui/base/l10n/l10n_util.h"
     14 
     15 namespace {
     16 
     17 ScreenlockBridge::UserPodCustomIcon GetIconForState(
     18     EasyUnlockScreenlockStateHandler::State state) {
     19   switch (state) {
     20     case EasyUnlockScreenlockStateHandler::STATE_NO_BLUETOOTH:
     21     case EasyUnlockScreenlockStateHandler::STATE_NO_PHONE:
     22     case EasyUnlockScreenlockStateHandler::STATE_PHONE_NOT_AUTHENTICATED:
     23     case EasyUnlockScreenlockStateHandler::STATE_PHONE_LOCKED:
     24     case EasyUnlockScreenlockStateHandler::STATE_PHONE_NOT_NEARBY:
     25     case EasyUnlockScreenlockStateHandler::STATE_PHONE_UNLOCKABLE:
     26     case EasyUnlockScreenlockStateHandler::STATE_PHONE_UNSUPPORTED:
     27       return ScreenlockBridge::USER_POD_CUSTOM_ICON_LOCKED;
     28     case EasyUnlockScreenlockStateHandler::STATE_BLUETOOTH_CONNECTING:
     29       return ScreenlockBridge::USER_POD_CUSTOM_ICON_SPINNER;
     30     case EasyUnlockScreenlockStateHandler::STATE_AUTHENTICATED:
     31       return ScreenlockBridge::USER_POD_CUSTOM_ICON_UNLOCKED;
     32     default:
     33       return ScreenlockBridge::USER_POD_CUSTOM_ICON_NONE;
     34   }
     35 }
     36 
     37 bool HardlockOnClick(EasyUnlockScreenlockStateHandler::State state) {
     38   return state != EasyUnlockScreenlockStateHandler::STATE_INACTIVE;
     39 }
     40 
     41 size_t GetTooltipResourceId(EasyUnlockScreenlockStateHandler::State state) {
     42   switch (state) {
     43     case EasyUnlockScreenlockStateHandler::STATE_NO_BLUETOOTH:
     44       return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_NO_BLUETOOTH;
     45     case EasyUnlockScreenlockStateHandler::STATE_NO_PHONE:
     46       return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_NO_PHONE;
     47     case EasyUnlockScreenlockStateHandler::STATE_PHONE_NOT_AUTHENTICATED:
     48       return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_PHONE_NOT_AUTHENTICATED;
     49     case EasyUnlockScreenlockStateHandler::STATE_PHONE_LOCKED:
     50       return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_PHONE_LOCKED;
     51     case EasyUnlockScreenlockStateHandler::STATE_PHONE_UNLOCKABLE:
     52       return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_PHONE_UNLOCKABLE;
     53     case EasyUnlockScreenlockStateHandler::STATE_PHONE_NOT_NEARBY:
     54       return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_PHONE_NOT_NEARBY;
     55     case EasyUnlockScreenlockStateHandler::STATE_AUTHENTICATED:
     56       return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_INSTRUCTIONS;
     57     case EasyUnlockScreenlockStateHandler::STATE_PHONE_UNSUPPORTED:
     58       return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_UNSUPPORTED_ANDROID_VERSION;
     59     default:
     60       return 0;
     61   }
     62 }
     63 
     64 bool TooltipContainsDeviceType(EasyUnlockScreenlockStateHandler::State state) {
     65   return state == EasyUnlockScreenlockStateHandler::STATE_AUTHENTICATED ||
     66          state == EasyUnlockScreenlockStateHandler::STATE_PHONE_UNLOCKABLE ||
     67          state == EasyUnlockScreenlockStateHandler::STATE_NO_BLUETOOTH ||
     68          state == EasyUnlockScreenlockStateHandler::STATE_PHONE_UNSUPPORTED;
     69 }
     70 
     71 bool IsLocaleEnUS() {
     72   return g_browser_process->GetApplicationLocale() == "en-US";
     73 }
     74 
     75 }  // namespace
     76 
     77 
     78 EasyUnlockScreenlockStateHandler::EasyUnlockScreenlockStateHandler(
     79     const std::string& user_email,
     80     HardlockState initial_hardlock_state,
     81     ScreenlockBridge* screenlock_bridge)
     82     : state_(STATE_INACTIVE),
     83       user_email_(user_email),
     84       screenlock_bridge_(screenlock_bridge),
     85       hardlock_state_(initial_hardlock_state),
     86       hardlock_ui_shown_(false),
     87       is_trial_run_(false) {
     88   DCHECK(screenlock_bridge_);
     89   screenlock_bridge_->AddObserver(this);
     90 }
     91 
     92 EasyUnlockScreenlockStateHandler::~EasyUnlockScreenlockStateHandler() {
     93   screenlock_bridge_->RemoveObserver(this);
     94   // Make sure the screenlock state set by this gets cleared.
     95   ChangeState(STATE_INACTIVE);
     96 }
     97 
     98 bool EasyUnlockScreenlockStateHandler::IsActive() const {
     99   return state_ != STATE_INACTIVE;
    100 }
    101 
    102 void EasyUnlockScreenlockStateHandler::ChangeState(State new_state) {
    103   if (state_ == new_state)
    104     return;
    105 
    106   state_ = new_state;
    107 
    108   // If lock screen is not active or it forces offline password, just cache the
    109   // current state. The screenlock state will get refreshed in |ScreenDidLock|.
    110   if (!screenlock_bridge_->IsLocked())
    111     return;
    112 
    113   // No hardlock UI for trial run.
    114   if (!is_trial_run_ && hardlock_state_ != NO_HARDLOCK) {
    115     ShowHardlockUI();
    116     return;
    117   }
    118 
    119   UpdateScreenlockAuthType();
    120 
    121   ScreenlockBridge::UserPodCustomIcon icon = GetIconForState(state_);
    122 
    123   if (icon == ScreenlockBridge::USER_POD_CUSTOM_ICON_NONE) {
    124     screenlock_bridge_->lock_handler()->HideUserPodCustomIcon(user_email_);
    125     return;
    126   }
    127 
    128   ScreenlockBridge::UserPodCustomIconOptions icon_options;
    129   icon_options.SetIcon(icon);
    130 
    131   // Don't hardlock on trial run.
    132   if (!is_trial_run_ && HardlockOnClick(state_))
    133     icon_options.SetHardlockOnClick();
    134 
    135   UpdateTooltipOptions(is_trial_run_, &icon_options);
    136 
    137   // For states without tooltips, we still need to set an accessibility label.
    138   if (state_ == EasyUnlockScreenlockStateHandler::STATE_BLUETOOTH_CONNECTING) {
    139     icon_options.SetAriaLabel(
    140         l10n_util::GetStringUTF16(IDS_SMART_LOCK_SPINNER_ACCESSIBILITY_LABEL));
    141   }
    142 
    143   screenlock_bridge_->lock_handler()->ShowUserPodCustomIcon(user_email_,
    144                                                             icon_options);
    145 }
    146 
    147 void EasyUnlockScreenlockStateHandler::SetHardlockState(
    148     HardlockState new_state) {
    149   if (hardlock_state_ == new_state)
    150     return;
    151 
    152   hardlock_state_ = new_state;
    153 
    154   // If hardlock_state_ was set to NO_HARDLOCK, this means the screen is about
    155   // to get unlocked. No need to update it in this case.
    156   if (hardlock_state_ != NO_HARDLOCK) {
    157     hardlock_ui_shown_ = false;
    158 
    159     RefreshScreenlockState();
    160   }
    161 }
    162 
    163 void EasyUnlockScreenlockStateHandler::MaybeShowHardlockUI() {
    164   if (hardlock_state_ != NO_HARDLOCK)
    165     ShowHardlockUI();
    166 }
    167 
    168 void EasyUnlockScreenlockStateHandler::SetTrialRun() {
    169   if (is_trial_run_)
    170     return;
    171   is_trial_run_ = true;
    172   RefreshScreenlockState();
    173 }
    174 
    175 void EasyUnlockScreenlockStateHandler::OnScreenDidLock() {
    176   RefreshScreenlockState();
    177 }
    178 
    179 void EasyUnlockScreenlockStateHandler::OnScreenDidUnlock() {
    180   hardlock_ui_shown_ = false;
    181   is_trial_run_ = false;
    182 }
    183 
    184 void EasyUnlockScreenlockStateHandler::OnFocusedUserChanged(
    185     const std::string& user_id) {
    186 }
    187 
    188 void EasyUnlockScreenlockStateHandler::RefreshScreenlockState() {
    189   State last_state = state_;
    190   // This should force updating screenlock state.
    191   state_ = STATE_INACTIVE;
    192   ChangeState(last_state);
    193 }
    194 
    195 void EasyUnlockScreenlockStateHandler::ShowHardlockUI() {
    196   DCHECK(hardlock_state_ != NO_HARDLOCK);
    197 
    198   if (!screenlock_bridge_->IsLocked())
    199     return;
    200 
    201   // Do not override online signin.
    202   const ScreenlockBridge::LockHandler::AuthType existing_auth_type =
    203       screenlock_bridge_->lock_handler()->GetAuthType(user_email_);
    204   if (existing_auth_type == ScreenlockBridge::LockHandler::ONLINE_SIGN_IN)
    205     return;
    206 
    207   if (existing_auth_type != ScreenlockBridge::LockHandler::OFFLINE_PASSWORD) {
    208     screenlock_bridge_->lock_handler()->SetAuthType(
    209         user_email_,
    210         ScreenlockBridge::LockHandler::OFFLINE_PASSWORD,
    211         base::string16());
    212   }
    213 
    214   if (hardlock_state_ == NO_PAIRING) {
    215     screenlock_bridge_->lock_handler()->HideUserPodCustomIcon(user_email_);
    216     hardlock_ui_shown_ = false;
    217     return;
    218   }
    219 
    220   if (hardlock_ui_shown_)
    221     return;
    222 
    223   ScreenlockBridge::UserPodCustomIconOptions icon_options;
    224   icon_options.SetIcon(ScreenlockBridge::USER_POD_CUSTOM_ICON_HARDLOCKED);
    225 
    226   // TODO(tbarzic): Remove this condition for M-40.
    227   if (IsLocaleEnUS()) {
    228     base::string16 tooltip;
    229     if (hardlock_state_ == USER_HARDLOCK) {
    230       tooltip = l10n_util::GetStringFUTF16(
    231           IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_USER, GetDeviceName());
    232     } else if (hardlock_state_ == PAIRING_CHANGED) {
    233       tooltip = l10n_util::GetStringUTF16(
    234           IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_PAIRING_CHANGED);
    235     } else if (hardlock_state_ == PAIRING_ADDED) {
    236       tooltip = l10n_util::GetStringUTF16(
    237           IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_PAIRING_ADDED);
    238     } else {
    239       LOG(ERROR) << "Unknown hardlock state " << hardlock_state_;
    240     }
    241     icon_options.SetTooltip(tooltip, true /* autoshow */);
    242   }
    243 
    244   screenlock_bridge_->lock_handler()->ShowUserPodCustomIcon(user_email_,
    245                                                             icon_options);
    246   hardlock_ui_shown_ = true;
    247 }
    248 
    249 void EasyUnlockScreenlockStateHandler::UpdateTooltipOptions(
    250     bool trial_run,
    251     ScreenlockBridge::UserPodCustomIconOptions* icon_options) {
    252   size_t resource_id = 0;
    253   base::string16 device_name;
    254   if (trial_run && state_ == STATE_AUTHENTICATED) {
    255     // TODO(tbarzic): Remove this condition for M-40 branch.
    256     if (IsLocaleEnUS())
    257       resource_id = IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_INITIAL_AUTHENTICATED;
    258     else
    259       resource_id = IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_TUTORIAL;
    260   } else {
    261     resource_id = GetTooltipResourceId(state_);
    262     if (TooltipContainsDeviceType(state_))
    263       device_name = GetDeviceName();
    264   }
    265 
    266   if (!resource_id)
    267     return;
    268 
    269   base::string16 tooltip;
    270   if (device_name.empty()) {
    271     tooltip = l10n_util::GetStringUTF16(resource_id);
    272   } else {
    273     tooltip = l10n_util::GetStringFUTF16(resource_id, device_name);
    274   }
    275 
    276   if (tooltip.empty())
    277     return;
    278 
    279   icon_options->SetTooltip(tooltip, trial_run /* autoshow tooltip */);
    280 }
    281 
    282 base::string16 EasyUnlockScreenlockStateHandler::GetDeviceName() {
    283 #if defined(OS_CHROMEOS)
    284   return chromeos::GetChromeDeviceType();
    285 #else
    286   // TODO(tbarzic): Figure out the name for non Chrome OS case.
    287   return base::ASCIIToUTF16("Chrome");
    288 #endif
    289 }
    290 
    291 void EasyUnlockScreenlockStateHandler::UpdateScreenlockAuthType() {
    292   if (!is_trial_run_ && hardlock_state_ != NO_HARDLOCK)
    293     return;
    294 
    295   // Do not override online signin.
    296   const ScreenlockBridge::LockHandler::AuthType existing_auth_type =
    297       screenlock_bridge_->lock_handler()->GetAuthType(user_email_);
    298   if (existing_auth_type == ScreenlockBridge::LockHandler::ONLINE_SIGN_IN)
    299     return;
    300 
    301   if (state_ == STATE_AUTHENTICATED) {
    302     if (existing_auth_type != ScreenlockBridge::LockHandler::USER_CLICK) {
    303       screenlock_bridge_->lock_handler()->SetAuthType(
    304           user_email_,
    305           ScreenlockBridge::LockHandler::USER_CLICK,
    306           l10n_util::GetStringUTF16(
    307               IDS_EASY_UNLOCK_SCREENLOCK_USER_POD_AUTH_VALUE));
    308     }
    309   } else if (existing_auth_type !=
    310              ScreenlockBridge::LockHandler::OFFLINE_PASSWORD) {
    311     screenlock_bridge_->lock_handler()->SetAuthType(
    312         user_email_,
    313         ScreenlockBridge::LockHandler::OFFLINE_PASSWORD,
    314         base::string16());
    315   }
    316 }
    317