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