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/browser/signin/easy_unlock_metrics.h"
12 #include "chrome/grit/generated_resources.h"
13 #include "ui/base/l10n/l10n_util.h"
17 ScreenlockBridge::UserPodCustomIcon
GetIconForState(
18 EasyUnlockScreenlockStateHandler::State 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_UNLOCKABLE
:
25 case EasyUnlockScreenlockStateHandler::STATE_PHONE_UNSUPPORTED
:
26 case EasyUnlockScreenlockStateHandler::STATE_RSSI_TOO_LOW
:
27 return ScreenlockBridge::USER_POD_CUSTOM_ICON_LOCKED
;
28 case EasyUnlockScreenlockStateHandler::STATE_TX_POWER_TOO_HIGH
:
29 case EasyUnlockScreenlockStateHandler::
30 STATE_PHONE_LOCKED_AND_TX_POWER_TOO_HIGH
:
31 // TODO(isherman): This icon is currently identical to the regular locked
32 // icon. Once the reduced proximity range flag is removed, consider
33 // deleting the redundant icon.
34 return ScreenlockBridge::USER_POD_CUSTOM_ICON_LOCKED_WITH_PROXIMITY_HINT
;
35 case EasyUnlockScreenlockStateHandler::STATE_BLUETOOTH_CONNECTING
:
36 return ScreenlockBridge::USER_POD_CUSTOM_ICON_SPINNER
;
37 case EasyUnlockScreenlockStateHandler::STATE_AUTHENTICATED
:
38 return ScreenlockBridge::USER_POD_CUSTOM_ICON_UNLOCKED
;
40 return ScreenlockBridge::USER_POD_CUSTOM_ICON_NONE
;
44 bool HardlockOnClick(EasyUnlockScreenlockStateHandler::State state
) {
45 return state
!= EasyUnlockScreenlockStateHandler::STATE_INACTIVE
;
48 size_t GetTooltipResourceId(EasyUnlockScreenlockStateHandler::State state
) {
50 case EasyUnlockScreenlockStateHandler::STATE_NO_BLUETOOTH
:
51 return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_NO_BLUETOOTH
;
52 case EasyUnlockScreenlockStateHandler::STATE_NO_PHONE
:
53 return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_NO_PHONE
;
54 case EasyUnlockScreenlockStateHandler::STATE_PHONE_NOT_AUTHENTICATED
:
55 return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_PHONE_NOT_AUTHENTICATED
;
56 case EasyUnlockScreenlockStateHandler::STATE_PHONE_LOCKED
:
57 return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_PHONE_LOCKED
;
58 case EasyUnlockScreenlockStateHandler::STATE_PHONE_UNLOCKABLE
:
59 return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_PHONE_UNLOCKABLE
;
60 case EasyUnlockScreenlockStateHandler::STATE_RSSI_TOO_LOW
:
61 return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_RSSI_TOO_LOW
;
62 case EasyUnlockScreenlockStateHandler::STATE_TX_POWER_TOO_HIGH
:
63 return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_TX_POWER_TOO_HIGH
;
64 case EasyUnlockScreenlockStateHandler::
65 STATE_PHONE_LOCKED_AND_TX_POWER_TOO_HIGH
:
67 IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_PHONE_LOCKED_AND_TX_POWER_TOO_HIGH
;
68 case EasyUnlockScreenlockStateHandler::STATE_AUTHENTICATED
:
69 return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_INSTRUCTIONS
;
70 case EasyUnlockScreenlockStateHandler::STATE_PHONE_UNSUPPORTED
:
71 return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_UNSUPPORTED_ANDROID_VERSION
;
77 bool TooltipContainsDeviceType(EasyUnlockScreenlockStateHandler::State state
) {
78 return state
== EasyUnlockScreenlockStateHandler::STATE_AUTHENTICATED
||
79 state
== EasyUnlockScreenlockStateHandler::STATE_PHONE_UNLOCKABLE
||
80 state
== EasyUnlockScreenlockStateHandler::STATE_NO_BLUETOOTH
||
81 state
== EasyUnlockScreenlockStateHandler::STATE_PHONE_UNSUPPORTED
||
82 state
== EasyUnlockScreenlockStateHandler::STATE_TX_POWER_TOO_HIGH
||
83 state
== EasyUnlockScreenlockStateHandler::
84 STATE_PHONE_LOCKED_AND_TX_POWER_TOO_HIGH
;
90 EasyUnlockScreenlockStateHandler::EasyUnlockScreenlockStateHandler(
91 const std::string
& user_email
,
92 HardlockState initial_hardlock_state
,
93 ScreenlockBridge
* screenlock_bridge
)
94 : state_(STATE_INACTIVE
),
95 user_email_(user_email
),
96 screenlock_bridge_(screenlock_bridge
),
97 hardlock_state_(initial_hardlock_state
),
98 hardlock_ui_shown_(false),
99 is_trial_run_(false) {
100 DCHECK(screenlock_bridge_
);
101 screenlock_bridge_
->AddObserver(this);
104 EasyUnlockScreenlockStateHandler::~EasyUnlockScreenlockStateHandler() {
105 screenlock_bridge_
->RemoveObserver(this);
106 // Make sure the screenlock state set by this gets cleared.
107 ChangeState(STATE_INACTIVE
);
110 bool EasyUnlockScreenlockStateHandler::IsActive() const {
111 return state_
!= STATE_INACTIVE
;
114 bool EasyUnlockScreenlockStateHandler::InStateValidOnRemoteAuthFailure() const {
115 // Note that NO_PHONE is not valid in this case because the phone may close
116 // the connection if the auth challenge sent to it is invalid. This case
117 // should be handled as authentication failure.
118 return state_
== EasyUnlockScreenlockStateHandler::STATE_NO_BLUETOOTH
||
119 state_
== EasyUnlockScreenlockStateHandler::STATE_PHONE_LOCKED
;
122 void EasyUnlockScreenlockStateHandler::ChangeState(State new_state
) {
123 if (state_
== new_state
)
128 // If lock screen is not active or it forces offline password, just cache the
129 // current state. The screenlock state will get refreshed in |ScreenDidLock|.
130 if (!screenlock_bridge_
->IsLocked())
133 // Do nothing when auth type is online.
134 if (screenlock_bridge_
->lock_handler()->GetAuthType(user_email_
) ==
135 ScreenlockBridge::LockHandler::ONLINE_SIGN_IN
) {
139 // No hardlock UI for trial run.
140 if (!is_trial_run_
&& hardlock_state_
!= NO_HARDLOCK
) {
145 UpdateScreenlockAuthType();
147 ScreenlockBridge::UserPodCustomIcon icon
= GetIconForState(state_
);
149 if (icon
== ScreenlockBridge::USER_POD_CUSTOM_ICON_NONE
) {
150 screenlock_bridge_
->lock_handler()->HideUserPodCustomIcon(user_email_
);
154 ScreenlockBridge::UserPodCustomIconOptions icon_options
;
155 icon_options
.SetIcon(icon
);
157 // Don't hardlock on trial run.
159 icon_options
.SetTrialRun();
160 else if (HardlockOnClick(state_
))
161 icon_options
.SetHardlockOnClick();
163 UpdateTooltipOptions(&icon_options
);
165 // For states without tooltips, we still need to set an accessibility label.
166 if (state_
== EasyUnlockScreenlockStateHandler::STATE_BLUETOOTH_CONNECTING
) {
167 icon_options
.SetAriaLabel(
168 l10n_util::GetStringUTF16(IDS_SMART_LOCK_SPINNER_ACCESSIBILITY_LABEL
));
171 screenlock_bridge_
->lock_handler()->ShowUserPodCustomIcon(user_email_
,
175 void EasyUnlockScreenlockStateHandler::SetHardlockState(
176 HardlockState new_state
) {
177 if (hardlock_state_
== new_state
)
180 if (new_state
== LOGIN_FAILED
&& hardlock_state_
!= NO_HARDLOCK
)
183 hardlock_state_
= new_state
;
185 // If hardlock_state_ was set to NO_HARDLOCK, this means the screen is about
186 // to get unlocked. No need to update it in this case.
187 if (hardlock_state_
!= NO_HARDLOCK
) {
188 hardlock_ui_shown_
= false;
190 RefreshScreenlockState();
194 void EasyUnlockScreenlockStateHandler::MaybeShowHardlockUI() {
195 if (hardlock_state_
!= NO_HARDLOCK
)
199 void EasyUnlockScreenlockStateHandler::SetTrialRun() {
202 is_trial_run_
= true;
203 RefreshScreenlockState();
204 RecordEasyUnlockTrialRunEvent(EASY_UNLOCK_TRIAL_RUN_EVENT_LAUNCHED
);
207 void EasyUnlockScreenlockStateHandler::RecordClickOnLockIcon() {
210 RecordEasyUnlockTrialRunEvent(EASY_UNLOCK_TRIAL_RUN_EVENT_CLICKED_LOCK_ICON
);
213 void EasyUnlockScreenlockStateHandler::OnScreenDidLock(
214 ScreenlockBridge::LockHandler::ScreenType screen_type
) {
215 RefreshScreenlockState();
218 void EasyUnlockScreenlockStateHandler::OnScreenDidUnlock(
219 ScreenlockBridge::LockHandler::ScreenType screen_type
) {
220 if (hardlock_state_
== LOGIN_FAILED
)
221 hardlock_state_
= NO_HARDLOCK
;
222 hardlock_ui_shown_
= false;
223 is_trial_run_
= false;
226 void EasyUnlockScreenlockStateHandler::OnFocusedUserChanged(
227 const std::string
& user_id
) {
230 void EasyUnlockScreenlockStateHandler::RefreshScreenlockState() {
231 State last_state
= state_
;
232 // This should force updating screenlock state.
233 state_
= STATE_INACTIVE
;
234 ChangeState(last_state
);
237 void EasyUnlockScreenlockStateHandler::ShowHardlockUI() {
238 DCHECK(hardlock_state_
!= NO_HARDLOCK
);
240 if (!screenlock_bridge_
->IsLocked())
243 // Do not override online signin.
244 const ScreenlockBridge::LockHandler::AuthType existing_auth_type
=
245 screenlock_bridge_
->lock_handler()->GetAuthType(user_email_
);
246 if (existing_auth_type
== ScreenlockBridge::LockHandler::ONLINE_SIGN_IN
)
249 if (existing_auth_type
!= ScreenlockBridge::LockHandler::OFFLINE_PASSWORD
) {
250 screenlock_bridge_
->lock_handler()->SetAuthType(
252 ScreenlockBridge::LockHandler::OFFLINE_PASSWORD
,
256 if (hardlock_state_
== NO_PAIRING
) {
257 screenlock_bridge_
->lock_handler()->HideUserPodCustomIcon(user_email_
);
258 hardlock_ui_shown_
= false;
262 if (hardlock_ui_shown_
)
265 ScreenlockBridge::UserPodCustomIconOptions icon_options
;
266 if (hardlock_state_
== LOGIN_FAILED
) {
267 icon_options
.SetIcon(ScreenlockBridge::USER_POD_CUSTOM_ICON_LOCKED
);
268 } else if (hardlock_state_
== PAIRING_CHANGED
||
269 hardlock_state_
== PAIRING_ADDED
) {
270 icon_options
.SetIcon(
271 ScreenlockBridge::USER_POD_CUSTOM_ICON_LOCKED_TO_BE_ACTIVATED
);
273 icon_options
.SetIcon(ScreenlockBridge::USER_POD_CUSTOM_ICON_HARDLOCKED
);
276 base::string16 device_name
= GetDeviceName();
277 base::string16 tooltip
;
278 if (hardlock_state_
== USER_HARDLOCK
) {
279 tooltip
= l10n_util::GetStringFUTF16(
280 IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_USER
, device_name
);
281 } else if (hardlock_state_
== PAIRING_CHANGED
) {
282 tooltip
= l10n_util::GetStringUTF16(
283 IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_PAIRING_CHANGED
);
284 } else if (hardlock_state_
== PAIRING_ADDED
) {
285 tooltip
= l10n_util::GetStringFUTF16(
286 IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_PAIRING_ADDED
, device_name
,
288 } else if (hardlock_state_
== LOGIN_FAILED
) {
289 tooltip
= l10n_util::GetStringUTF16(
290 IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_LOGIN_FAILURE
);
292 LOG(ERROR
) << "Unknown hardlock state " << hardlock_state_
;
294 icon_options
.SetTooltip(tooltip
, true /* autoshow */);
296 screenlock_bridge_
->lock_handler()->ShowUserPodCustomIcon(user_email_
,
298 hardlock_ui_shown_
= true;
301 void EasyUnlockScreenlockStateHandler::UpdateTooltipOptions(
302 ScreenlockBridge::UserPodCustomIconOptions
* icon_options
) {
303 size_t resource_id
= 0;
304 base::string16 device_name
;
305 if (is_trial_run_
&& state_
== STATE_AUTHENTICATED
) {
306 resource_id
= IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_INITIAL_AUTHENTICATED
;
308 resource_id
= GetTooltipResourceId(state_
);
309 if (TooltipContainsDeviceType(state_
))
310 device_name
= GetDeviceName();
316 base::string16 tooltip
;
317 if (device_name
.empty()) {
318 tooltip
= l10n_util::GetStringUTF16(resource_id
);
320 tooltip
= l10n_util::GetStringFUTF16(resource_id
, device_name
);
326 icon_options
->SetTooltip(
328 is_trial_run_
|| (state_
!= STATE_AUTHENTICATED
) /* autoshow tooltip */);
331 base::string16
EasyUnlockScreenlockStateHandler::GetDeviceName() {
332 #if defined(OS_CHROMEOS)
333 return chromeos::GetChromeDeviceType();
335 // TODO(tbarzic): Figure out the name for non Chrome OS case.
336 return base::ASCIIToUTF16("Chrome");
340 void EasyUnlockScreenlockStateHandler::UpdateScreenlockAuthType() {
341 if (!is_trial_run_
&& hardlock_state_
!= NO_HARDLOCK
)
344 // Do not override online signin.
345 const ScreenlockBridge::LockHandler::AuthType existing_auth_type
=
346 screenlock_bridge_
->lock_handler()->GetAuthType(user_email_
);
347 DCHECK_NE(ScreenlockBridge::LockHandler::ONLINE_SIGN_IN
, existing_auth_type
);
349 if (state_
== STATE_AUTHENTICATED
) {
350 if (existing_auth_type
!= ScreenlockBridge::LockHandler::USER_CLICK
) {
351 screenlock_bridge_
->lock_handler()->SetAuthType(
353 ScreenlockBridge::LockHandler::USER_CLICK
,
354 l10n_util::GetStringUTF16(
355 IDS_EASY_UNLOCK_SCREENLOCK_USER_POD_AUTH_VALUE
));
357 } else if (existing_auth_type
!=
358 ScreenlockBridge::LockHandler::OFFLINE_PASSWORD
) {
359 screenlock_bridge_
->lock_handler()->SetAuthType(
361 ScreenlockBridge::LockHandler::OFFLINE_PASSWORD
,