| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/signin/easy_unlock_screenlock_state_handler.h" |
| |
| #include "base/bind.h" |
| #include "base/strings/string16.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/chromeos/chromeos_utils.h" |
| #include "chrome/grit/generated_resources.h" |
| #include "ui/base/l10n/l10n_util.h" |
| |
| namespace { |
| |
| ScreenlockBridge::UserPodCustomIcon GetIconForState( |
| EasyUnlockScreenlockStateHandler::State state) { |
| switch (state) { |
| case EasyUnlockScreenlockStateHandler::STATE_NO_BLUETOOTH: |
| case EasyUnlockScreenlockStateHandler::STATE_NO_PHONE: |
| case EasyUnlockScreenlockStateHandler::STATE_PHONE_NOT_AUTHENTICATED: |
| case EasyUnlockScreenlockStateHandler::STATE_PHONE_LOCKED: |
| case EasyUnlockScreenlockStateHandler::STATE_PHONE_NOT_NEARBY: |
| case EasyUnlockScreenlockStateHandler::STATE_PHONE_UNLOCKABLE: |
| case EasyUnlockScreenlockStateHandler::STATE_PHONE_UNSUPPORTED: |
| return ScreenlockBridge::USER_POD_CUSTOM_ICON_LOCKED; |
| case EasyUnlockScreenlockStateHandler::STATE_BLUETOOTH_CONNECTING: |
| return ScreenlockBridge::USER_POD_CUSTOM_ICON_SPINNER; |
| case EasyUnlockScreenlockStateHandler::STATE_AUTHENTICATED: |
| return ScreenlockBridge::USER_POD_CUSTOM_ICON_UNLOCKED; |
| default: |
| return ScreenlockBridge::USER_POD_CUSTOM_ICON_NONE; |
| } |
| } |
| |
| bool HardlockOnClick(EasyUnlockScreenlockStateHandler::State state) { |
| return state != EasyUnlockScreenlockStateHandler::STATE_INACTIVE; |
| } |
| |
| size_t GetTooltipResourceId(EasyUnlockScreenlockStateHandler::State state) { |
| switch (state) { |
| case EasyUnlockScreenlockStateHandler::STATE_NO_BLUETOOTH: |
| return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_NO_BLUETOOTH; |
| case EasyUnlockScreenlockStateHandler::STATE_NO_PHONE: |
| return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_NO_PHONE; |
| case EasyUnlockScreenlockStateHandler::STATE_PHONE_NOT_AUTHENTICATED: |
| return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_PHONE_NOT_AUTHENTICATED; |
| case EasyUnlockScreenlockStateHandler::STATE_PHONE_LOCKED: |
| return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_PHONE_LOCKED; |
| case EasyUnlockScreenlockStateHandler::STATE_PHONE_UNLOCKABLE: |
| return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_PHONE_UNLOCKABLE; |
| case EasyUnlockScreenlockStateHandler::STATE_PHONE_NOT_NEARBY: |
| return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_PHONE_NOT_NEARBY; |
| case EasyUnlockScreenlockStateHandler::STATE_AUTHENTICATED: |
| return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_INSTRUCTIONS; |
| case EasyUnlockScreenlockStateHandler::STATE_PHONE_UNSUPPORTED: |
| return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_UNSUPPORTED_ANDROID_VERSION; |
| default: |
| return 0; |
| } |
| } |
| |
| bool TooltipContainsDeviceType(EasyUnlockScreenlockStateHandler::State state) { |
| return state == EasyUnlockScreenlockStateHandler::STATE_AUTHENTICATED || |
| state == EasyUnlockScreenlockStateHandler::STATE_PHONE_UNLOCKABLE || |
| state == EasyUnlockScreenlockStateHandler::STATE_NO_BLUETOOTH || |
| state == EasyUnlockScreenlockStateHandler::STATE_PHONE_UNSUPPORTED; |
| } |
| |
| bool IsLocaleEnUS() { |
| return g_browser_process->GetApplicationLocale() == "en-US"; |
| } |
| |
| } // namespace |
| |
| |
| EasyUnlockScreenlockStateHandler::EasyUnlockScreenlockStateHandler( |
| const std::string& user_email, |
| HardlockState initial_hardlock_state, |
| ScreenlockBridge* screenlock_bridge) |
| : state_(STATE_INACTIVE), |
| user_email_(user_email), |
| screenlock_bridge_(screenlock_bridge), |
| hardlock_state_(initial_hardlock_state), |
| hardlock_ui_shown_(false), |
| is_trial_run_(false) { |
| DCHECK(screenlock_bridge_); |
| screenlock_bridge_->AddObserver(this); |
| } |
| |
| EasyUnlockScreenlockStateHandler::~EasyUnlockScreenlockStateHandler() { |
| screenlock_bridge_->RemoveObserver(this); |
| // Make sure the screenlock state set by this gets cleared. |
| ChangeState(STATE_INACTIVE); |
| } |
| |
| bool EasyUnlockScreenlockStateHandler::IsActive() const { |
| return state_ != STATE_INACTIVE; |
| } |
| |
| bool EasyUnlockScreenlockStateHandler::InStateValidOnRemoteAuthFailure() const { |
| // Note that NO_PHONE is not valid in this case because the phone may close |
| // the connection if the auth challenge sent to it is invalid. This case |
| // should be handled as authentication failure. |
| return state_ == EasyUnlockScreenlockStateHandler::STATE_NO_BLUETOOTH || |
| state_ == EasyUnlockScreenlockStateHandler::STATE_PHONE_LOCKED; |
| } |
| |
| void EasyUnlockScreenlockStateHandler::ChangeState(State new_state) { |
| if (state_ == new_state) |
| return; |
| |
| state_ = new_state; |
| |
| // If lock screen is not active or it forces offline password, just cache the |
| // current state. The screenlock state will get refreshed in |ScreenDidLock|. |
| if (!screenlock_bridge_->IsLocked()) |
| return; |
| |
| // No hardlock UI for trial run. |
| if (!is_trial_run_ && hardlock_state_ != NO_HARDLOCK) { |
| ShowHardlockUI(); |
| return; |
| } |
| |
| UpdateScreenlockAuthType(); |
| |
| ScreenlockBridge::UserPodCustomIcon icon = GetIconForState(state_); |
| |
| if (icon == ScreenlockBridge::USER_POD_CUSTOM_ICON_NONE) { |
| screenlock_bridge_->lock_handler()->HideUserPodCustomIcon(user_email_); |
| return; |
| } |
| |
| ScreenlockBridge::UserPodCustomIconOptions icon_options; |
| icon_options.SetIcon(icon); |
| |
| // Don't hardlock on trial run. |
| if (!is_trial_run_ && HardlockOnClick(state_)) |
| icon_options.SetHardlockOnClick(); |
| |
| UpdateTooltipOptions(is_trial_run_, &icon_options); |
| |
| // For states without tooltips, we still need to set an accessibility label. |
| if (state_ == EasyUnlockScreenlockStateHandler::STATE_BLUETOOTH_CONNECTING) { |
| icon_options.SetAriaLabel( |
| l10n_util::GetStringUTF16(IDS_SMART_LOCK_SPINNER_ACCESSIBILITY_LABEL)); |
| } |
| |
| screenlock_bridge_->lock_handler()->ShowUserPodCustomIcon(user_email_, |
| icon_options); |
| } |
| |
| void EasyUnlockScreenlockStateHandler::SetHardlockState( |
| HardlockState new_state) { |
| if (hardlock_state_ == new_state) |
| return; |
| |
| if (new_state == LOGIN_FAILED && hardlock_state_ != NO_HARDLOCK) |
| return; |
| |
| hardlock_state_ = new_state; |
| |
| // If hardlock_state_ was set to NO_HARDLOCK, this means the screen is about |
| // to get unlocked. No need to update it in this case. |
| if (hardlock_state_ != NO_HARDLOCK) { |
| hardlock_ui_shown_ = false; |
| |
| RefreshScreenlockState(); |
| } |
| } |
| |
| void EasyUnlockScreenlockStateHandler::MaybeShowHardlockUI() { |
| if (hardlock_state_ != NO_HARDLOCK) |
| ShowHardlockUI(); |
| } |
| |
| void EasyUnlockScreenlockStateHandler::SetTrialRun() { |
| if (is_trial_run_) |
| return; |
| is_trial_run_ = true; |
| RefreshScreenlockState(); |
| } |
| |
| void EasyUnlockScreenlockStateHandler::OnScreenDidLock() { |
| RefreshScreenlockState(); |
| } |
| |
| void EasyUnlockScreenlockStateHandler::OnScreenDidUnlock() { |
| if (hardlock_state_ == LOGIN_FAILED) |
| hardlock_state_ = NO_HARDLOCK; |
| hardlock_ui_shown_ = false; |
| is_trial_run_ = false; |
| } |
| |
| void EasyUnlockScreenlockStateHandler::OnFocusedUserChanged( |
| const std::string& user_id) { |
| } |
| |
| void EasyUnlockScreenlockStateHandler::RefreshScreenlockState() { |
| State last_state = state_; |
| // This should force updating screenlock state. |
| state_ = STATE_INACTIVE; |
| ChangeState(last_state); |
| } |
| |
| void EasyUnlockScreenlockStateHandler::ShowHardlockUI() { |
| DCHECK(hardlock_state_ != NO_HARDLOCK); |
| |
| if (!screenlock_bridge_->IsLocked()) |
| return; |
| |
| if (screenlock_bridge_->lock_handler()->GetAuthType(user_email_) != |
| ScreenlockBridge::LockHandler::OFFLINE_PASSWORD) { |
| screenlock_bridge_->lock_handler()->SetAuthType( |
| user_email_, |
| ScreenlockBridge::LockHandler::OFFLINE_PASSWORD, |
| base::string16()); |
| } |
| |
| if (hardlock_state_ == NO_PAIRING) { |
| screenlock_bridge_->lock_handler()->HideUserPodCustomIcon(user_email_); |
| hardlock_ui_shown_ = false; |
| return; |
| } |
| |
| if (hardlock_ui_shown_) |
| return; |
| |
| ScreenlockBridge::UserPodCustomIconOptions icon_options; |
| if (hardlock_state_ == LOGIN_FAILED) { |
| icon_options.SetIcon(ScreenlockBridge::USER_POD_CUSTOM_ICON_LOCKED); |
| } else { |
| icon_options.SetIcon(ScreenlockBridge::USER_POD_CUSTOM_ICON_HARDLOCKED); |
| } |
| |
| // TODO(tbarzic): Remove this condition for M-40. |
| if (IsLocaleEnUS()) { |
| base::string16 tooltip; |
| if (hardlock_state_ == USER_HARDLOCK) { |
| tooltip = l10n_util::GetStringFUTF16( |
| IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_USER, GetDeviceName()); |
| } else if (hardlock_state_ == PAIRING_CHANGED) { |
| tooltip = l10n_util::GetStringUTF16( |
| IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_PAIRING_CHANGED); |
| } else if (hardlock_state_ == LOGIN_FAILED) { |
| tooltip = l10n_util::GetStringUTF16( |
| IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_LOGIN_FAILURE); |
| } else { |
| LOG(ERROR) << "Unknown hardlock state " << hardlock_state_; |
| } |
| icon_options.SetTooltip(tooltip, true /* autoshow */); |
| } |
| |
| screenlock_bridge_->lock_handler()->ShowUserPodCustomIcon(user_email_, |
| icon_options); |
| hardlock_ui_shown_ = true; |
| } |
| |
| void EasyUnlockScreenlockStateHandler::UpdateTooltipOptions( |
| bool trial_run, |
| ScreenlockBridge::UserPodCustomIconOptions* icon_options) { |
| size_t resource_id = 0; |
| base::string16 device_name; |
| if (trial_run && state_ == STATE_AUTHENTICATED) { |
| // TODO(tbarzic): Remove this condition for M-40 branch. |
| if (IsLocaleEnUS()) |
| resource_id = IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_INITIAL_AUTHENTICATED; |
| else |
| resource_id = IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_TUTORIAL; |
| } else { |
| resource_id = GetTooltipResourceId(state_); |
| if (TooltipContainsDeviceType(state_)) |
| device_name = GetDeviceName(); |
| } |
| |
| if (!resource_id) |
| return; |
| |
| base::string16 tooltip; |
| if (device_name.empty()) { |
| tooltip = l10n_util::GetStringUTF16(resource_id); |
| } else { |
| tooltip = l10n_util::GetStringFUTF16(resource_id, device_name); |
| } |
| |
| if (tooltip.empty()) |
| return; |
| |
| icon_options->SetTooltip(tooltip, trial_run /* autoshow tooltip */); |
| } |
| |
| base::string16 EasyUnlockScreenlockStateHandler::GetDeviceName() { |
| #if defined(OS_CHROMEOS) |
| return chromeos::GetChromeDeviceType(); |
| #else |
| // TODO(tbarzic): Figure out the name for non Chrome OS case. |
| return base::ASCIIToUTF16("Chrome"); |
| #endif |
| } |
| |
| void EasyUnlockScreenlockStateHandler::UpdateScreenlockAuthType() { |
| if (!is_trial_run_ && hardlock_state_ != NO_HARDLOCK) |
| return; |
| |
| if (state_ == STATE_AUTHENTICATED) { |
| if (screenlock_bridge_->lock_handler()->GetAuthType(user_email_) != |
| ScreenlockBridge::LockHandler::USER_CLICK) { |
| screenlock_bridge_->lock_handler()->SetAuthType( |
| user_email_, |
| ScreenlockBridge::LockHandler::USER_CLICK, |
| l10n_util::GetStringUTF16( |
| IDS_EASY_UNLOCK_SCREENLOCK_USER_POD_AUTH_VALUE)); |
| } |
| } else if (screenlock_bridge_->lock_handler()->GetAuthType(user_email_) != |
| ScreenlockBridge::LockHandler::OFFLINE_PASSWORD) { |
| screenlock_bridge_->lock_handler()->SetAuthType( |
| user_email_, |
| ScreenlockBridge::LockHandler::OFFLINE_PASSWORD, |
| base::string16()); |
| } |
| } |