Add ENABLE_MEDIA_ROUTER define to builds other than Android and iOS.
[chromium-blink-merge.git] / chrome / browser / signin / easy_unlock_screenlock_state_handler.cc
blob3a4ee6362398d696ef7b8a0359ab4ee285236844
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"
7 #include "base/bind.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"
15 namespace {
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_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;
39 default:
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) {
49 switch (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:
66 return
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;
72 default:
73 return 0;
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;
87 // Returns true iff the |state| corresponds to a locked remote device.
88 bool IsLockedState(EasyUnlockScreenlockStateHandler::State state) {
89 return (state == EasyUnlockScreenlockStateHandler::STATE_PHONE_LOCKED ||
90 state == EasyUnlockScreenlockStateHandler::
91 STATE_PHONE_LOCKED_AND_TX_POWER_TOO_HIGH);
94 } // namespace
97 EasyUnlockScreenlockStateHandler::EasyUnlockScreenlockStateHandler(
98 const std::string& user_email,
99 HardlockState initial_hardlock_state,
100 ScreenlockBridge* screenlock_bridge)
101 : state_(STATE_INACTIVE),
102 user_email_(user_email),
103 screenlock_bridge_(screenlock_bridge),
104 hardlock_state_(initial_hardlock_state),
105 hardlock_ui_shown_(false),
106 is_trial_run_(false),
107 did_see_locked_phone_(false) {
108 DCHECK(screenlock_bridge_);
109 screenlock_bridge_->AddObserver(this);
112 EasyUnlockScreenlockStateHandler::~EasyUnlockScreenlockStateHandler() {
113 screenlock_bridge_->RemoveObserver(this);
114 // Make sure the screenlock state set by this gets cleared.
115 ChangeState(STATE_INACTIVE);
118 bool EasyUnlockScreenlockStateHandler::IsActive() const {
119 return state_ != STATE_INACTIVE;
122 bool EasyUnlockScreenlockStateHandler::InStateValidOnRemoteAuthFailure() const {
123 // Note that NO_PHONE is not valid in this case because the phone may close
124 // the connection if the auth challenge sent to it is invalid. This case
125 // should be handled as authentication failure.
126 return state_ == EasyUnlockScreenlockStateHandler::STATE_NO_BLUETOOTH ||
127 state_ == EasyUnlockScreenlockStateHandler::STATE_PHONE_LOCKED;
130 void EasyUnlockScreenlockStateHandler::ChangeState(State new_state) {
131 if (state_ == new_state)
132 return;
134 state_ = new_state;
136 // If lock screen is not active or it forces offline password, just cache the
137 // current state. The screenlock state will get refreshed in |ScreenDidLock|.
138 if (!screenlock_bridge_->IsLocked())
139 return;
141 // Do nothing when auth type is online.
142 if (screenlock_bridge_->lock_handler()->GetAuthType(user_email_) ==
143 ScreenlockBridge::LockHandler::ONLINE_SIGN_IN) {
144 return;
147 if (IsLockedState(state_))
148 did_see_locked_phone_ = true;
150 // No hardlock UI for trial run.
151 if (!is_trial_run_ && hardlock_state_ != NO_HARDLOCK) {
152 ShowHardlockUI();
153 return;
156 UpdateScreenlockAuthType();
158 ScreenlockBridge::UserPodCustomIcon icon = GetIconForState(state_);
160 if (icon == ScreenlockBridge::USER_POD_CUSTOM_ICON_NONE) {
161 screenlock_bridge_->lock_handler()->HideUserPodCustomIcon(user_email_);
162 return;
165 ScreenlockBridge::UserPodCustomIconOptions icon_options;
166 icon_options.SetIcon(icon);
168 // Don't hardlock on trial run.
169 if (is_trial_run_)
170 icon_options.SetTrialRun();
171 else if (HardlockOnClick(state_))
172 icon_options.SetHardlockOnClick();
174 UpdateTooltipOptions(&icon_options);
176 // For states without tooltips, we still need to set an accessibility label.
177 if (state_ == EasyUnlockScreenlockStateHandler::STATE_BLUETOOTH_CONNECTING) {
178 icon_options.SetAriaLabel(
179 l10n_util::GetStringUTF16(IDS_SMART_LOCK_SPINNER_ACCESSIBILITY_LABEL));
182 screenlock_bridge_->lock_handler()->ShowUserPodCustomIcon(user_email_,
183 icon_options);
186 void EasyUnlockScreenlockStateHandler::SetHardlockState(
187 HardlockState new_state) {
188 if (hardlock_state_ == new_state)
189 return;
191 if (new_state == LOGIN_FAILED && hardlock_state_ != NO_HARDLOCK)
192 return;
194 hardlock_state_ = new_state;
196 // If hardlock_state_ was set to NO_HARDLOCK, this means the screen is about
197 // to get unlocked. No need to update it in this case.
198 if (hardlock_state_ != NO_HARDLOCK) {
199 hardlock_ui_shown_ = false;
201 RefreshScreenlockState();
205 void EasyUnlockScreenlockStateHandler::MaybeShowHardlockUI() {
206 if (hardlock_state_ != NO_HARDLOCK)
207 ShowHardlockUI();
210 void EasyUnlockScreenlockStateHandler::SetTrialRun() {
211 if (is_trial_run_)
212 return;
213 is_trial_run_ = true;
214 RefreshScreenlockState();
215 RecordEasyUnlockTrialRunEvent(EASY_UNLOCK_TRIAL_RUN_EVENT_LAUNCHED);
218 void EasyUnlockScreenlockStateHandler::RecordClickOnLockIcon() {
219 if (!is_trial_run_)
220 return;
221 RecordEasyUnlockTrialRunEvent(EASY_UNLOCK_TRIAL_RUN_EVENT_CLICKED_LOCK_ICON);
224 void EasyUnlockScreenlockStateHandler::OnScreenDidLock(
225 ScreenlockBridge::LockHandler::ScreenType screen_type) {
226 did_see_locked_phone_ = IsLockedState(state_);
227 RefreshScreenlockState();
230 void EasyUnlockScreenlockStateHandler::OnScreenDidUnlock(
231 ScreenlockBridge::LockHandler::ScreenType screen_type) {
232 if (hardlock_state_ == LOGIN_FAILED)
233 hardlock_state_ = NO_HARDLOCK;
234 hardlock_ui_shown_ = false;
235 is_trial_run_ = false;
237 // Upon a successful unlock event, record whether the user's phone was locked
238 // at any point while the lock screen was up.
239 if (state_ == STATE_AUTHENTICATED)
240 RecordEasyUnlockDidUserManuallyUnlockPhone(did_see_locked_phone_);
241 did_see_locked_phone_ = false;
244 void EasyUnlockScreenlockStateHandler::OnFocusedUserChanged(
245 const std::string& user_id) {
248 void EasyUnlockScreenlockStateHandler::RefreshScreenlockState() {
249 State last_state = state_;
250 // This should force updating screenlock state.
251 state_ = STATE_INACTIVE;
252 ChangeState(last_state);
255 void EasyUnlockScreenlockStateHandler::ShowHardlockUI() {
256 DCHECK(hardlock_state_ != NO_HARDLOCK);
258 if (!screenlock_bridge_->IsLocked())
259 return;
261 // Do not override online signin.
262 const ScreenlockBridge::LockHandler::AuthType existing_auth_type =
263 screenlock_bridge_->lock_handler()->GetAuthType(user_email_);
264 if (existing_auth_type == ScreenlockBridge::LockHandler::ONLINE_SIGN_IN)
265 return;
267 if (existing_auth_type != ScreenlockBridge::LockHandler::OFFLINE_PASSWORD) {
268 screenlock_bridge_->lock_handler()->SetAuthType(
269 user_email_,
270 ScreenlockBridge::LockHandler::OFFLINE_PASSWORD,
271 base::string16());
274 if (hardlock_state_ == NO_PAIRING) {
275 screenlock_bridge_->lock_handler()->HideUserPodCustomIcon(user_email_);
276 hardlock_ui_shown_ = false;
277 return;
280 if (hardlock_ui_shown_)
281 return;
283 ScreenlockBridge::UserPodCustomIconOptions icon_options;
284 if (hardlock_state_ == LOGIN_FAILED) {
285 icon_options.SetIcon(ScreenlockBridge::USER_POD_CUSTOM_ICON_LOCKED);
286 } else if (hardlock_state_ == PAIRING_CHANGED ||
287 hardlock_state_ == PAIRING_ADDED) {
288 icon_options.SetIcon(
289 ScreenlockBridge::USER_POD_CUSTOM_ICON_LOCKED_TO_BE_ACTIVATED);
290 } else {
291 icon_options.SetIcon(ScreenlockBridge::USER_POD_CUSTOM_ICON_HARDLOCKED);
294 base::string16 device_name = GetDeviceName();
295 base::string16 tooltip;
296 if (hardlock_state_ == USER_HARDLOCK) {
297 tooltip = l10n_util::GetStringFUTF16(
298 IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_USER, device_name);
299 } else if (hardlock_state_ == PAIRING_CHANGED) {
300 tooltip = l10n_util::GetStringUTF16(
301 IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_PAIRING_CHANGED);
302 } else if (hardlock_state_ == PAIRING_ADDED) {
303 tooltip = l10n_util::GetStringFUTF16(
304 IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_PAIRING_ADDED, device_name,
305 device_name);
306 } else if (hardlock_state_ == LOGIN_FAILED) {
307 tooltip = l10n_util::GetStringUTF16(
308 IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_LOGIN_FAILURE);
309 } else {
310 LOG(ERROR) << "Unknown hardlock state " << hardlock_state_;
312 icon_options.SetTooltip(tooltip, true /* autoshow */);
314 screenlock_bridge_->lock_handler()->ShowUserPodCustomIcon(user_email_,
315 icon_options);
316 hardlock_ui_shown_ = true;
319 void EasyUnlockScreenlockStateHandler::UpdateTooltipOptions(
320 ScreenlockBridge::UserPodCustomIconOptions* icon_options) {
321 size_t resource_id = 0;
322 base::string16 device_name;
323 if (is_trial_run_ && state_ == STATE_AUTHENTICATED) {
324 resource_id = IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_INITIAL_AUTHENTICATED;
325 } else {
326 resource_id = GetTooltipResourceId(state_);
327 if (TooltipContainsDeviceType(state_))
328 device_name = GetDeviceName();
331 if (!resource_id)
332 return;
334 base::string16 tooltip;
335 if (device_name.empty()) {
336 tooltip = l10n_util::GetStringUTF16(resource_id);
337 } else {
338 tooltip = l10n_util::GetStringFUTF16(resource_id, device_name);
341 if (tooltip.empty())
342 return;
344 icon_options->SetTooltip(
345 tooltip,
346 is_trial_run_ || (state_ != STATE_AUTHENTICATED) /* autoshow tooltip */);
349 base::string16 EasyUnlockScreenlockStateHandler::GetDeviceName() {
350 #if defined(OS_CHROMEOS)
351 return chromeos::GetChromeDeviceType();
352 #else
353 // TODO(tbarzic): Figure out the name for non Chrome OS case.
354 return base::ASCIIToUTF16("Chrome");
355 #endif
358 void EasyUnlockScreenlockStateHandler::UpdateScreenlockAuthType() {
359 if (!is_trial_run_ && hardlock_state_ != NO_HARDLOCK)
360 return;
362 // Do not override online signin.
363 const ScreenlockBridge::LockHandler::AuthType existing_auth_type =
364 screenlock_bridge_->lock_handler()->GetAuthType(user_email_);
365 DCHECK_NE(ScreenlockBridge::LockHandler::ONLINE_SIGN_IN, existing_auth_type);
367 if (state_ == STATE_AUTHENTICATED) {
368 if (existing_auth_type != ScreenlockBridge::LockHandler::USER_CLICK) {
369 screenlock_bridge_->lock_handler()->SetAuthType(
370 user_email_,
371 ScreenlockBridge::LockHandler::USER_CLICK,
372 l10n_util::GetStringUTF16(
373 IDS_EASY_UNLOCK_SCREENLOCK_USER_POD_AUTH_VALUE));
375 } else if (existing_auth_type !=
376 ScreenlockBridge::LockHandler::OFFLINE_PASSWORD) {
377 screenlock_bridge_->lock_handler()->SetAuthType(
378 user_email_,
379 ScreenlockBridge::LockHandler::OFFLINE_PASSWORD,
380 base::string16());