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.
5 #include "chrome/browser/signin/easy_unlock_screenlock_state_handler.h"
8 #include "base/strings/string16.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "chrome/browser/chromeos/chromeos_utils.h"
11 #include "chrome/grit/generated_resources.h"
12 #include "ui/base/l10n/l10n_util.h"
16 ScreenlockBridge::UserPodCustomIcon
GetIconForState(
17 EasyUnlockScreenlockStateHandler::State state
) {
19 case EasyUnlockScreenlockStateHandler::STATE_NO_BLUETOOTH
:
20 case EasyUnlockScreenlockStateHandler::STATE_NO_PHONE
:
21 case EasyUnlockScreenlockStateHandler::STATE_PHONE_NOT_AUTHENTICATED
:
22 case EasyUnlockScreenlockStateHandler::STATE_PHONE_LOCKED
:
23 case EasyUnlockScreenlockStateHandler::STATE_PHONE_UNLOCKABLE
:
24 case EasyUnlockScreenlockStateHandler::STATE_PHONE_UNSUPPORTED
:
25 case EasyUnlockScreenlockStateHandler::STATE_RSSI_TOO_LOW
:
26 return ScreenlockBridge::USER_POD_CUSTOM_ICON_LOCKED
;
27 case EasyUnlockScreenlockStateHandler::STATE_TX_POWER_TOO_HIGH
:
28 return ScreenlockBridge::USER_POD_CUSTOM_ICON_LOCKED_WITH_PROXIMITY_HINT
;
29 case EasyUnlockScreenlockStateHandler::STATE_BLUETOOTH_CONNECTING
:
30 return ScreenlockBridge::USER_POD_CUSTOM_ICON_SPINNER
;
31 case EasyUnlockScreenlockStateHandler::STATE_AUTHENTICATED
:
32 return ScreenlockBridge::USER_POD_CUSTOM_ICON_UNLOCKED
;
34 return ScreenlockBridge::USER_POD_CUSTOM_ICON_NONE
;
38 bool HardlockOnClick(EasyUnlockScreenlockStateHandler::State state
) {
39 return state
!= EasyUnlockScreenlockStateHandler::STATE_INACTIVE
;
42 size_t GetTooltipResourceId(EasyUnlockScreenlockStateHandler::State state
) {
44 case EasyUnlockScreenlockStateHandler::STATE_NO_BLUETOOTH
:
45 return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_NO_BLUETOOTH
;
46 case EasyUnlockScreenlockStateHandler::STATE_NO_PHONE
:
47 return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_NO_PHONE
;
48 case EasyUnlockScreenlockStateHandler::STATE_PHONE_NOT_AUTHENTICATED
:
49 return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_PHONE_NOT_AUTHENTICATED
;
50 case EasyUnlockScreenlockStateHandler::STATE_PHONE_LOCKED
:
51 return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_PHONE_LOCKED
;
52 case EasyUnlockScreenlockStateHandler::STATE_PHONE_UNLOCKABLE
:
53 return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_PHONE_UNLOCKABLE
;
54 case EasyUnlockScreenlockStateHandler::STATE_RSSI_TOO_LOW
:
55 return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_RSSI_TOO_LOW
;
56 case EasyUnlockScreenlockStateHandler::STATE_TX_POWER_TOO_HIGH
:
57 return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_TX_POWER_TOO_HIGH
;
58 case EasyUnlockScreenlockStateHandler::STATE_AUTHENTICATED
:
59 return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_INSTRUCTIONS
;
60 case EasyUnlockScreenlockStateHandler::STATE_PHONE_UNSUPPORTED
:
61 return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_UNSUPPORTED_ANDROID_VERSION
;
67 bool TooltipContainsDeviceType(EasyUnlockScreenlockStateHandler::State state
) {
68 return state
== EasyUnlockScreenlockStateHandler::STATE_AUTHENTICATED
||
69 state
== EasyUnlockScreenlockStateHandler::STATE_PHONE_UNLOCKABLE
||
70 state
== EasyUnlockScreenlockStateHandler::STATE_NO_BLUETOOTH
||
71 state
== EasyUnlockScreenlockStateHandler::STATE_PHONE_UNSUPPORTED
||
72 state
== EasyUnlockScreenlockStateHandler::STATE_RSSI_TOO_LOW
||
73 state
== EasyUnlockScreenlockStateHandler::STATE_TX_POWER_TOO_HIGH
;
79 EasyUnlockScreenlockStateHandler::EasyUnlockScreenlockStateHandler(
80 const std::string
& user_email
,
81 HardlockState initial_hardlock_state
,
82 ScreenlockBridge
* screenlock_bridge
)
83 : state_(STATE_INACTIVE
),
84 user_email_(user_email
),
85 screenlock_bridge_(screenlock_bridge
),
86 hardlock_state_(initial_hardlock_state
),
87 hardlock_ui_shown_(false),
88 is_trial_run_(false) {
89 DCHECK(screenlock_bridge_
);
90 screenlock_bridge_
->AddObserver(this);
93 EasyUnlockScreenlockStateHandler::~EasyUnlockScreenlockStateHandler() {
94 screenlock_bridge_
->RemoveObserver(this);
95 // Make sure the screenlock state set by this gets cleared.
96 ChangeState(STATE_INACTIVE
);
99 bool EasyUnlockScreenlockStateHandler::IsActive() const {
100 return state_
!= STATE_INACTIVE
;
103 bool EasyUnlockScreenlockStateHandler::InStateValidOnRemoteAuthFailure() const {
104 // Note that NO_PHONE is not valid in this case because the phone may close
105 // the connection if the auth challenge sent to it is invalid. This case
106 // should be handled as authentication failure.
107 return state_
== EasyUnlockScreenlockStateHandler::STATE_NO_BLUETOOTH
||
108 state_
== EasyUnlockScreenlockStateHandler::STATE_PHONE_LOCKED
;
111 void EasyUnlockScreenlockStateHandler::ChangeState(State new_state
) {
112 if (state_
== new_state
)
117 // If lock screen is not active or it forces offline password, just cache the
118 // current state. The screenlock state will get refreshed in |ScreenDidLock|.
119 if (!screenlock_bridge_
->IsLocked())
122 // Do nothing when auth type is online.
123 if (screenlock_bridge_
->lock_handler()->GetAuthType(user_email_
) ==
124 ScreenlockBridge::LockHandler::ONLINE_SIGN_IN
) {
128 // No hardlock UI for trial run.
129 if (!is_trial_run_
&& hardlock_state_
!= NO_HARDLOCK
) {
134 UpdateScreenlockAuthType();
136 ScreenlockBridge::UserPodCustomIcon icon
= GetIconForState(state_
);
138 if (icon
== ScreenlockBridge::USER_POD_CUSTOM_ICON_NONE
) {
139 screenlock_bridge_
->lock_handler()->HideUserPodCustomIcon(user_email_
);
143 ScreenlockBridge::UserPodCustomIconOptions icon_options
;
144 icon_options
.SetIcon(icon
);
146 // Don't hardlock on trial run.
147 if (!is_trial_run_
&& HardlockOnClick(state_
))
148 icon_options
.SetHardlockOnClick();
150 UpdateTooltipOptions(is_trial_run_
, &icon_options
);
152 // For states without tooltips, we still need to set an accessibility label.
153 if (state_
== EasyUnlockScreenlockStateHandler::STATE_BLUETOOTH_CONNECTING
) {
154 icon_options
.SetAriaLabel(
155 l10n_util::GetStringUTF16(IDS_SMART_LOCK_SPINNER_ACCESSIBILITY_LABEL
));
158 screenlock_bridge_
->lock_handler()->ShowUserPodCustomIcon(user_email_
,
162 void EasyUnlockScreenlockStateHandler::SetHardlockState(
163 HardlockState new_state
) {
164 if (hardlock_state_
== new_state
)
167 if (new_state
== LOGIN_FAILED
&& hardlock_state_
!= NO_HARDLOCK
)
170 hardlock_state_
= new_state
;
172 // If hardlock_state_ was set to NO_HARDLOCK, this means the screen is about
173 // to get unlocked. No need to update it in this case.
174 if (hardlock_state_
!= NO_HARDLOCK
) {
175 hardlock_ui_shown_
= false;
177 RefreshScreenlockState();
181 void EasyUnlockScreenlockStateHandler::MaybeShowHardlockUI() {
182 if (hardlock_state_
!= NO_HARDLOCK
)
186 void EasyUnlockScreenlockStateHandler::SetTrialRun() {
189 is_trial_run_
= true;
190 RefreshScreenlockState();
193 void EasyUnlockScreenlockStateHandler::OnScreenDidLock() {
194 RefreshScreenlockState();
197 void EasyUnlockScreenlockStateHandler::OnScreenDidUnlock() {
198 if (hardlock_state_
== LOGIN_FAILED
)
199 hardlock_state_
= NO_HARDLOCK
;
200 hardlock_ui_shown_
= false;
201 is_trial_run_
= false;
204 void EasyUnlockScreenlockStateHandler::OnFocusedUserChanged(
205 const std::string
& user_id
) {
208 void EasyUnlockScreenlockStateHandler::RefreshScreenlockState() {
209 State last_state
= state_
;
210 // This should force updating screenlock state.
211 state_
= STATE_INACTIVE
;
212 ChangeState(last_state
);
215 void EasyUnlockScreenlockStateHandler::ShowHardlockUI() {
216 DCHECK(hardlock_state_
!= NO_HARDLOCK
);
218 if (!screenlock_bridge_
->IsLocked())
221 // Do not override online signin.
222 const ScreenlockBridge::LockHandler::AuthType existing_auth_type
=
223 screenlock_bridge_
->lock_handler()->GetAuthType(user_email_
);
224 if (existing_auth_type
== ScreenlockBridge::LockHandler::ONLINE_SIGN_IN
)
227 if (existing_auth_type
!= ScreenlockBridge::LockHandler::OFFLINE_PASSWORD
) {
228 screenlock_bridge_
->lock_handler()->SetAuthType(
230 ScreenlockBridge::LockHandler::OFFLINE_PASSWORD
,
234 if (hardlock_state_
== NO_PAIRING
) {
235 screenlock_bridge_
->lock_handler()->HideUserPodCustomIcon(user_email_
);
236 hardlock_ui_shown_
= false;
240 if (hardlock_ui_shown_
)
243 ScreenlockBridge::UserPodCustomIconOptions icon_options
;
244 if (hardlock_state_
== LOGIN_FAILED
) {
245 icon_options
.SetIcon(ScreenlockBridge::USER_POD_CUSTOM_ICON_LOCKED
);
246 } else if (hardlock_state_
== PAIRING_CHANGED
||
247 hardlock_state_
== PAIRING_ADDED
) {
248 icon_options
.SetIcon(
249 ScreenlockBridge::USER_POD_CUSTOM_ICON_LOCKED_TO_BE_ACTIVATED
);
251 icon_options
.SetIcon(ScreenlockBridge::USER_POD_CUSTOM_ICON_HARDLOCKED
);
254 base::string16 device_name
= GetDeviceName();
255 base::string16 tooltip
;
256 if (hardlock_state_
== USER_HARDLOCK
) {
257 tooltip
= l10n_util::GetStringFUTF16(
258 IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_USER
, device_name
);
259 } else if (hardlock_state_
== PAIRING_CHANGED
) {
260 tooltip
= l10n_util::GetStringUTF16(
261 IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_PAIRING_CHANGED
);
262 } else if (hardlock_state_
== PAIRING_ADDED
) {
263 tooltip
= l10n_util::GetStringFUTF16(
264 IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_PAIRING_ADDED
, device_name
,
266 } else if (hardlock_state_
== LOGIN_FAILED
) {
267 tooltip
= l10n_util::GetStringUTF16(
268 IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_LOGIN_FAILURE
);
270 LOG(ERROR
) << "Unknown hardlock state " << hardlock_state_
;
272 icon_options
.SetTooltip(tooltip
, true /* autoshow */);
274 screenlock_bridge_
->lock_handler()->ShowUserPodCustomIcon(user_email_
,
276 hardlock_ui_shown_
= true;
279 void EasyUnlockScreenlockStateHandler::UpdateTooltipOptions(
281 ScreenlockBridge::UserPodCustomIconOptions
* icon_options
) {
282 size_t resource_id
= 0;
283 base::string16 device_name
;
284 if (trial_run
&& state_
== STATE_AUTHENTICATED
) {
285 resource_id
= IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_INITIAL_AUTHENTICATED
;
287 resource_id
= GetTooltipResourceId(state_
);
288 if (TooltipContainsDeviceType(state_
))
289 device_name
= GetDeviceName();
295 base::string16 tooltip
;
296 if (device_name
.empty()) {
297 tooltip
= l10n_util::GetStringUTF16(resource_id
);
299 tooltip
= l10n_util::GetStringFUTF16(resource_id
, device_name
);
305 icon_options
->SetTooltip(tooltip
, trial_run
/* autoshow tooltip */);
308 base::string16
EasyUnlockScreenlockStateHandler::GetDeviceName() {
309 #if defined(OS_CHROMEOS)
310 return chromeos::GetChromeDeviceType();
312 // TODO(tbarzic): Figure out the name for non Chrome OS case.
313 return base::ASCIIToUTF16("Chrome");
317 void EasyUnlockScreenlockStateHandler::UpdateScreenlockAuthType() {
318 if (!is_trial_run_
&& hardlock_state_
!= NO_HARDLOCK
)
321 // Do not override online signin.
322 const ScreenlockBridge::LockHandler::AuthType existing_auth_type
=
323 screenlock_bridge_
->lock_handler()->GetAuthType(user_email_
);
324 DCHECK_NE(ScreenlockBridge::LockHandler::ONLINE_SIGN_IN
, existing_auth_type
);
326 if (state_
== STATE_AUTHENTICATED
) {
327 if (existing_auth_type
!= ScreenlockBridge::LockHandler::USER_CLICK
) {
328 screenlock_bridge_
->lock_handler()->SetAuthType(
330 ScreenlockBridge::LockHandler::USER_CLICK
,
331 l10n_util::GetStringUTF16(
332 IDS_EASY_UNLOCK_SCREENLOCK_USER_POD_AUTH_VALUE
));
334 } else if (existing_auth_type
!=
335 ScreenlockBridge::LockHandler::OFFLINE_PASSWORD
) {
336 screenlock_bridge_
->lock_handler()->SetAuthType(
338 ScreenlockBridge::LockHandler::OFFLINE_PASSWORD
,