1 // Copyright 2017 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 "ash/login/ui/login_auth_user_view.h"
6 
7 #include <map>
8 #include <memory>
9 #include <utility>
10 
11 #include "ash/login/login_screen_controller.h"
12 #include "ash/login/resources/grit/login_resources.h"
13 #include "ash/login/ui/arrow_button_view.h"
14 #include "ash/login/ui/horizontal_image_sequence_animation_decoder.h"
15 #include "ash/login/ui/lock_screen.h"
16 #include "ash/login/ui/login_display_style.h"
17 #include "ash/login/ui/login_password_view.h"
18 #include "ash/login/ui/login_pin_input_view.h"
19 #include "ash/login/ui/login_pin_view.h"
20 #include "ash/login/ui/login_user_view.h"
21 #include "ash/login/ui/non_accessible_view.h"
22 #include "ash/login/ui/pin_keyboard_animation.h"
23 #include "ash/login/ui/pin_request_view.h"
24 #include "ash/login/ui/system_label_button.h"
25 #include "ash/login/ui/views_utils.h"
26 #include "ash/public/cpp/login_constants.h"
27 #include "ash/resources/vector_icons/vector_icons.h"
28 #include "ash/session/session_controller_impl.h"
29 #include "ash/shell.h"
30 #include "ash/strings/grit/ash_strings.h"
31 #include "ash/style/ash_color_provider.h"
32 #include "ash/system/model/clock_model.h"
33 #include "ash/system/model/system_tray_model.h"
34 #include "ash/system/night_light/time_of_day.h"
35 #include "ash/wallpaper/wallpaper_controller_impl.h"
36 #include "base/bind.h"
37 #include "base/i18n/time_formatting.h"
38 #include "base/memory/ptr_util.h"
39 #include "base/strings/utf_string_conversions.h"
40 #include "base/time/time.h"
41 #include "base/timer/timer.h"
42 #include "chromeos/constants/chromeos_features.h"
43 #include "components/user_manager/user.h"
44 #include "ui/accessibility/ax_enums.mojom.h"
45 #include "ui/accessibility/ax_node_data.h"
46 #include "ui/base/l10n/l10n_util.h"
47 #include "ui/base/resource/resource_bundle.h"
48 #include "ui/compositor/callback_layer_animation_observer.h"
49 #include "ui/compositor/layer_animation_sequence.h"
50 #include "ui/compositor/layer_animator.h"
51 #include "ui/compositor/scoped_layer_animation_settings.h"
52 #include "ui/gfx/color_analysis.h"
53 #include "ui/gfx/geometry/size.h"
54 #include "ui/gfx/interpolated_transform.h"
55 #include "ui/gfx/paint_vector_icon.h"
56 #include "ui/gfx/vector_icon_types.h"
57 #include "ui/views/background.h"
58 #include "ui/views/border.h"
59 #include "ui/views/controls/button/md_text_button.h"
60 #include "ui/views/controls/highlight_path_generator.h"
61 #include "ui/views/controls/label.h"
62 #include "ui/views/layout/box_layout.h"
63 #include "ui/views/layout/fill_layout.h"
64 #include "ui/views/layout/flex_layout.h"
65 #include "ui/views/layout/grid_layout.h"
66 #include "ui/views/style/typography.h"
67 #include "ui/views/view.h"
68 
69 namespace ash {
70 namespace {
71 
72 constexpr const char kLoginAuthUserViewClassName[] = "LoginAuthUserView";
73 
74 // Distance between the user view (ie, the icon and name) and other elements
75 const int kDistanceBetweenUserViewAndPasswordDp = 24;
76 const int kDistanceBetweenUserViewAndPinInputDp = 32;
77 const int kDistanceBetweenUserViewAndOnlineSigninDp = 24;
78 const int kDistanceBetweenUserViewAndChallengeResponseDp = 32;
79 
80 // Distance between the password textfield and the the pin keyboard.
81 const int kDistanceBetweenPasswordFieldAndPinKeyboardDp = 16;
82 
83 // Height of button used for switching between pin and password authentication.
84 const int kPinPasswordToggleButtonHeight = 32;
85 const int kPinPasswordToggleButtonPaddingTop = 24;
86 
87 // Distance from the end of pin keyboard to the bottom of the big user view.
88 const int kDistanceFromPinKeyboardToBigUserViewBottomDp = 50;
89 
90 // Distance from the top of the user view to the user icon.
91 constexpr int kDistanceFromTopOfBigUserViewToUserIconDp = 24;
92 
93 constexpr SkColor kChallengeResponseErrorColor = gfx::kGoogleRed300;
94 
95 // Date time format containing only the day of the week, for example: "Tuesday".
96 constexpr char kDayOfWeekOnlyTimeFormat[] = "EEEE";
97 
98 constexpr int kFingerprintIconSizeDp = 28;
99 constexpr int kResetToDefaultIconDelayMs = 1300;
100 constexpr base::TimeDelta kResetToDefaultMessageDelayMs =
101     base::TimeDelta::FromMilliseconds(3000);
102 constexpr int kFingerprintIconTopSpacingDp = 20;
103 constexpr int kSpacingBetweenFingerprintIconAndLabelDp = 15;
104 constexpr int kFingerprintViewWidthDp = 204;
105 constexpr int kDistanceBetweenPasswordFieldAndFingerprintViewDp = 90;
106 constexpr int kFingerprintFailedAnimationDurationMs = 700;
107 constexpr int kFingerprintFailedAnimationNumFrames = 45;
108 
109 constexpr base::TimeDelta kChallengeResponseResetAfterFailureDelay =
110     base::TimeDelta::FromSeconds(5);
111 constexpr int kChallengeResponseArrowSizeDp = 48;
112 constexpr int kSpacingBetweenChallengeResponseArrowAndIconDp = 100;
113 constexpr int kSpacingBetweenChallengeResponseIconAndLabelDp = 15;
114 constexpr int kChallengeResponseIconSizeDp = 28;
115 constexpr int kDistanceBetweenPwdFieldAndChallengeResponseViewDp = 0;
116 
117 constexpr int kDisabledAuthMessageVerticalBorderDp = 16;
118 constexpr int kDisabledAuthMessageHorizontalBorderDp = 16;
119 constexpr int kDisabledAuthMessageChildrenSpacingDp = 4;
120 constexpr int kDisabledAuthMessageTimeWidthDp = 204;
121 constexpr int kDisabledAuthMessageMultiprofileWidthDp = 304;
122 constexpr int kDisabledAuthMessageHeightDp = 98;
123 constexpr int kDisabledAuthMessageIconSizeDp = 24;
124 constexpr int kDisabledAuthMessageTitleFontSizeDeltaDp = 3;
125 constexpr int kDisabledAuthMessageContentsFontSizeDeltaDp = -1;
126 constexpr int kDisabledAuthMessageRoundedCornerRadiusDp = 8;
127 
128 constexpr int kLockedTpmMessageVerticalBorderDp = 16;
129 constexpr int kLockedTpmMessageHorizontalBorderDp = 16;
130 constexpr int kLockedTpmMessageChildrenSpacingDp = 4;
131 constexpr int kLockedTpmMessageWidthDp = 360;
132 constexpr int kLockedTpmMessageHeightDp = 108;
133 constexpr int kLockedTpmMessageIconSizeDp = 24;
134 constexpr int kLockedTpmMessageDeltaDp = 0;
135 constexpr int kLockedTpmMessageRoundedCornerRadiusDp = 8;
136 
137 constexpr int kNonEmptyWidthDp = 1;
SizeFromHeight(int height)138 gfx::Size SizeFromHeight(int height) {
139   return gfx::Size(kNonEmptyWidthDp, height);
140 }
141 
142 // Returns an observer that will hide |view| when it fires. The observer will
143 // delete itself after firing (by returning true). Make sure to call
144 // |observer->SetActive()| after attaching it.
BuildObserverToHideView(views::View * view)145 ui::CallbackLayerAnimationObserver* BuildObserverToHideView(views::View* view) {
146   return new ui::CallbackLayerAnimationObserver(base::BindRepeating(
147       [](views::View* view,
148          const ui::CallbackLayerAnimationObserver& observer) {
149         // Don't hide the view if the animation is aborted, as |view| may no
150         // longer be valid.
151         if (observer.aborted_count())
152           return true;
153 
154         view->SetVisible(false);
155         return true;
156       },
157       view));
158 }
159 
BuildObserverToNotifyA11yLocationChanged(views::View * view)160 ui::CallbackLayerAnimationObserver* BuildObserverToNotifyA11yLocationChanged(
161     views::View* view) {
162   return new ui::CallbackLayerAnimationObserver(base::BindRepeating(
163       [](views::View* view,
164          const ui::CallbackLayerAnimationObserver& observer) {
165         // Don't notify a11y event if the animation is aborted, as |view| may no
166         // longer be valid.
167         if (observer.aborted_count())
168           return true;
169 
170         view->NotifyAccessibilityEvent(ax::mojom::Event::kLocationChanged,
171                                        false /*send_native_event*/);
172         return true;
173       },
174       view));
175 }
176 
BuildObserverToNotifyA11yLocationChanged(LoginPinView * view)177 ui::CallbackLayerAnimationObserver* BuildObserverToNotifyA11yLocationChanged(
178     LoginPinView* view) {
179   return new ui::CallbackLayerAnimationObserver(base::BindRepeating(
180       [](LoginPinView* view,
181          const ui::CallbackLayerAnimationObserver& observer) {
182         // Don't notify a11y event if the animation is aborted, as |view| may no
183         // longer be valid.
184         if (observer.aborted_count())
185           return true;
186 
187         view->NotifyAccessibilityLocationChanged();
188         return true;
189       },
190       view));
191 }
192 
193 // Clears the password for the given |LoginPasswordView| instance, hides it, and
194 // then deletes itself.
195 class ClearPasswordAndHideAnimationObserver
196     : public ui::ImplicitAnimationObserver {
197  public:
ClearPasswordAndHideAnimationObserver(LoginPasswordView * view)198   explicit ClearPasswordAndHideAnimationObserver(LoginPasswordView* view)
199       : password_view_(view) {}
200   ~ClearPasswordAndHideAnimationObserver() override = default;
201 
202   // ui::ImplicitAnimationObserver:
OnImplicitAnimationsCompleted()203   void OnImplicitAnimationsCompleted() override {
204     password_view_->Reset();
205     password_view_->SetVisible(false);
206     delete this;
207   }
208 
209  private:
210   LoginPasswordView* const password_view_;
211 
212   DISALLOW_COPY_AND_ASSIGN(ClearPasswordAndHideAnimationObserver);
213 };
214 
215 // The label shown below the fingerprint icon.
216 class FingerprintLabel : public views::Label {
217  public:
FingerprintLabel()218   FingerprintLabel() {
219     SetSubpixelRenderingEnabled(false);
220     SetAutoColorReadabilityEnabled(false);
221     SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor(
222         AshColorProvider::ContentLayerType::kTextColorSecondary));
223     SetMultiLine(true);
224 
225     SetTextBasedOnState(FingerprintState::AVAILABLE_DEFAULT,
226                         false /*can_use_pin*/);
227   }
228 
SetTextBasedOnAuthAttempt(bool success)229   void SetTextBasedOnAuthAttempt(bool success) {
230     SetText(l10n_util::GetStringUTF16(
231         success ? IDS_ASH_LOGIN_FINGERPRINT_UNLOCK_AUTH_SUCCESS
232                 : IDS_ASH_LOGIN_FINGERPRINT_UNLOCK_AUTH_FAILED));
233     SetAccessibleName(l10n_util::GetStringUTF16(
234         success ? IDS_ASH_LOGIN_FINGERPRINT_UNLOCK_ACCESSIBLE_AUTH_SUCCESS
235                 : IDS_ASH_LOGIN_FINGERPRINT_UNLOCK_ACCESSIBLE_AUTH_FAILED));
236   }
237 
SetTextBasedOnState(FingerprintState state,bool can_use_pin)238   void SetTextBasedOnState(FingerprintState state, bool can_use_pin) {
239     auto get_displayed_id = [&]() {
240       switch (state) {
241         case FingerprintState::UNAVAILABLE:
242         case FingerprintState::AVAILABLE_DEFAULT:
243           return IDS_ASH_LOGIN_FINGERPRINT_UNLOCK_AVAILABLE;
244         case FingerprintState::AVAILABLE_WITH_TOUCH_SENSOR_WARNING:
245           return IDS_ASH_LOGIN_FINGERPRINT_UNLOCK_TOUCH_SENSOR;
246         case FingerprintState::DISABLED_FROM_ATTEMPTS:
247           return IDS_ASH_LOGIN_FINGERPRINT_UNLOCK_DISABLED_FROM_ATTEMPTS;
248         case FingerprintState::DISABLED_FROM_TIMEOUT:
249           if (can_use_pin)
250             return IDS_ASH_LOGIN_FINGERPRINT_UNLOCK_PIN_OR_PASSWORD_REQUIRED;
251           return IDS_ASH_LOGIN_FINGERPRINT_UNLOCK_PASSWORD_REQUIRED;
252       }
253       NOTREACHED();
254     };
255 
256     auto get_accessible_id = [&]() {
257       if (state == FingerprintState::DISABLED_FROM_ATTEMPTS)
258         return IDS_ASH_LOGIN_FINGERPRINT_UNLOCK_ACCESSIBLE_AUTH_DISABLED_FROM_ATTEMPTS;
259       return get_displayed_id();
260     };
261 
262     SetText(l10n_util::GetStringUTF16(get_displayed_id()));
263     SetAccessibleName(l10n_util::GetStringUTF16(get_accessible_id()));
264   }
265 
266   // views::View:
GetAccessibleNodeData(ui::AXNodeData * node_data)267   void GetAccessibleNodeData(ui::AXNodeData* node_data) override {
268     node_data->role = ax::mojom::Role::kStaticText;
269     node_data->SetName(accessible_name_);
270   }
271 
272  private:
SetAccessibleName(const base::string16 & name)273   void SetAccessibleName(const base::string16& name) {
274     accessible_name_ = name;
275     NotifyAccessibilityEvent(ax::mojom::Event::kTextChanged,
276                              true /*send_native_event*/);
277   }
278 
279   base::string16 accessible_name_;
280 
281   DISALLOW_COPY_AND_ASSIGN(FingerprintLabel);
282 };
283 
284 // The content needed to render the disabled auth message view.
285 struct LockScreenMessage {
286   base::string16 title;
287   base::string16 content;
288   const gfx::VectorIcon* icon;
289 };
290 
291 // Returns the message used when the device was locked due to a time window
292 // limit.
GetWindowLimitMessage(const base::Time & unlock_time,bool use_24hour_clock)293 LockScreenMessage GetWindowLimitMessage(const base::Time& unlock_time,
294                                         bool use_24hour_clock) {
295   LockScreenMessage message;
296   message.title = l10n_util::GetStringUTF16(IDS_ASH_LOGIN_TIME_FOR_BED_MESSAGE);
297 
298   base::Time local_midnight = base::Time::Now().LocalMidnight();
299 
300   base::string16 time_to_display;
301   if (use_24hour_clock) {
302     time_to_display = base::TimeFormatTimeOfDayWithHourClockType(
303         unlock_time, base::k24HourClock, base::kDropAmPm);
304   } else {
305     time_to_display = base::TimeFormatTimeOfDayWithHourClockType(
306         unlock_time, base::k12HourClock, base::kKeepAmPm);
307   }
308 
309   if (unlock_time < local_midnight + base::TimeDelta::FromDays(1)) {
310     // Unlock time is today.
311     message.content = l10n_util::GetStringFUTF16(
312         IDS_ASH_LOGIN_COME_BACK_MESSAGE, time_to_display);
313   } else if (unlock_time < local_midnight + base::TimeDelta::FromDays(2)) {
314     // Unlock time is tomorrow.
315     message.content = l10n_util::GetStringFUTF16(
316         IDS_ASH_LOGIN_COME_BACK_TOMORROW_MESSAGE, time_to_display);
317   } else {
318     message.content = l10n_util::GetStringFUTF16(
319         IDS_ASH_LOGIN_COME_BACK_DAY_OF_WEEK_MESSAGE,
320         base::TimeFormatWithPattern(unlock_time, kDayOfWeekOnlyTimeFormat),
321         time_to_display);
322   }
323   message.icon = &kLockScreenTimeLimitMoonIcon;
324   return message;
325 }
326 
327 // Returns the message used when the device was locked due to a time usage
328 // limit.
GetUsageLimitMessage(const base::TimeDelta & used_time)329 LockScreenMessage GetUsageLimitMessage(const base::TimeDelta& used_time) {
330   LockScreenMessage message;
331 
332   // 1 minute is used instead of 0, because the device is used for a few
333   // milliseconds before locking.
334   if (used_time < base::TimeDelta::FromMinutes(1)) {
335     // The device was locked all day.
336     message.title = l10n_util::GetStringUTF16(IDS_ASH_LOGIN_TAKE_BREAK_MESSAGE);
337     message.content =
338         l10n_util::GetStringUTF16(IDS_ASH_LOGIN_LOCKED_ALL_DAY_MESSAGE);
339   } else {
340     // The usage limit is over.
341     message.title = l10n_util::GetStringUTF16(IDS_ASH_LOGIN_TIME_IS_UP_MESSAGE);
342 
343     // TODO(933973): Stop displaying the hours part of the string when duration
344     // is less than 1 hour. Example: change "0 hours, 7 minutes" to "7 minutes".
345     base::string16 used_time_string;
346     if (!base::TimeDurationFormat(
347             used_time, base::DurationFormatWidth::DURATION_WIDTH_WIDE,
348             &used_time_string)) {
349       LOG(ERROR) << "Failed to generate time duration string.";
350       return message;
351     }
352 
353     message.content = l10n_util::GetStringFUTF16(
354         IDS_ASH_LOGIN_SCREEN_TIME_USED_MESSAGE, used_time_string);
355   }
356   message.icon = &kLockScreenTimeLimitTimerIcon;
357   return message;
358 }
359 
360 // Returns the message used when the device was locked due to a time limit
361 // override.
GetOverrideMessage()362 LockScreenMessage GetOverrideMessage() {
363   LockScreenMessage message;
364   message.title =
365       l10n_util::GetStringUTF16(IDS_ASH_LOGIN_TIME_FOR_A_BREAK_MESSAGE);
366   message.content =
367       l10n_util::GetStringUTF16(IDS_ASH_LOGIN_MANUAL_LOCK_MESSAGE);
368   message.icon = &kLockScreenTimeLimitLockIcon;
369   return message;
370 }
371 
GetLockScreenMessage(AuthDisabledReason lock_reason,const base::Time & unlock_time,const base::TimeDelta & used_time,bool use_24hour_clock)372 LockScreenMessage GetLockScreenMessage(AuthDisabledReason lock_reason,
373                                        const base::Time& unlock_time,
374                                        const base::TimeDelta& used_time,
375                                        bool use_24hour_clock) {
376   switch (lock_reason) {
377     case AuthDisabledReason::kTimeWindowLimit:
378       return GetWindowLimitMessage(unlock_time, use_24hour_clock);
379     case AuthDisabledReason::kTimeUsageLimit:
380       return GetUsageLimitMessage(used_time);
381     case AuthDisabledReason::kTimeLimitOverride:
382       return GetOverrideMessage();
383     default:
384       NOTREACHED();
385   }
386 }
387 
388 }  // namespace
389 
390 // Consists of fingerprint icon view and a label.
391 class LoginAuthUserView::FingerprintView : public views::View {
392  public:
FingerprintView()393   FingerprintView() {
394     SetPaintToLayer();
395     layer()->SetFillsBoundsOpaquely(false);
396     SetBorder(views::CreateEmptyBorder(kFingerprintIconTopSpacingDp, 0, 0, 0));
397 
398     auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
399         views::BoxLayout::Orientation::kVertical, gfx::Insets(),
400         kSpacingBetweenFingerprintIconAndLabelDp));
401     layout->set_main_axis_alignment(
402         views::BoxLayout::MainAxisAlignment::kCenter);
403 
404     icon_ = new AnimatedRoundedImageView(
405         gfx::Size(kFingerprintIconSizeDp, kFingerprintIconSizeDp),
406         0 /*corner_radius*/);
407     icon_->SetImage(gfx::CreateVectorIcon(
408         kLockScreenFingerprintIcon, kFingerprintIconSizeDp,
409         AshColorProvider::Get()->GetContentLayerColor(
410             AshColorProvider::ContentLayerType::kIconColorPrimary)));
411     AddChildView(icon_);
412 
413     label_ = new FingerprintLabel();
414     AddChildView(label_);
415 
416     DisplayCurrentState();
417   }
418 
419   ~FingerprintView() override = default;
420 
SetState(FingerprintState state)421   void SetState(FingerprintState state) {
422     if (state_ == state)
423       return;
424 
425     reset_state_.Stop();
426     state_ = state;
427 
428     DisplayCurrentState();
429 
430     if (ShouldFireChromeVoxAlert(state))
431       FireAlert();
432   }
433 
SetCanUsePin(bool value)434   void SetCanUsePin(bool value) {
435     if (can_use_pin_ == value)
436       return;
437 
438     can_use_pin_ = value;
439     label_->SetTextBasedOnState(state_, can_use_pin_);
440   }
441 
NotifyFingerprintAuthResult(bool success)442   void NotifyFingerprintAuthResult(bool success) {
443     reset_state_.Stop();
444     label_->SetTextBasedOnAuthAttempt(success);
445 
446     if (success) {
447       icon_->SetImage(gfx::CreateVectorIcon(kLockScreenFingerprintSuccessIcon,
448                                             kFingerprintIconSizeDp,
449                                             gfx::kGoogleGreen300));
450     } else {
451       SetIcon(FingerprintState::DISABLED_FROM_ATTEMPTS);
452       // base::Unretained is safe because reset_state_ is owned by |this|.
453       reset_state_.Start(
454           FROM_HERE,
455           base::TimeDelta::FromMilliseconds(kResetToDefaultIconDelayMs),
456           base::BindOnce(&FingerprintView::DisplayCurrentState,
457                          base::Unretained(this)));
458 
459       FireAlert();
460     }
461   }
462 
463   // views::View:
CalculatePreferredSize() const464   gfx::Size CalculatePreferredSize() const override {
465     gfx::Size size = views::View::CalculatePreferredSize();
466     size.set_width(kFingerprintViewWidthDp);
467     return size;
468   }
469 
470   // views::View:
OnGestureEvent(ui::GestureEvent * event)471   void OnGestureEvent(ui::GestureEvent* event) override {
472     if (event->type() != ui::ET_GESTURE_TAP)
473       return;
474     if (state_ == FingerprintState::AVAILABLE_DEFAULT ||
475         state_ == FingerprintState::AVAILABLE_WITH_TOUCH_SENSOR_WARNING) {
476       SetState(FingerprintState::AVAILABLE_WITH_TOUCH_SENSOR_WARNING);
477       reset_state_.Start(
478           FROM_HERE, kResetToDefaultMessageDelayMs,
479           base::BindOnce(&FingerprintView::SetState, base::Unretained(this),
480                          FingerprintState::AVAILABLE_DEFAULT));
481     }
482   }
483 
484  private:
DisplayCurrentState()485   void DisplayCurrentState() {
486     SetVisible(state_ != FingerprintState::UNAVAILABLE);
487     SetIcon(state_);
488     label_->SetTextBasedOnState(state_, can_use_pin_);
489   }
490 
FireAlert()491   void FireAlert() {
492     label_->NotifyAccessibilityEvent(ax::mojom::Event::kAlert,
493                                      true /*send_native_event*/);
494   }
495 
SetIcon(FingerprintState state)496   void SetIcon(FingerprintState state) {
497     const SkColor icon_color = AshColorProvider::Get()->GetContentLayerColor(
498         AshColorProvider::ContentLayerType::kIconColorPrimary);
499     const SkColor color =
500         state == FingerprintState::AVAILABLE_DEFAULT ||
501                 state == FingerprintState::AVAILABLE_WITH_TOUCH_SENSOR_WARNING
502             ? icon_color
503             : AshColorProvider::Get()->GetDisabledColor(icon_color);
504     switch (state) {
505       case FingerprintState::UNAVAILABLE:
506       case FingerprintState::AVAILABLE_DEFAULT:
507       case FingerprintState::AVAILABLE_WITH_TOUCH_SENSOR_WARNING:
508       case FingerprintState::DISABLED_FROM_TIMEOUT:
509         icon_->SetImage(gfx::CreateVectorIcon(kLockScreenFingerprintIcon,
510                                               kFingerprintIconSizeDp, color));
511         break;
512       case FingerprintState::DISABLED_FROM_ATTEMPTS:
513         icon_->SetAnimationDecoder(
514             std::make_unique<HorizontalImageSequenceAnimationDecoder>(
515                 *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
516                     IDR_LOGIN_FINGERPRINT_UNLOCK_SPINNER),
517                 base::TimeDelta::FromMilliseconds(
518                     kFingerprintFailedAnimationDurationMs),
519                 kFingerprintFailedAnimationNumFrames),
520             AnimatedRoundedImageView::Playback::kSingle);
521         break;
522     }
523   }
524 
ShouldFireChromeVoxAlert(FingerprintState state)525   bool ShouldFireChromeVoxAlert(FingerprintState state) {
526     return state == FingerprintState::DISABLED_FROM_ATTEMPTS ||
527            state == FingerprintState::DISABLED_FROM_TIMEOUT;
528   }
529 
530   FingerprintLabel* label_ = nullptr;
531   AnimatedRoundedImageView* icon_ = nullptr;
532   base::OneShotTimer reset_state_;
533   FingerprintState state_ = FingerprintState::AVAILABLE_DEFAULT;
534 
535   // Affects DISABLED_FROM_TIMEOUT message.
536   bool can_use_pin_ = false;
537 
538   DISALLOW_COPY_AND_ASSIGN(FingerprintView);
539 };
540 
541 // Consists of challenge-response icon view and a label.
542 class LoginAuthUserView::ChallengeResponseView : public views::View {
543  public:
544   enum class State { kInitial, kAuthenticating, kFailure };
545 
ChallengeResponseView(base::RepeatingClosure on_start_tap)546   explicit ChallengeResponseView(base::RepeatingClosure on_start_tap)
547       : on_start_tap_(std::move(on_start_tap)) {
548     SetPaintToLayer();
549     layer()->SetFillsBoundsOpaquely(false);
550 
551     auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
552         views::BoxLayout::Orientation::kVertical));
553     layout->set_cross_axis_alignment(
554         views::BoxLayout::CrossAxisAlignment::kCenter);
555     auto arrow_button_view = std::make_unique<ArrowButtonView>(
556         base::BindRepeating(&ChallengeResponseView::ArrowButtonPressed,
557                             base::Unretained(this)),
558         kChallengeResponseArrowSizeDp);
559     arrow_button_view->SetInstallFocusRingOnFocus(true);
560     views::InstallCircleHighlightPathGenerator(arrow_button_view.get());
561     arrow_button_ = AddChildView(std::move(arrow_button_view));
562     arrow_button_->SetAccessibleName(l10n_util::GetStringUTF16(
563         IDS_ASH_LOGIN_START_SMART_CARD_AUTH_BUTTON_ACCESSIBLE_NAME));
564 
565     arrow_to_icon_spacer_ = AddChildView(std::make_unique<NonAccessibleView>());
566     arrow_to_icon_spacer_->SetPreferredSize(
567         gfx::Size(0, kSpacingBetweenChallengeResponseArrowAndIconDp));
568 
569     icon_ = AddChildView(std::make_unique<views::ImageView>());
570     icon_->SetImage(GetImageForIcon());
571 
572     auto* icon_to_label_spacer =
573         AddChildView(std::make_unique<NonAccessibleView>());
574     icon_to_label_spacer->SetPreferredSize(
575         gfx::Size(0, kSpacingBetweenChallengeResponseIconAndLabelDp));
576 
577     label_ = AddChildView(std::make_unique<views::Label>(
578         GetTextForLabel(), views::style::CONTEXT_LABEL,
579         views::style::STYLE_PRIMARY));
580     label_->SetAutoColorReadabilityEnabled(false);
581     label_->SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor(
582         AshColorProvider::ContentLayerType::kTextColorSecondary));
583     label_->SetSubpixelRenderingEnabled(false);
584     label_->SetFontList(views::Label::GetDefaultFontList().Derive(
585         /*size_delta=*/1, gfx::Font::FontStyle::ITALIC,
586         gfx::Font::Weight::NORMAL));
587   }
588 
589   ~ChallengeResponseView() override = default;
590 
SetState(State state)591   void SetState(State state) {
592     if (state_ == state)
593       return;
594     state_ = state;
595 
596     reset_state_timer_.Stop();
597     if (state == State::kFailure) {
598       reset_state_timer_.Start(
599           FROM_HERE, kChallengeResponseResetAfterFailureDelay,
600           base::BindOnce(&ChallengeResponseView::SetState,
601                          base::Unretained(this), State::kInitial));
602     }
603 
604     arrow_button_->EnableLoadingAnimation(state == State::kAuthenticating);
605     icon_->SetImage(GetImageForIcon());
606     label_->SetText(GetTextForLabel());
607 
608     if (state == State::kFailure) {
609       label_->NotifyAccessibilityEvent(ax::mojom::Event::kAlert,
610                                        /*send_native_event=*/true);
611     }
612 
613     Layout();
614   }
615 
RequestFocus()616   void RequestFocus() override { arrow_button_->RequestFocus(); }
617 
GetButtonForTesting()618   views::Button* GetButtonForTesting() { return arrow_button_; }
GetLabelForTesting()619   views::Label* GetLabelForTesting() { return label_; }
620 
621  private:
GetImageForIcon() const622   gfx::ImageSkia GetImageForIcon() const {
623     switch (state_) {
624       case State::kInitial:
625       case State::kAuthenticating:
626         return gfx::CreateVectorIcon(
627             kLockScreenSmartCardIcon, kChallengeResponseIconSizeDp,
628             AshColorProvider::Get()->GetContentLayerColor(
629                 AshColorProvider::ContentLayerType::kIconColorPrimary));
630       case State::kFailure:
631         return gfx::CreateVectorIcon(kLockScreenSmartCardFailureIcon,
632                                      kChallengeResponseIconSizeDp,
633                                      kChallengeResponseErrorColor);
634     }
635   }
636 
GetTextForLabel() const637   base::string16 GetTextForLabel() const {
638     switch (state_) {
639       case State::kInitial:
640       case State::kAuthenticating:
641         return l10n_util::GetStringUTF16(
642             IDS_ASH_LOGIN_SMART_CARD_SIGN_IN_MESSAGE);
643       case State::kFailure:
644         return l10n_util::GetStringUTF16(
645             IDS_ASH_LOGIN_SMART_CARD_SIGN_IN_FAILURE_MESSAGE);
646     }
647   }
648 
ArrowButtonPressed()649   void ArrowButtonPressed() {
650     // Ignore further clicks while handling the previous one.
651     if (state_ != State::kAuthenticating)
652       on_start_tap_.Run();
653   }
654 
655   base::RepeatingClosure on_start_tap_;
656   State state_ = State::kInitial;
657   ArrowButtonView* arrow_button_ = nullptr;
658   NonAccessibleView* arrow_to_icon_spacer_ = nullptr;
659   views::ImageView* icon_ = nullptr;
660   views::Label* label_ = nullptr;
661   base::OneShotTimer reset_state_timer_;
662 
663   DISALLOW_COPY_AND_ASSIGN(ChallengeResponseView);
664 };
665 
666 // The message shown to user when the auth method is |AUTH_DISABLED|.
667 class LoginAuthUserView::DisabledAuthMessageView : public views::View {
668  public:
669   class ASH_EXPORT TestApi {
670    public:
TestApi(DisabledAuthMessageView * view)671     explicit TestApi(DisabledAuthMessageView* view) : view_(view) {}
672     ~TestApi() = default;
673 
GetDisabledAuthMessageContent() const674     const base::string16& GetDisabledAuthMessageContent() const {
675       return view_->message_contents_->GetText();
676     }
677 
678    private:
679     DisabledAuthMessageView* const view_;
680   };
681 
682   // If the reason of disabled auth is multiprofile policy, then we can already
683   // set the text and message. Otherwise, in case of disabled auth because of
684   // time limit exceeded on child account, we wait for SetAuthDisabledMessage to
685   // be called.
DisabledAuthMessageView(bool shown_because_of_multiprofile_policy,MultiProfileUserBehavior multiprofile_policy)686   DisabledAuthMessageView(bool shown_because_of_multiprofile_policy,
687                           MultiProfileUserBehavior multiprofile_policy)
688       : shown_because_of_multiprofile_policy_(
689             shown_because_of_multiprofile_policy) {
690     SetLayoutManager(std::make_unique<views::BoxLayout>(
691         views::BoxLayout::Orientation::kVertical,
692         gfx::Insets(kDisabledAuthMessageVerticalBorderDp,
693                     kDisabledAuthMessageHorizontalBorderDp),
694         kDisabledAuthMessageChildrenSpacingDp));
695     SetPaintToLayer();
696     layer()->SetFillsBoundsOpaquely(false);
697     SetPreferredSize(gfx::Size(shown_because_of_multiprofile_policy
698                                    ? kDisabledAuthMessageMultiprofileWidthDp
699                                    : kDisabledAuthMessageTimeWidthDp,
700                                kDisabledAuthMessageHeightDp));
701     SetFocusBehavior(FocusBehavior::ALWAYS);
702     if (!shown_because_of_multiprofile_policy) {
703       message_icon_ = new views::ImageView();
704       message_icon_->SetPreferredSize(gfx::Size(
705           kDisabledAuthMessageIconSizeDp, kDisabledAuthMessageIconSizeDp));
706       message_icon_->SetImage(gfx::CreateVectorIcon(
707           kLockScreenTimeLimitMoonIcon, kDisabledAuthMessageIconSizeDp,
708           AshColorProvider::Get()->GetContentLayerColor(
709               AshColorProvider::ContentLayerType::kIconColorPrimary)));
710       AddChildView(message_icon_);
711     }
712 
713     auto decorate_label = [](views::Label* label) {
714       label->SetSubpixelRenderingEnabled(false);
715       label->SetAutoColorReadabilityEnabled(false);
716       label->SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor(
717           AshColorProvider::ContentLayerType::kTextColorPrimary));
718       label->SetFocusBehavior(FocusBehavior::ALWAYS);
719     };
720     message_title_ =
721         new views::Label(base::string16(), views::style::CONTEXT_LABEL,
722                          views::style::STYLE_PRIMARY);
723     message_title_->SetFontList(
724         gfx::FontList().Derive(kDisabledAuthMessageTitleFontSizeDeltaDp,
725                                gfx::Font::NORMAL, gfx::Font::Weight::MEDIUM));
726     decorate_label(message_title_);
727     AddChildView(message_title_);
728 
729     message_contents_ =
730         new views::Label(base::string16(), views::style::CONTEXT_LABEL,
731                          views::style::STYLE_PRIMARY);
732     message_contents_->SetFontList(
733         gfx::FontList().Derive(kDisabledAuthMessageContentsFontSizeDeltaDp,
734                                gfx::Font::NORMAL, gfx::Font::Weight::NORMAL));
735     decorate_label(message_contents_);
736     message_contents_->SetMultiLine(true);
737     AddChildView(message_contents_);
738 
739     if (shown_because_of_multiprofile_policy) {
740       message_title_->SetText(l10n_util::GetStringUTF16(
741           IDS_ASH_LOGIN_MULTI_PROFILES_RESTRICTED_POLICY_TITLE));
742       switch (multiprofile_policy) {
743         case MultiProfileUserBehavior::PRIMARY_ONLY:
744           message_contents_->SetText(l10n_util::GetStringUTF16(
745               IDS_ASH_LOGIN_MULTI_PROFILES_PRIMARY_ONLY_POLICY_MSG));
746           break;
747         case MultiProfileUserBehavior::NOT_ALLOWED:
748           message_contents_->SetText(l10n_util::GetStringUTF16(
749               IDS_ASH_LOGIN_MULTI_PROFILES_NOT_ALLOWED_POLICY_MSG));
750           break;
751         case MultiProfileUserBehavior::OWNER_PRIMARY_ONLY:
752           message_contents_->SetText(l10n_util::GetStringUTF16(
753               IDS_ASH_LOGIN_MULTI_PROFILES_OWNER_PRIMARY_ONLY_MSG));
754           break;
755         default:
756           NOTREACHED();
757       }
758     }
759   }
760 
761   ~DisabledAuthMessageView() override = default;
762 
763   // Set the parameters needed to render the message.
SetAuthDisabledMessage(const AuthDisabledData & auth_disabled_data,bool use_24hour_clock)764   void SetAuthDisabledMessage(const AuthDisabledData& auth_disabled_data,
765                               bool use_24hour_clock) {
766     // Do not do anything if message is already shown.
767     if (shown_because_of_multiprofile_policy_)
768       return;
769     LockScreenMessage message = GetLockScreenMessage(
770         auth_disabled_data.reason, auth_disabled_data.auth_reenabled_time,
771         auth_disabled_data.device_used_time, use_24hour_clock);
772     message_icon_->SetImage(gfx::CreateVectorIcon(
773         *message.icon, kDisabledAuthMessageIconSizeDp,
774         AshColorProvider::Get()->GetContentLayerColor(
775             AshColorProvider::ContentLayerType::kIconColorPrimary)));
776     message_title_->SetText(message.title);
777     message_contents_->SetText(message.content);
778     Layout();
779   }
780 
781   // views::View:
OnPaint(gfx::Canvas * canvas)782   void OnPaint(gfx::Canvas* canvas) override {
783     views::View::OnPaint(canvas);
784 
785     cc::PaintFlags flags;
786     flags.setStyle(cc::PaintFlags::kFill_Style);
787     flags.setColor(
788         PinRequestView::GetChildUserDialogColor(false /*using blur*/));
789     canvas->DrawRoundRect(GetContentsBounds(),
790                           kDisabledAuthMessageRoundedCornerRadiusDp, flags);
791   }
RequestFocus()792   void RequestFocus() override { message_title_->RequestFocus(); }
793 
794  private:
795   views::Label* message_title_;
796   views::Label* message_contents_;
797   views::ImageView* message_icon_;
798   // Used in case a child account has triggered the disabled auth message
799   // because of time limit exceeded while it also has disabled auth by
800   // multiprofile policy.
801   bool shown_because_of_multiprofile_policy_ = false;
802 
803   DISALLOW_COPY_AND_ASSIGN(DisabledAuthMessageView);
804 };
805 
806 // The message shown to user when TPM is locked.
807 class LoginAuthUserView::LockedTpmMessageView : public views::View {
808  public:
LockedTpmMessageView()809   LockedTpmMessageView() {
810     SetLayoutManager(std::make_unique<views::BoxLayout>(
811         views::BoxLayout::Orientation::kVertical,
812         gfx::Insets(kLockedTpmMessageVerticalBorderDp,
813                     kLockedTpmMessageHorizontalBorderDp),
814         kLockedTpmMessageChildrenSpacingDp));
815     SetPaintToLayer();
816     layer()->SetFillsBoundsOpaquely(false);
817     SetPreferredSize(
818         gfx::Size(kLockedTpmMessageWidthDp, kLockedTpmMessageHeightDp));
819     SetFocusBehavior(FocusBehavior::ALWAYS);
820 
821     auto message_icon = std::make_unique<views::ImageView>();
822     message_icon->SetPreferredSize(
823         gfx::Size(kLockedTpmMessageIconSizeDp, kLockedTpmMessageIconSizeDp));
824     message_icon->SetImage(gfx::CreateVectorIcon(
825         kLockScreenAlertIcon,
826         AshColorProvider::Get()->GetContentLayerColor(
827             AshColorProvider::ContentLayerType::kIconColorPrimary)));
828     message_icon_ = AddChildView(std::move(message_icon));
829 
830     message_warning_ = CreateLabel();
831     message_description_ = CreateLabel();
832 
833     // Set content.
834     base::string16 message_description = l10n_util::GetStringUTF16(
835         IDS_ASH_LOGIN_POD_TPM_LOCKED_ISSUE_DESCRIPTION);
836     message_description_->SetText(message_description);
837   }
838 
839   LockedTpmMessageView(const LockedTpmMessageView&) = delete;
840   LockedTpmMessageView& operator=(const LockedTpmMessageView&) = delete;
841   ~LockedTpmMessageView() override = default;
842 
843   // Set the parameters needed to render the message.
SetRemainingTime(base::TimeDelta time_left)844   void SetRemainingTime(base::TimeDelta time_left) {
845     base::string16 time_left_message;
846     if (base::TimeDurationFormatWithSeconds(
847             time_left, base::DurationFormatWidth::DURATION_WIDTH_WIDE,
848             &time_left_message)) {
849       base::string16 message_warning = l10n_util::GetStringFUTF16(
850           IDS_ASH_LOGIN_POD_TPM_LOCKED_ISSUE_WARNING, time_left_message);
851       message_warning_->SetText(message_warning);
852 
853       if (time_left.InMinutes() != prev_time_left_.InMinutes()) {
854         message_warning_->NotifyAccessibilityEvent(
855             ax::mojom::Event::kTextChanged, true);
856       }
857       prev_time_left_ = time_left;
858     }
859   }
860 
861   // views::View:
OnPaint(gfx::Canvas * canvas)862   void OnPaint(gfx::Canvas* canvas) override {
863     views::View::OnPaint(canvas);
864 
865     cc::PaintFlags flags;
866     flags.setStyle(cc::PaintFlags::kFill_Style);
867     flags.setColor(
868         PinRequestView::GetChildUserDialogColor(false /*using blur*/));
869     canvas->DrawRoundRect(GetContentsBounds(),
870                           kLockedTpmMessageRoundedCornerRadiusDp, flags);
871   }
RequestFocus()872   void RequestFocus() override { message_warning_->RequestFocus(); }
873 
874  private:
CreateLabel()875   views::Label* CreateLabel() {
876     auto label = std::make_unique<views::Label>(base::string16(),
877                                                 views::style::CONTEXT_LABEL,
878                                                 views::style::STYLE_PRIMARY);
879     label->SetFontList(gfx::FontList().Derive(kLockedTpmMessageDeltaDp,
880                                               gfx::Font::NORMAL,
881                                               gfx::Font::Weight::NORMAL));
882     label->SetSubpixelRenderingEnabled(false);
883     label->SetAutoColorReadabilityEnabled(false);
884     label->SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor(
885         AshColorProvider::ContentLayerType::kTextColorPrimary));
886     label->SetFocusBehavior(FocusBehavior::ALWAYS);
887     label->SetMultiLine(true);
888     return AddChildView(std::move(label));
889   }
890 
891   base::TimeDelta prev_time_left_;
892   views::Label* message_warning_;
893   views::Label* message_description_;
894   views::ImageView* message_icon_;
895 };
896 
897 LoginAuthUserView::AuthMethodsMetadata::AuthMethodsMetadata() = default;
898 LoginAuthUserView::AuthMethodsMetadata::~AuthMethodsMetadata() = default;
899 LoginAuthUserView::AuthMethodsMetadata::AuthMethodsMetadata(
900     const AuthMethodsMetadata&) = default;
901 
902 struct LoginAuthUserView::UiState {
UiStateash::LoginAuthUserView::UiState903   explicit UiState(const LoginAuthUserView* view) {
904     has_password = view->ShouldShowPasswordField();
905     has_pin_input = view->ShouldShowPinInputField();
906     has_pinpad = view->ShouldShowPinPad();
907     has_toggle = view->ShouldShowToggle();
908     has_fingerprint = view->HasAuthMethod(LoginAuthUserView::AUTH_FINGERPRINT);
909     has_challenge_response =
910         view->HasAuthMethod(LoginAuthUserView::AUTH_CHALLENGE_RESPONSE);
911     auth_disabled = view->HasAuthMethod(LoginAuthUserView::AUTH_DISABLED);
912     tpm_is_locked =
913         view->HasAuthMethod(LoginAuthUserView::AUTH_DISABLED_TPM_LOCKED);
914     force_online_sign_in =
915         view->HasAuthMethod(LoginAuthUserView::AUTH_ONLINE_SIGN_IN);
916 
917     non_pin_y_start_in_screen = view->GetBoundsInScreen().y();
918     pin_start_in_screen = view->pin_view_->GetBoundsInScreen().origin();
919   }
920 
921   bool has_password = false;
922   bool has_pin_input = false;
923   bool has_pinpad = false;
924   bool has_toggle = false;
925   bool has_fingerprint = false;
926   bool has_challenge_response = false;
927   bool auth_disabled = false;
928   bool tpm_is_locked = false;
929   bool force_online_sign_in = false;
930   // Used for this view's animation in `ApplyAnimationPostLayout`.
931   int non_pin_y_start_in_screen = 0;
932   gfx::Point pin_start_in_screen;
933 };
934 
TestApi(LoginAuthUserView * view)935 LoginAuthUserView::TestApi::TestApi(LoginAuthUserView* view) : view_(view) {}
936 
937 LoginAuthUserView::TestApi::~TestApi() = default;
938 
user_view() const939 LoginUserView* LoginAuthUserView::TestApi::user_view() const {
940   return view_->user_view_;
941 }
942 
password_view() const943 LoginPasswordView* LoginAuthUserView::TestApi::password_view() const {
944   return view_->password_view_;
945 }
946 
pin_view() const947 LoginPinView* LoginAuthUserView::TestApi::pin_view() const {
948   return view_->pin_view_;
949 }
950 
pin_input_view() const951 LoginPinInputView* LoginAuthUserView::TestApi::pin_input_view() const {
952   return view_->pin_input_view_;
953 }
954 
pin_password_toggle() const955 views::Button* LoginAuthUserView::TestApi::pin_password_toggle() const {
956   return view_->pin_password_toggle_;
957 }
958 
online_sign_in_message() const959 views::Button* LoginAuthUserView::TestApi::online_sign_in_message() const {
960   return view_->online_sign_in_message_;
961 }
962 
disabled_auth_message() const963 views::View* LoginAuthUserView::TestApi::disabled_auth_message() const {
964   return view_->disabled_auth_message_;
965 }
966 
challenge_response_button()967 views::Button* LoginAuthUserView::TestApi::challenge_response_button() {
968   return view_->challenge_response_view_->GetButtonForTesting();
969 }
970 
challenge_response_label()971 views::Label* LoginAuthUserView::TestApi::challenge_response_label() {
972   return view_->challenge_response_view_->GetLabelForTesting();
973 }
974 
HasAuthMethod(AuthMethods auth_method) const975 bool LoginAuthUserView::TestApi::HasAuthMethod(AuthMethods auth_method) const {
976   return view_->HasAuthMethod(auth_method);
977 }
978 
979 const base::string16&
GetDisabledAuthMessageContent() const980 LoginAuthUserView::TestApi::GetDisabledAuthMessageContent() const {
981   return LoginAuthUserView::DisabledAuthMessageView::TestApi(
982              view_->disabled_auth_message_)
983       .GetDisabledAuthMessageContent();
984 }
985 
986 LoginAuthUserView::Callbacks::Callbacks() = default;
987 
988 LoginAuthUserView::Callbacks::Callbacks(const Callbacks& other) = default;
989 
990 LoginAuthUserView::Callbacks::~Callbacks() = default;
991 
LoginAuthUserView(const LoginUserInfo & user,const Callbacks & callbacks)992 LoginAuthUserView::LoginAuthUserView(const LoginUserInfo& user,
993                                      const Callbacks& callbacks)
994     : NonAccessibleView(kLoginAuthUserViewClassName),
995       on_auth_(callbacks.on_auth),
996       on_tap_(callbacks.on_tap) {
997   DCHECK(callbacks.on_auth);
998   DCHECK(callbacks.on_tap);
999   DCHECK(callbacks.on_remove_warning_shown);
1000   DCHECK(callbacks.on_remove);
1001   DCHECK(callbacks.on_easy_unlock_icon_hovered);
1002   DCHECK_NE(user.basic_user_info.type, user_manager::USER_TYPE_PUBLIC_ACCOUNT);
1003 
1004   // Build child views.
1005   auto user_view = std::make_unique<LoginUserView>(
1006       LoginDisplayStyle::kLarge, true /*show_dropdown*/,
1007       base::BindRepeating(&LoginAuthUserView::OnUserViewTap,
1008                           base::Unretained(this)),
1009       callbacks.on_remove_warning_shown, callbacks.on_remove);
1010   user_view_ = user_view.get();
1011 
1012   const LoginPalette palette = CreateDefaultLoginPalette();
1013 
1014   auto password_view = std::make_unique<LoginPasswordView>(palette);
1015   password_view_ = password_view.get();
1016   password_view->SetPaintToLayer();  // Needed for opacity animation.
1017   password_view->layer()->SetFillsBoundsOpaquely(false);
1018   password_view_->SetDisplayPasswordButtonVisible(
1019       user.show_display_password_button);
1020   password_view->Init(
1021       base::BindRepeating(&LoginAuthUserView::OnAuthSubmit,
1022                           base::Unretained(this)),
1023       base::BindRepeating(&LoginAuthUserView::OnPasswordTextChanged,
1024                           base::Unretained(this)),
1025       callbacks.on_easy_unlock_icon_hovered,
1026       callbacks.on_easy_unlock_icon_tapped);
1027 
1028   auto pin_input_view = std::make_unique<LoginPinInputView>(palette);
1029   pin_input_view_ = pin_input_view.get();
1030   pin_input_view->Init(base::BindRepeating(&LoginAuthUserView::OnAuthSubmit,
1031                                            base::Unretained(this)),
1032                        base::BindRepeating(&LoginAuthUserView::OnPinTextChanged,
1033                                            base::Unretained(this)));
1034 
1035   auto toggle_container = std::make_unique<NonAccessibleView>();
1036   toggle_container->SetLayoutManager(std::make_unique<views::BoxLayout>(
1037       views::BoxLayout::Orientation::kVertical,
1038       gfx::Insets(kPinPasswordToggleButtonPaddingTop, 0, 0, 0)));
1039   pin_password_toggle_ =
1040       toggle_container->AddChildView(std::make_unique<SystemLabelButton>(
1041           base::BindRepeating(&LoginAuthUserView::OnSwitchButtonClicked,
1042                               base::Unretained(this)),
1043           GetPinPasswordToggleText(), SystemLabelButton::DisplayType::DEFAULT,
1044           /*multiline*/ false));
1045   pin_password_toggle_->SetMaxSize(
1046       gfx::Size(/*ignored*/ 0, kPinPasswordToggleButtonHeight));
1047 
1048   auto pin_view = std::make_unique<LoginPinView>(
1049       LoginPinView::Style::kAlphanumeric, palette,
1050       base::BindRepeating(&LoginAuthUserView::OnPinPadInsertDigit,
1051                           base::Unretained(this)),
1052       base::BindRepeating(&LoginAuthUserView::OnPinPadBackspace,
1053                           base::Unretained(this)));
1054   pin_view_ = pin_view.get();
1055   DCHECK(pin_view_->layer());
1056 
1057   auto padding_below_password_view = std::make_unique<NonAccessibleView>();
1058   padding_below_password_view->SetPreferredSize(gfx::Size(
1059       kNonEmptyWidthDp, kDistanceBetweenPasswordFieldAndPinKeyboardDp));
1060   padding_below_password_view_ = padding_below_password_view.get();
1061 
1062   auto padding_below_user_view = std::make_unique<NonAccessibleView>();
1063   padding_below_user_view->SetPreferredSize(
1064       gfx::Size(kNonEmptyWidthDp, kDistanceBetweenUserViewAndPasswordDp));
1065   padding_below_user_view_ = padding_below_user_view.get();
1066 
1067   base::string16 button_message =
1068       l10n_util::GetStringUTF16(IDS_ASH_LOGIN_SIGN_IN_REQUIRED_MESSAGE);
1069   if (user.is_signed_in) {
1070     button_message =
1071         l10n_util::GetStringUTF16(IDS_ASH_LOCK_SCREEN_VERIFY_ACCOUNT_MESSAGE);
1072   }
1073   bool is_login_secondary =
1074       Shell::Get()->session_controller()->GetSessionState() ==
1075       session_manager::SessionState::LOGIN_SECONDARY;
1076   auto online_sign_in_button = std::make_unique<SystemLabelButton>(
1077       base::BindRepeating(&LoginAuthUserView::OnOnlineSignInMessageTap,
1078                           base::Unretained(this)),
1079       button_message, SystemLabelButton::DisplayType::ALERT_WITH_ICON,
1080       /*multiline*/ false);
1081   // Disable online sign-in on secondary login screen as there is no OOBE there.
1082   online_sign_in_button->SetEnabled(!is_login_secondary);
1083   online_sign_in_message_ = online_sign_in_button.get();
1084 
1085   bool shown_because_of_multiprofile_policy =
1086       !user.is_multiprofile_allowed && is_login_secondary;
1087   auto disabled_auth_message = std::make_unique<DisabledAuthMessageView>(
1088       shown_because_of_multiprofile_policy, user.multiprofile_policy);
1089   disabled_auth_message_ = disabled_auth_message.get();
1090 
1091   auto locked_tpm_message_view = std::make_unique<LockedTpmMessageView>();
1092   locked_tpm_message_view_ = locked_tpm_message_view.get();
1093 
1094   auto fingerprint_view = std::make_unique<FingerprintView>();
1095   fingerprint_view_ = fingerprint_view.get();
1096 
1097   auto challenge_response_view =
1098       std::make_unique<ChallengeResponseView>(base::BindRepeating(
1099           &LoginAuthUserView::AttemptAuthenticateWithChallengeResponse,
1100           weak_factory_.GetWeakPtr()));
1101   challenge_response_view_ = challenge_response_view.get();
1102 
1103   SetPaintToLayer(ui::LayerType::LAYER_NOT_DRAWN);
1104 
1105   // Build layout.
1106   auto wrapped_password_view =
1107       login_views_utils::WrapViewForPreferredSize(std::move(password_view));
1108   auto wrapped_online_sign_in_message_view =
1109       login_views_utils::WrapViewForPreferredSize(
1110           std::move(online_sign_in_button));
1111   auto wrapped_disabled_auth_message_view =
1112       login_views_utils::WrapViewForPreferredSize(
1113           std::move(disabled_auth_message));
1114   auto wrapped_locked_tpm_message_view =
1115       login_views_utils::WrapViewForPreferredSize(
1116           std::move(locked_tpm_message_view));
1117   auto wrapped_user_view =
1118       login_views_utils::WrapViewForPreferredSize(std::move(user_view));
1119   auto wrapped_pin_view =
1120       login_views_utils::WrapViewForPreferredSize(std::move(pin_view));
1121   auto wrapped_pin_input_view =
1122       login_views_utils::WrapViewForPreferredSize(std::move(pin_input_view));
1123   auto wrapped_pin_password_toggle_view =
1124       login_views_utils::WrapViewForPreferredSize(std::move(toggle_container));
1125   auto wrapped_fingerprint_view =
1126       login_views_utils::WrapViewForPreferredSize(std::move(fingerprint_view));
1127   auto wrapped_challenge_response_view =
1128       login_views_utils::WrapViewForPreferredSize(
1129           std::move(challenge_response_view));
1130   auto wrapped_padding_below_password_view =
1131       login_views_utils::WrapViewForPreferredSize(
1132           std::move(padding_below_password_view));
1133   auto wrapped_padding_below_user_view =
1134       login_views_utils::WrapViewForPreferredSize(
1135           std::move(padding_below_user_view));
1136 
1137   // Add views in tabbing order; they are rendered in a different order below.
1138   views::View* wrapped_password_view_ptr =
1139       AddChildView(std::move(wrapped_password_view));
1140   views::View* wrapped_online_sign_in_message_view_ptr =
1141       AddChildView(std::move(wrapped_online_sign_in_message_view));
1142   views::View* wrapped_disabled_auth_message_view_ptr =
1143       AddChildView(std::move(wrapped_disabled_auth_message_view));
1144   views::View* wrapped_locked_tpm_message_view_ptr =
1145       AddChildView(std::move(wrapped_locked_tpm_message_view));
1146   views::View* wrapped_pin_input_view_ptr =
1147       AddChildView(std::move(wrapped_pin_input_view));
1148   views::View* wrapped_pin_view_ptr = AddChildView(std::move(wrapped_pin_view));
1149   views::View* wrapped_pin_password_toggle_view_ptr =
1150       AddChildView(std::move(wrapped_pin_password_toggle_view));
1151   views::View* wrapped_fingerprint_view_ptr =
1152       AddChildView(std::move(wrapped_fingerprint_view));
1153   views::View* wrapped_challenge_response_view_ptr =
1154       AddChildView(std::move(wrapped_challenge_response_view));
1155   views::View* wrapped_user_view_ptr =
1156       AddChildView(std::move(wrapped_user_view));
1157   views::View* wrapped_padding_below_password_view_ptr =
1158       AddChildView(std::move(wrapped_padding_below_password_view));
1159   views::View* wrapped_padding_below_user_view_ptr =
1160       AddChildView(std::move(wrapped_padding_below_user_view));
1161 
1162   // Use views::GridLayout instead of views::BoxLayout because views::BoxLayout
1163   // lays out children according to the view->children order.
1164   views::GridLayout* grid_layout =
1165       SetLayoutManager(std::make_unique<views::GridLayout>());
1166   views::ColumnSet* column_set = grid_layout->AddColumnSet(0);
1167   column_set->AddColumn(views::GridLayout::CENTER, views::GridLayout::LEADING,
1168                         0 /*resize_percent*/,
1169                         views::GridLayout::ColumnSize::kUsePreferred,
1170                         0 /*fixed_width*/, 0 /*min_width*/);
1171   auto add_view = [&](views::View* view) {
1172     grid_layout->StartRow(0 /*vertical_resize*/, 0 /*column_set_id*/);
1173     grid_layout->AddExistingView(view);
1174   };
1175   auto add_padding = [&](int amount) {
1176     grid_layout->AddPaddingRow(0 /*vertical_resize*/, amount /*size*/);
1177   };
1178 
1179   // Add views in rendering order.
1180   add_padding(kDistanceFromTopOfBigUserViewToUserIconDp);
1181   add_view(wrapped_user_view_ptr);
1182   add_view(wrapped_padding_below_user_view_ptr);
1183   add_view(wrapped_locked_tpm_message_view_ptr);
1184   add_view(wrapped_password_view_ptr);
1185   add_view(wrapped_online_sign_in_message_view_ptr);
1186   add_view(wrapped_disabled_auth_message_view_ptr);
1187   add_view(wrapped_pin_input_view_ptr);
1188   add_view(wrapped_padding_below_password_view_ptr);
1189   add_view(wrapped_pin_view_ptr);
1190   add_view(wrapped_pin_password_toggle_view_ptr);
1191   add_view(wrapped_fingerprint_view_ptr);
1192   add_view(wrapped_challenge_response_view_ptr);
1193   add_padding(kDistanceFromPinKeyboardToBigUserViewBottomDp);
1194 
1195   // Update authentication UI.
1196   CaptureStateForAnimationPreLayout();
1197   SetAuthMethods(auth_methods_);
1198   ApplyAnimationPostLayout(/*animate*/ false);
1199   user_view_->UpdateForUser(user, /*animate*/ false);
1200 }
1201 
1202 LoginAuthUserView::~LoginAuthUserView() = default;
1203 
SetAuthMethods(uint32_t auth_methods,const AuthMethodsMetadata & auth_metadata)1204 void LoginAuthUserView::SetAuthMethods(
1205     uint32_t auth_methods,
1206     const AuthMethodsMetadata& auth_metadata) {
1207   // It is an error to call this method without storing the previous state.
1208   DCHECK(previous_state_);
1209 
1210   // Apply changes and determine the new state of input fields.
1211   auth_methods_ = static_cast<AuthMethods>(auth_methods);
1212   auth_metadata_ = auth_metadata;
1213   UpdateInputFieldMode();
1214   const UiState current_state{this};
1215 
1216   online_sign_in_message_->SetVisible(current_state.force_online_sign_in);
1217   disabled_auth_message_->SetVisible(current_state.auth_disabled);
1218   locked_tpm_message_view_->SetVisible(current_state.tpm_is_locked);
1219   if (current_state.tpm_is_locked &&
1220       auth_metadata.time_until_tpm_unlock.has_value())
1221     locked_tpm_message_view_->SetRemainingTime(
1222         auth_metadata.time_until_tpm_unlock.value());
1223 
1224   // Adjust the PIN keyboard visibility before the password textfield's one, so
1225   // that when both are about to be hidden the focus doesn't jump to the "1"
1226   // keyboard button, causing unexpected accessibility effects.
1227   pin_view_->SetVisible(current_state.has_pinpad);
1228 
1229   password_view_->SetEnabled(current_state.has_password);
1230   password_view_->SetEnabledOnEmptyPassword(HasAuthMethod(AUTH_TAP));
1231   password_view_->SetFocusEnabledForChildViews(current_state.has_password);
1232   password_view_->SetVisible(current_state.has_password);
1233   password_view_->layer()->SetOpacity(current_state.has_password ? 1 : 0);
1234 
1235   pin_input_view_->UpdateLength(auth_metadata_.autosubmit_pin_length);
1236   pin_input_view_->SetAuthenticateWithEmptyPinOnReturnKey(
1237       HasAuthMethod(AUTH_TAP));
1238   pin_input_view_->SetVisible(current_state.has_pin_input);
1239 
1240   pin_password_toggle_->SetVisible(current_state.has_toggle);
1241   pin_password_toggle_->SetText(GetPinPasswordToggleText());
1242 
1243   fingerprint_view_->SetVisible(current_state.has_fingerprint);
1244   fingerprint_view_->SetCanUsePin(HasAuthMethod(AUTH_PIN));
1245   challenge_response_view_->SetVisible(current_state.has_challenge_response);
1246 
1247   padding_below_user_view_->SetPreferredSize(GetPaddingBelowUserView());
1248   padding_below_password_view_->SetPreferredSize(GetPaddingBelowPasswordView());
1249 
1250   password_view_->SetPlaceholderText(GetPasswordViewPlaceholder());
1251   const std::string& user_display_email =
1252       current_user().basic_user_info.display_email;
1253   password_view_->SetAccessibleName(l10n_util::GetStringFUTF16(
1254       IDS_ASH_LOGIN_POD_PASSWORD_FIELD_ACCESSIBLE_NAME,
1255       base::UTF8ToUTF16(user_display_email)));
1256 
1257   // Only the active auth user view has authentication methods. If that is the
1258   // case, then render the user view as if it was always focused, since clicking
1259   // on it will not do anything (such as swapping users).
1260   user_view_->SetForceOpaque(auth_methods_ != AUTH_NONE);
1261   user_view_->SetTapEnabled(auth_methods_ == AUTH_NONE);
1262 
1263   UpdateFocus();
1264   PreferredSizeChanged();
1265 }
1266 
SetEasyUnlockIcon(EasyUnlockIconId id,const base::string16 & accessibility_label)1267 void LoginAuthUserView::SetEasyUnlockIcon(
1268     EasyUnlockIconId id,
1269     const base::string16& accessibility_label) {
1270   password_view_->SetEasyUnlockIcon(id, accessibility_label);
1271 
1272   const std::string& user_display_email =
1273       current_user().basic_user_info.display_email;
1274   if (id == EasyUnlockIconId::UNLOCKED) {
1275     password_view_->SetAccessibleName(l10n_util::GetStringFUTF16(
1276         IDS_ASH_LOGIN_POD_AUTH_TAP_PASSWORD_FIELD_ACCESSIBLE_NAME,
1277         base::UTF8ToUTF16(user_display_email)));
1278   } else {
1279     password_view_->SetAccessibleName(l10n_util::GetStringFUTF16(
1280         IDS_ASH_LOGIN_POD_PASSWORD_FIELD_ACCESSIBLE_NAME,
1281         base::UTF8ToUTF16(user_display_email)));
1282   }
1283 }
1284 
CaptureStateForAnimationPreLayout()1285 void LoginAuthUserView::CaptureStateForAnimationPreLayout() {
1286   auto stop_animation = [](views::View* view) {
1287     if (view->layer()->GetAnimator()->is_animating())
1288       view->layer()->GetAnimator()->StopAnimating();
1289   };
1290 
1291   // Stop any running animation scheduled in ApplyAnimationPostLayout.
1292   stop_animation(this);
1293   stop_animation(password_view_);
1294   stop_animation(pin_view_);
1295   stop_animation(fingerprint_view_);
1296   stop_animation(challenge_response_view_);
1297   stop_animation(pin_password_toggle_);
1298 
1299   DCHECK(!previous_state_);
1300   previous_state_ = std::make_unique<UiState>(this);
1301 }
1302 
ApplyAnimationPostLayout(bool animate)1303 void LoginAuthUserView::ApplyAnimationPostLayout(bool animate) {
1304   DCHECK(previous_state_);
1305   // Release the previous state if no animation should be performed.
1306   if (!animate) {
1307     previous_state_.reset();
1308     return;
1309   }
1310 
1311   const UiState current_state{this};
1312 
1313   ////////
1314   // Animate the user info (ie, icon, name) up or down the screen.
1315   {
1316     int non_pin_y_end_in_screen = GetBoundsInScreen().y();
1317 
1318     // Transform the layer so the user view renders where it used to be. This
1319     // requires a y offset.
1320     // Note: Doing this animation via ui::ScopedLayerAnimationSettings works,
1321     // but it seems that the timing gets slightly out of sync with the PIN
1322     // animation.
1323     auto move_to_center = std::make_unique<ui::InterpolatedTranslation>(
1324         gfx::PointF(0, previous_state_->non_pin_y_start_in_screen -
1325                            non_pin_y_end_in_screen),
1326         gfx::PointF());
1327     auto transition =
1328         ui::LayerAnimationElement::CreateInterpolatedTransformElement(
1329             std::move(move_to_center),
1330             base::TimeDelta::FromMilliseconds(
1331                 login_constants::kChangeUserAnimationDurationMs));
1332     transition->set_tween_type(gfx::Tween::Type::FAST_OUT_SLOW_IN);
1333     auto* sequence = new ui::LayerAnimationSequence(std::move(transition));
1334     auto* observer = BuildObserverToNotifyA11yLocationChanged(this);
1335     sequence->AddObserver(observer);
1336     observer->SetActive();
1337     layer()->GetAnimator()->StartAnimation(sequence);
1338   }
1339 
1340   ////////
1341   // Fade the password view if it is being hidden or shown.
1342 
1343   if (current_state.has_password != previous_state_->has_password) {
1344     float opacity_start = 0, opacity_end = 1;
1345     if (!current_state.has_password)
1346       std::swap(opacity_start, opacity_end);
1347 
1348     password_view_->layer()->SetOpacity(opacity_start);
1349 
1350     {
1351       ui::ScopedLayerAnimationSettings settings(
1352           password_view_->layer()->GetAnimator());
1353       settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(
1354           login_constants::kChangeUserAnimationDurationMs));
1355       settings.SetTweenType(gfx::Tween::Type::FAST_OUT_SLOW_IN);
1356       if (previous_state_->has_password && !current_state.has_password) {
1357         settings.AddObserver(
1358             new ClearPasswordAndHideAnimationObserver(password_view_));
1359       }
1360 
1361       password_view_->layer()->SetOpacity(opacity_end);
1362     }
1363   }
1364 
1365   ////////
1366   // Fade the pin/pwd toggle if its being hidden or shown.
1367   if (previous_state_->has_toggle != current_state.has_toggle) {
1368     float opacity_start = 0, opacity_end = 1;
1369     if (!current_state.has_toggle)
1370       std::swap(opacity_start, opacity_end);
1371 
1372     pin_password_toggle_->layer()->SetOpacity(opacity_start);
1373 
1374     {
1375       ui::ScopedLayerAnimationSettings settings(
1376           pin_password_toggle_->layer()->GetAnimator());
1377       settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(
1378           login_constants::kChangeUserAnimationDurationMs));
1379       settings.SetTweenType(gfx::Tween::Type::FAST_OUT_SLOW_IN);
1380       pin_password_toggle_->layer()->SetOpacity(opacity_end);
1381     }
1382   }
1383 
1384   ////////
1385   // Grow/shrink the PIN keyboard if it is being hidden or shown.
1386 
1387   if (previous_state_->has_pinpad != current_state.has_pinpad) {
1388     if (!current_state.has_pinpad) {
1389       gfx::Point pin_end_in_screen = pin_view_->GetBoundsInScreen().origin();
1390       gfx::Rect pin_bounds = pin_view_->bounds();
1391       pin_bounds.set_x(previous_state_->pin_start_in_screen.x() -
1392                        pin_end_in_screen.x());
1393       pin_bounds.set_y(previous_state_->pin_start_in_screen.y() -
1394                        pin_end_in_screen.y());
1395 
1396       // Since PIN is disabled, the previous Layout() hid the PIN keyboard.
1397       // We need to redisplay it where it used to be.
1398       // pin_view_->SetVisible(true);
1399       pin_view_->SetBoundsRect(pin_bounds);
1400     }
1401 
1402     auto transition = std::make_unique<PinKeyboardAnimation>(
1403         current_state.has_pinpad /*grow*/, pin_view_->height(),
1404         // TODO(https://crbug.com/955119): Implement proper animation.
1405         base::TimeDelta::FromMilliseconds(
1406             login_constants::kChangeUserAnimationDurationMs / 2.0f),
1407         gfx::Tween::FAST_OUT_SLOW_IN);
1408     auto* sequence = new ui::LayerAnimationSequence(std::move(transition));
1409 
1410     // Hide the PIN keyboard after animation if needed.
1411     if (!current_state.has_pinpad) {
1412       auto* observer = BuildObserverToHideView(pin_view_);
1413       sequence->AddObserver(observer);
1414       observer->SetActive();
1415     }
1416     auto* observer = BuildObserverToNotifyA11yLocationChanged(pin_view_);
1417     sequence->AddObserver(observer);
1418     observer->SetActive();
1419     pin_view_->layer()->GetAnimator()->ScheduleAnimation(sequence);
1420   }
1421 
1422   ////////
1423   // Fade the fingerprint view if it is being hidden or shown.
1424 
1425   if (previous_state_->has_fingerprint != current_state.has_fingerprint) {
1426     float opacity_start = 0, opacity_end = 1;
1427     if (!current_state.has_fingerprint)
1428       std::swap(opacity_start, opacity_end);
1429 
1430     fingerprint_view_->layer()->SetOpacity(opacity_start);
1431 
1432     {
1433       ui::ScopedLayerAnimationSettings settings(
1434           fingerprint_view_->layer()->GetAnimator());
1435       settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(
1436           login_constants::kChangeUserAnimationDurationMs));
1437       settings.SetTweenType(gfx::Tween::Type::FAST_OUT_SLOW_IN);
1438       fingerprint_view_->layer()->SetOpacity(opacity_end);
1439     }
1440   }
1441 
1442   ////////
1443   // Fade the challenge response (Smart Card) if it is being hidden or shown.
1444   if (previous_state_->has_challenge_response !=
1445       current_state.has_challenge_response) {
1446     float opacity_start = 0, opacity_end = 1;
1447     if (!current_state.has_challenge_response)
1448       std::swap(opacity_start, opacity_end);
1449 
1450     challenge_response_view_->layer()->SetOpacity(opacity_start);
1451 
1452     {
1453       ui::ScopedLayerAnimationSettings settings(
1454           challenge_response_view_->layer()->GetAnimator());
1455       settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(
1456           login_constants::kChangeUserAnimationDurationMs));
1457       settings.SetTweenType(gfx::Tween::Type::FAST_OUT_SLOW_IN);
1458       challenge_response_view_->layer()->SetOpacity(opacity_end);
1459     }
1460   }
1461 
1462   previous_state_.reset();
1463 }
1464 
UpdateForUser(const LoginUserInfo & user)1465 void LoginAuthUserView::UpdateForUser(const LoginUserInfo& user) {
1466   const bool user_changed = current_user().basic_user_info.account_id !=
1467                             user.basic_user_info.account_id;
1468   user_view_->UpdateForUser(user, true /*animate*/);
1469   if (user_changed) {
1470     password_view_->Reset();
1471     password_view_->SetDisplayPasswordButtonVisible(
1472         user.show_display_password_button);
1473   }
1474   online_sign_in_message_->SetText(
1475       l10n_util::GetStringUTF16(IDS_ASH_LOGIN_SIGN_IN_REQUIRED_MESSAGE));
1476 }
1477 
SetFingerprintState(FingerprintState state)1478 void LoginAuthUserView::SetFingerprintState(FingerprintState state) {
1479   fingerprint_view_->SetState(state);
1480 }
1481 
NotifyFingerprintAuthResult(bool success)1482 void LoginAuthUserView::NotifyFingerprintAuthResult(bool success) {
1483   fingerprint_view_->NotifyFingerprintAuthResult(success);
1484 }
1485 
SetAuthDisabledMessage(const AuthDisabledData & auth_disabled_data)1486 void LoginAuthUserView::SetAuthDisabledMessage(
1487     const AuthDisabledData& auth_disabled_data) {
1488   disabled_auth_message_->SetAuthDisabledMessage(
1489       auth_disabled_data, current_user().use_24hour_clock);
1490   Layout();
1491 }
1492 
current_user() const1493 const LoginUserInfo& LoginAuthUserView::current_user() const {
1494   return user_view_->current_user();
1495 }
1496 
GetActiveInputView()1497 views::View* LoginAuthUserView::GetActiveInputView() {
1498   if (input_field_mode_ == InputFieldMode::PIN_WITH_TOGGLE)
1499     return pin_input_view_;
1500 
1501   return password_view_;
1502 }
1503 
CalculatePreferredSize() const1504 gfx::Size LoginAuthUserView::CalculatePreferredSize() const {
1505   gfx::Size size = views::View::CalculatePreferredSize();
1506   // Make sure we are at least as big as the user view. If we do not do this the
1507   // view will be below minimum size when no auth methods are displayed.
1508   size.SetToMax(user_view_->GetPreferredSize());
1509   return size;
1510 }
1511 
RequestFocus()1512 void LoginAuthUserView::RequestFocus() {
1513   if (input_field_mode_ == InputFieldMode::PIN_WITH_TOGGLE)
1514     pin_input_view_->RequestFocus();
1515   else
1516     password_view_->RequestFocus();
1517 }
1518 
OnAuthSubmit(const base::string16 & password)1519 void LoginAuthUserView::OnAuthSubmit(const base::string16& password) {
1520   // Pressing enter when the password field is empty and tap-to-unlock is
1521   // enabled should attempt unlock.
1522   if (HasAuthMethod(AUTH_TAP) && password.empty()) {
1523     Shell::Get()->login_screen_controller()->AuthenticateUserWithEasyUnlock(
1524         current_user().basic_user_info.account_id);
1525     return;
1526   }
1527 
1528   password_view_->SetReadOnly(true);
1529   pin_input_view_->SetReadOnly(true);
1530 
1531   Shell::Get()->login_screen_controller()->AuthenticateUserWithPasswordOrPin(
1532       current_user().basic_user_info.account_id, base::UTF16ToUTF8(password),
1533       HasAuthMethod(AUTH_PIN),
1534       base::BindOnce(&LoginAuthUserView::OnAuthComplete,
1535                      weak_factory_.GetWeakPtr()));
1536 }
1537 
OnAuthComplete(base::Optional<bool> auth_success)1538 void LoginAuthUserView::OnAuthComplete(base::Optional<bool> auth_success) {
1539   // Clear the password only if auth fails. Make sure to keep the password view
1540   // disabled even if auth succeededs, as if the user submits a password while
1541   // animating the next lock screen will not work as expected. See
1542   // https://crbug.com/808486.
1543   if (!auth_success.has_value() || !auth_success.value()) {
1544     password_view_->Reset();
1545     password_view_->SetReadOnly(false);
1546     pin_input_view_->Reset();
1547     pin_input_view_->SetReadOnly(false);
1548   }
1549 
1550   on_auth_.Run(auth_success.value(), /*display_error_messages=*/true);
1551 }
1552 
OnChallengeResponseAuthComplete(base::Optional<bool> auth_success)1553 void LoginAuthUserView::OnChallengeResponseAuthComplete(
1554     base::Optional<bool> auth_success) {
1555   if (!auth_success.has_value() || !auth_success.value()) {
1556     password_view_->Reset();
1557     password_view_->SetReadOnly(false);
1558     // If the user canceled the PIN request during ChallengeResponse,
1559     // ChallengeResponse will fail with an unknown error. Since this is
1560     // expected, we do not show this error.
1561     if (Shell::Get()
1562             ->login_screen_controller()
1563             ->GetSecurityTokenPinRequestCanceled()) {
1564       challenge_response_view_->SetState(
1565           ChallengeResponseView::State::kInitial);
1566     } else {
1567       challenge_response_view_->SetState(
1568           ChallengeResponseView::State::kFailure);
1569     }
1570   }
1571 
1572   on_auth_.Run(auth_success.value_or(false), /*display_error_messages=*/false);
1573 }
1574 
OnUserViewTap()1575 void LoginAuthUserView::OnUserViewTap() {
1576   if (HasAuthMethod(AUTH_TAP)) {
1577     Shell::Get()->login_screen_controller()->AuthenticateUserWithEasyUnlock(
1578         current_user().basic_user_info.account_id);
1579   } else if (HasAuthMethod(AUTH_ONLINE_SIGN_IN)) {
1580     // Tapping anywhere in the user view is the same with tapping the message.
1581     OnOnlineSignInMessageTap();
1582   } else {
1583     on_tap_.Run();
1584   }
1585 }
1586 
OnOnlineSignInMessageTap()1587 void LoginAuthUserView::OnOnlineSignInMessageTap() {
1588   Shell::Get()->login_screen_controller()->ShowGaiaSignin(
1589       current_user().basic_user_info.account_id);
1590 }
1591 
OnPinPadBackspace()1592 void LoginAuthUserView::OnPinPadBackspace() {
1593   DCHECK(pin_input_view_);
1594   DCHECK(password_view_);
1595   if (input_field_mode_ == InputFieldMode::PIN_WITH_TOGGLE)
1596     pin_input_view_->Backspace();
1597   else
1598     password_view_->Backspace();
1599 }
1600 
OnPinPadInsertDigit(int digit)1601 void LoginAuthUserView::OnPinPadInsertDigit(int digit) {
1602   DCHECK(pin_input_view_);
1603   DCHECK(password_view_);
1604   if (input_field_mode_ == InputFieldMode::PIN_WITH_TOGGLE)
1605     pin_input_view_->InsertDigit(digit);
1606   else
1607     password_view_->InsertNumber(digit);
1608 }
1609 
OnPasswordTextChanged(bool is_empty)1610 void LoginAuthUserView::OnPasswordTextChanged(bool is_empty) {
1611   DCHECK(pin_view_);
1612   if (input_field_mode_ != InputFieldMode::PIN_WITH_TOGGLE)
1613     pin_view_->OnPasswordTextChanged(is_empty);
1614 }
1615 
OnPinTextChanged(bool is_empty)1616 void LoginAuthUserView::OnPinTextChanged(bool is_empty) {
1617   DCHECK(pin_view_);
1618   if (input_field_mode_ == InputFieldMode::PIN_WITH_TOGGLE)
1619     pin_view_->OnPasswordTextChanged(is_empty);
1620 }
1621 
HasAuthMethod(AuthMethods auth_method) const1622 bool LoginAuthUserView::HasAuthMethod(AuthMethods auth_method) const {
1623   return (auth_methods_ & auth_method) != 0;
1624 }
1625 
AttemptAuthenticateWithChallengeResponse()1626 void LoginAuthUserView::AttemptAuthenticateWithChallengeResponse() {
1627   challenge_response_view_->SetState(
1628       ChallengeResponseView::State::kAuthenticating);
1629   Shell::Get()
1630       ->login_screen_controller()
1631       ->AuthenticateUserWithChallengeResponse(
1632           current_user().basic_user_info.account_id,
1633           base::BindOnce(&LoginAuthUserView::OnChallengeResponseAuthComplete,
1634                          weak_factory_.GetWeakPtr()));
1635 }
1636 
UpdateFocus()1637 void LoginAuthUserView::UpdateFocus() {
1638   DCHECK(previous_state_);
1639   const UiState current_state{this};
1640 
1641   if (current_state.tpm_is_locked) {
1642     locked_tpm_message_view_->RequestFocus();
1643     return;
1644   }
1645   // All further states are exclusive.
1646   if (current_state.auth_disabled)
1647     disabled_auth_message_->RequestFocus();
1648   if (current_state.has_challenge_response)
1649     challenge_response_view_->RequestFocus();
1650   if (current_state.has_password && !previous_state_->has_password)
1651     password_view_->RequestFocus();
1652   if (current_state.has_pin_input)
1653     pin_input_view_->RequestFocus();
1654   // Tapping the user view will trigger the online sign-in flow when
1655   // |force_online_sign_in| is true.
1656   if (current_state.force_online_sign_in)
1657     user_view_->RequestFocus();
1658 }
1659 
OnSwitchButtonClicked()1660 void LoginAuthUserView::OnSwitchButtonClicked() {
1661   // Ignore events from the switch button if no longer present.
1662   if (input_field_mode_ != InputFieldMode::PIN_WITH_TOGGLE &&
1663       input_field_mode_ != InputFieldMode::PWD_WITH_TOGGLE) {
1664     return;
1665   }
1666 
1667   // Clear both input fields.
1668   password_view_->Reset();
1669   pin_input_view_->Reset();
1670   // Cache the current state of the UI.
1671   CaptureStateForAnimationPreLayout();
1672   // Same auth methods, but the input field mode has changed.
1673   input_field_mode_ = (input_field_mode_ == InputFieldMode::PIN_WITH_TOGGLE)
1674                           ? InputFieldMode::PWD_WITH_TOGGLE
1675                           : InputFieldMode::PIN_WITH_TOGGLE;
1676   SetAuthMethods(auth_methods_, auth_metadata_);
1677   // Layout and animate.
1678   Layout();
1679   ApplyAnimationPostLayout(/*animate*/ true);
1680 }
1681 
UpdateInputFieldMode()1682 void LoginAuthUserView::UpdateInputFieldMode() {
1683   // There isn't an input field when any of the following is true:
1684   // - Challenge response is active (Smart Card)
1685   // - Online sign in message shown
1686   // - Disabled message shown
1687   // - No password auth available
1688   if (HasAuthMethod(AUTH_CHALLENGE_RESPONSE) ||
1689       HasAuthMethod(AUTH_ONLINE_SIGN_IN) ||
1690       HasAuthMethod(AUTH_DISABLED) ||
1691       !HasAuthMethod(AUTH_PASSWORD)) {
1692     input_field_mode_ = InputFieldMode::NONE;
1693     return;
1694   }
1695 
1696   if (!HasAuthMethod(AUTH_PIN)) {
1697     input_field_mode_ = InputFieldMode::PASSWORD_ONLY;
1698     return;
1699   }
1700 
1701   // Default to combined password/pin if autosubmit is disabled.
1702   const int pin_length = auth_metadata_.autosubmit_pin_length;
1703   if (!LoginPinInputView::IsAutosubmitSupported(pin_length)) {
1704     input_field_mode_ = InputFieldMode::PIN_AND_PASSWORD;
1705     return;
1706   }
1707 
1708   // Defaults to PIN + switch button if not showing the switch button already.
1709   if (input_field_mode_ != InputFieldMode::PIN_WITH_TOGGLE &&
1710       input_field_mode_ != InputFieldMode::PWD_WITH_TOGGLE) {
1711     input_field_mode_ = InputFieldMode::PIN_WITH_TOGGLE;
1712     return;
1713   }
1714 }
1715 
ShouldShowPinPad() const1716 bool LoginAuthUserView::ShouldShowPinPad() const {
1717   if (auth_metadata_.virtual_keyboard_visible)
1718     return false;
1719   switch (input_field_mode_) {
1720     case InputFieldMode::NONE:
1721       return false;
1722     case InputFieldMode::PASSWORD_ONLY:
1723     case InputFieldMode::PWD_WITH_TOGGLE:
1724       return auth_metadata_.show_pinpad_for_pw;
1725     case InputFieldMode::PIN_AND_PASSWORD:
1726     case InputFieldMode::PIN_WITH_TOGGLE:
1727       return true;
1728   }
1729 }
1730 
ShouldShowPasswordField() const1731 bool LoginAuthUserView::ShouldShowPasswordField() const {
1732   return input_field_mode_ == InputFieldMode::PASSWORD_ONLY ||
1733          input_field_mode_ == InputFieldMode::PIN_AND_PASSWORD ||
1734          input_field_mode_ == InputFieldMode::PWD_WITH_TOGGLE;
1735 }
1736 
ShouldShowPinInputField() const1737 bool LoginAuthUserView::ShouldShowPinInputField() const {
1738   return input_field_mode_ == InputFieldMode::PIN_WITH_TOGGLE;
1739 }
1740 
ShouldShowToggle() const1741 bool LoginAuthUserView::ShouldShowToggle() const {
1742   return input_field_mode_ == InputFieldMode::PIN_WITH_TOGGLE ||
1743          input_field_mode_ == InputFieldMode::PWD_WITH_TOGGLE;
1744 }
1745 
GetPaddingBelowUserView() const1746 gfx::Size LoginAuthUserView::GetPaddingBelowUserView() const {
1747   const UiState state{this};
1748 
1749   if (state.has_password)
1750     return SizeFromHeight(kDistanceBetweenUserViewAndPasswordDp);
1751   if (state.has_pin_input)
1752     return SizeFromHeight(kDistanceBetweenUserViewAndPinInputDp);
1753   if (state.force_online_sign_in)
1754     return SizeFromHeight(kDistanceBetweenUserViewAndOnlineSigninDp);
1755   if (state.has_challenge_response)
1756     return SizeFromHeight(kDistanceBetweenUserViewAndChallengeResponseDp);
1757 
1758   return SizeFromHeight(0);
1759 }
1760 
GetPaddingBelowPasswordView() const1761 gfx::Size LoginAuthUserView::GetPaddingBelowPasswordView() const {
1762   const UiState state{this};
1763 
1764   if (state.has_pinpad)
1765     return SizeFromHeight(kDistanceBetweenPasswordFieldAndPinKeyboardDp);
1766   if (state.has_fingerprint)
1767     return SizeFromHeight(kDistanceBetweenPasswordFieldAndFingerprintViewDp);
1768   if (state.has_challenge_response)
1769     return SizeFromHeight(kDistanceBetweenPwdFieldAndChallengeResponseViewDp);
1770 
1771   return SizeFromHeight(0);
1772 }
1773 
GetPinPasswordToggleText()1774 base::string16 LoginAuthUserView::GetPinPasswordToggleText() {
1775   if (input_field_mode_ == InputFieldMode::PWD_WITH_TOGGLE)
1776     return l10n_util::GetStringUTF16(IDS_ASH_LOGIN_SWITCH_TO_PIN);
1777   else
1778     return l10n_util::GetStringUTF16(IDS_ASH_LOGIN_SWITCH_TO_PASSWORD);
1779 }
1780 
GetPasswordViewPlaceholder() const1781 base::string16 LoginAuthUserView::GetPasswordViewPlaceholder() const {
1782   // Note: |AUTH_TAP| must have higher priority than |AUTH_PIN| when
1783   // determining the placeholder.
1784   if (HasAuthMethod(AUTH_TAP))
1785     return l10n_util::GetStringUTF16(
1786         IDS_ASH_LOGIN_POD_PASSWORD_TAP_PLACEHOLDER);
1787   if (input_field_mode_ == InputFieldMode::PIN_AND_PASSWORD)
1788     return l10n_util::GetStringUTF16(
1789         IDS_ASH_LOGIN_POD_PASSWORD_PIN_PLACEHOLDER);
1790 
1791   return l10n_util::GetStringUTF16(IDS_ASH_LOGIN_POD_PASSWORD_PLACEHOLDER);
1792 }
1793 
1794 }  // namespace ash
1795