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/lock_debug_view.h"
6 
7 #include <algorithm>
8 #include <map>
9 #include <memory>
10 #include <utility>
11 
12 #include "ash/detachable_base/detachable_base_pairing_status.h"
13 #include "ash/ime/ime_controller_impl.h"
14 #include "ash/login/login_screen_controller.h"
15 #include "ash/login/ui/lock_contents_view.h"
16 #include "ash/login/ui/lock_screen.h"
17 #include "ash/login/ui/login_data_dispatcher.h"
18 #include "ash/login/ui/login_detachable_base_model.h"
19 #include "ash/login/ui/non_accessible_view.h"
20 #include "ash/login/ui/views_utils.h"
21 #include "ash/public/cpp/kiosk_app_menu.h"
22 #include "ash/public/cpp/login_types.h"
23 #include "ash/shelf/login_shelf_view.h"
24 #include "ash/shelf/shelf.h"
25 #include "ash/shelf/shelf_widget.h"
26 #include "ash/shell.h"
27 #include "ash/style/ash_color_provider.h"
28 #include "ash/wallpaper/wallpaper_controller_impl.h"
29 #include "base/bind.h"
30 #include "base/memory/ptr_util.h"
31 #include "base/optional.h"
32 #include "base/stl_util.h"
33 #include "base/strings/string_number_conversions.h"
34 #include "base/strings/utf_string_conversions.h"
35 #include "ui/base/ime/chromeos/ime_keyboard.h"
36 #include "ui/views/controls/button/md_text_button.h"
37 #include "ui/views/controls/scroll_view.h"
38 #include "ui/views/controls/scrollbar/overlay_scroll_bar.h"
39 #include "ui/views/layout/box_layout.h"
40 #include "ui/views/view.h"
41 
42 namespace ash {
43 namespace {
44 
45 constexpr const char* kDebugUserNames[] = {
46     "Angelina Johnson", "Marcus Cohen", "Chris Wallace",
47     "Debbie Craig",     "Stella Wong",  "Stephanie Wade",
48 };
49 
50 constexpr const char* kDebugPublicAccountNames[] = {
51     "Seattle Public Library",
52     "San Jose Public Library",
53     "Sunnyvale Public Library",
54     "Mountain View Public Library",
55 };
56 
57 constexpr const char* kDebugDetachableBases[] = {"Base A", "Base B", "Base C"};
58 
59 constexpr const char kDebugOsVersion[] =
60     "Chromium 64.0.3279.0 (Platform 10146.0.0 dev-channel peppy test)";
61 constexpr const char kDebugEnterpriseInfo[] = "Asset ID: 1111";
62 constexpr const char kDebugBluetoothName[] = "Bluetooth adapter";
63 
64 constexpr const char kDebugKioskAppId[] = "asdf1234";
65 constexpr const char kDebugKioskAppName[] = "Test App Name";
66 
67 constexpr const char kDebugDefaultLocaleCode[] = "en-GB";
68 constexpr const char kDebugDefaultLocaleTitle[] = "English";
69 constexpr const char kDebugEnterpriseDomain[] = "library.com";
70 
71 // Additional state for a user that the debug UI needs to reference.
72 struct UserMetadata {
UserMetadataash::__anonea65d5820111::UserMetadata73   explicit UserMetadata(const UserInfo& user_info)
74       : account_id(user_info.account_id),
75         display_name(user_info.display_name),
76         type(user_info.type) {}
77 
78   AccountId account_id;
79   std::string display_name;
80   bool enable_pin = false;
81   bool enable_tap_to_unlock = false;
82   bool enable_challenge_response = false;  // Smart Card
83   bool enable_auth = true;
84   user_manager::UserType type = user_manager::USER_TYPE_REGULAR;
85   EasyUnlockIconId easy_unlock_id = EasyUnlockIconId::NONE;
86   FingerprintState fingerprint_state = FingerprintState::UNAVAILABLE;
87 };
88 
DetachableBasePairingStatusToString(DetachableBasePairingStatus pairing_status)89 std::string DetachableBasePairingStatusToString(
90     DetachableBasePairingStatus pairing_status) {
91   switch (pairing_status) {
92     case DetachableBasePairingStatus::kNone:
93       return "No device";
94     case DetachableBasePairingStatus::kAuthenticated:
95       return "Authenticated";
96     case DetachableBasePairingStatus::kNotAuthenticated:
97       return "Not authenticated";
98     case DetachableBasePairingStatus::kInvalidDevice:
99       return "Invalid device";
100   }
101   return "Unknown";
102 }
103 
104 // Update the user data based on |type| and |user_index|.
PopulateUserData(const LoginUserInfo & user,user_manager::UserType type,int user_index)105 LoginUserInfo PopulateUserData(const LoginUserInfo& user,
106                                user_manager::UserType type,
107                                int user_index) {
108   LoginUserInfo result = user;
109   result.basic_user_info.type = type;
110 
111   bool is_public_account = type == user_manager::USER_TYPE_PUBLIC_ACCOUNT;
112   // Set debug user names and email. Useful for the stub user, which does not
113   // have a name  and email set.
114   result.basic_user_info.display_name =
115       is_public_account
116           ? kDebugPublicAccountNames[user_index %
117                                      base::size(kDebugPublicAccountNames)]
118           : kDebugUserNames[user_index % base::size(kDebugUserNames)];
119   result.basic_user_info.display_email =
120       result.basic_user_info.account_id.GetUserEmail();
121 
122   if (is_public_account) {
123     result.public_account_info.emplace();
124     result.public_account_info->device_enterprise_manager =
125         kDebugEnterpriseDomain;
126     result.public_account_info->default_locale = kDebugDefaultLocaleCode;
127     result.public_account_info->show_expanded_view = true;
128 
129     std::vector<LocaleItem> locales;
130     LocaleItem locale_item;
131     locale_item.language_code = kDebugDefaultLocaleCode;
132     locale_item.title = kDebugDefaultLocaleTitle;
133     result.public_account_info->available_locales.push_back(
134         std::move(locale_item));
135 
136     // Request keyboard layouts for the default locale.
137     Shell::Get()
138         ->login_screen_controller()
139         ->RequestPublicSessionKeyboardLayouts(result.basic_user_info.account_id,
140                                               kDebugDefaultLocaleCode);
141   } else {
142     result.public_account_info.reset();
143   }
144 
145   return result;
146 }
147 
148 }  // namespace
149 
150 // Applies a series of user-defined transformations to a
151 // |LoginDataDispatcher| instance; this is used for debugging and
152 // development. The debug overlay uses this class to change what data is exposed
153 // to the UI.
154 class LockDebugView::DebugDataDispatcherTransformer
155     : public LoginDataDispatcher::Observer {
156  public:
DebugDataDispatcherTransformer(mojom::TrayActionState initial_lock_screen_note_state,LoginDataDispatcher * dispatcher,const base::RepeatingClosure & on_users_received,LockDebugView * lock_debug_view)157   DebugDataDispatcherTransformer(
158       mojom::TrayActionState initial_lock_screen_note_state,
159       LoginDataDispatcher* dispatcher,
160       const base::RepeatingClosure& on_users_received,
161       LockDebugView* lock_debug_view)
162       : root_dispatcher_(dispatcher),
163         lock_screen_note_state_(initial_lock_screen_note_state),
164         on_users_received_(on_users_received),
165         lock_debug_view_(lock_debug_view) {
166     root_dispatcher_->AddObserver(this);
167   }
~DebugDataDispatcherTransformer()168   ~DebugDataDispatcherTransformer() override {
169     root_dispatcher_->RemoveObserver(this);
170   }
171 
debug_dispatcher()172   LoginDataDispatcher* debug_dispatcher() { return &debug_dispatcher_; }
173 
174   // Changes the number of displayed users to |count|.
SetUserCount(int count)175   void SetUserCount(int count) { NotifyUsers(BuildUserList(count)); }
176 
177   // Create user list.
BuildUserList(int count)178   std::vector<LoginUserInfo> BuildUserList(int count) {
179     DCHECK(!root_users_.empty());
180 
181     count = std::max(count, 0);
182 
183     // Trim any extra debug users.
184     if (debug_users_.size() > size_t{count})
185       debug_users_.erase(debug_users_.begin() + count, debug_users_.end());
186 
187     // Build |users|, add any new users to |debug_users|.
188     std::vector<LoginUserInfo> users;
189     for (size_t i = 0; i < size_t{count}; ++i) {
190       users.push_back(root_users_[i % root_users_.size()]);
191       if (i >= root_users_.size()) {
192         users[i].basic_user_info.account_id = AccountId::FromUserEmailGaiaId(
193             users[i].basic_user_info.account_id.GetUserEmail() +
194                 base::NumberToString(i),
195             users[i].basic_user_info.account_id.GetGaiaId() +
196                 base::NumberToString(i));
197       }
198 
199       // Setup user data based on the user type in debug_users_.
200       user_manager::UserType type = (i < debug_users_.size())
201                                         ? debug_users_[i].type
202                                         : users[i].basic_user_info.type;
203       users[i] = PopulateUserData(users[i], type, i);
204 
205       if (i >= debug_users_.size())
206         debug_users_.push_back(UserMetadata(users[i].basic_user_info));
207     }
208 
209     return users;
210   }
211 
NotifyUsers(const std::vector<LoginUserInfo> & users)212   void NotifyUsers(const std::vector<LoginUserInfo>& users) {
213     // User notification resets PIN state.
214     for (UserMetadata& user : debug_users_)
215       user.enable_pin = false;
216 
217     debug_dispatcher_.SetUserList(users);
218   }
219 
GetUserCount() const220   int GetUserCount() const { return debug_users_.size(); }
221 
GetDisplayNameForUserIndex(size_t user_index)222   base::string16 GetDisplayNameForUserIndex(size_t user_index) {
223     DCHECK(user_index >= 0 && user_index < debug_users_.size());
224     return base::UTF8ToUTF16(debug_users_[user_index].display_name);
225   }
226 
GetAccountIdForUserIndex(size_t user_index)227   const AccountId& GetAccountIdForUserIndex(size_t user_index) {
228     DCHECK(user_index >= 0 && user_index < debug_users_.size());
229     UserMetadata* debug_user = &debug_users_[user_index];
230     return debug_user->account_id;
231   }
232 
233   // Activates or deactivates PIN for the user at |user_index|.
TogglePinStateForUserIndex(size_t user_index)234   void TogglePinStateForUserIndex(size_t user_index) {
235     DCHECK(user_index >= 0 && user_index < debug_users_.size());
236     UserMetadata* debug_user = &debug_users_[user_index];
237     debug_user->enable_pin = !debug_user->enable_pin;
238     debug_dispatcher_.SetPinEnabledForUser(debug_user->account_id,
239                                            debug_user->enable_pin);
240   }
241 
242   // Activates or deactivates challenge response for the user at
243   // |user_index|.
ToggleChallengeResponseStateForUserIndex(size_t user_index)244   void ToggleChallengeResponseStateForUserIndex(size_t user_index) {
245     DCHECK(user_index < debug_users_.size());
246     UserMetadata* debug_user = &debug_users_[user_index];
247     debug_user->enable_challenge_response =
248         !debug_user->enable_challenge_response;
249     debug_dispatcher_.SetChallengeResponseAuthEnabledForUser(
250         debug_user->account_id, debug_user->enable_challenge_response);
251   }
252 
253   // Activates or deactivates tap unlock for the user at |user_index|.
ToggleTapStateForUserIndex(size_t user_index)254   void ToggleTapStateForUserIndex(size_t user_index) {
255     DCHECK(user_index >= 0 && user_index < debug_users_.size());
256     UserMetadata* debug_user = &debug_users_[user_index];
257     debug_user->enable_tap_to_unlock = !debug_user->enable_tap_to_unlock;
258     debug_dispatcher_.SetTapToUnlockEnabledForUser(
259         debug_user->account_id, debug_user->enable_tap_to_unlock);
260   }
261 
262   // Enables click to auth for the user at |user_index|.
CycleEasyUnlockForUserIndex(size_t user_index)263   void CycleEasyUnlockForUserIndex(size_t user_index) {
264     DCHECK(user_index >= 0 && user_index < debug_users_.size());
265     UserMetadata* debug_user = &debug_users_[user_index];
266 
267     // EasyUnlockIconId state transition.
268     auto get_next_id = [](EasyUnlockIconId id) {
269       switch (id) {
270         case EasyUnlockIconId::NONE:
271           return EasyUnlockIconId::SPINNER;
272         case EasyUnlockIconId::SPINNER:
273           return EasyUnlockIconId::LOCKED;
274         case EasyUnlockIconId::LOCKED:
275           return EasyUnlockIconId::LOCKED_TO_BE_ACTIVATED;
276         case EasyUnlockIconId::LOCKED_TO_BE_ACTIVATED:
277           return EasyUnlockIconId::LOCKED_WITH_PROXIMITY_HINT;
278         case EasyUnlockIconId::LOCKED_WITH_PROXIMITY_HINT:
279           return EasyUnlockIconId::HARDLOCKED;
280         case EasyUnlockIconId::HARDLOCKED:
281           return EasyUnlockIconId::UNLOCKED;
282         case EasyUnlockIconId::UNLOCKED:
283           return EasyUnlockIconId::NONE;
284       }
285       return EasyUnlockIconId::NONE;
286     };
287     debug_user->easy_unlock_id = get_next_id(debug_user->easy_unlock_id);
288 
289     // Enable/disable click to unlock.
290     debug_user->enable_tap_to_unlock =
291         debug_user->easy_unlock_id == EasyUnlockIconId::UNLOCKED;
292 
293     // Prepare icon that we will show.
294     EasyUnlockIconOptions icon;
295     icon.icon = debug_user->easy_unlock_id;
296     if (icon.icon == EasyUnlockIconId::SPINNER) {
297       icon.aria_label = base::ASCIIToUTF16("Icon is spinning");
298     } else if (icon.icon == EasyUnlockIconId::LOCKED ||
299                icon.icon == EasyUnlockIconId::LOCKED_TO_BE_ACTIVATED) {
300       icon.autoshow_tooltip = true;
301       icon.tooltip = base::ASCIIToUTF16(
302           "This is a long message to trigger overflow. This should show up "
303           "automatically. icon_id=" +
304           base::NumberToString(static_cast<int>(icon.icon)));
305     } else {
306       icon.tooltip =
307           base::ASCIIToUTF16("This should not show up automatically.");
308     }
309 
310     // Show icon and enable/disable click to unlock.
311     debug_dispatcher_.ShowEasyUnlockIcon(debug_user->account_id, icon);
312     debug_dispatcher_.SetTapToUnlockEnabledForUser(
313         debug_user->account_id, debug_user->enable_tap_to_unlock);
314   }
315 
316   // Enables fingerprint auth for the user at |user_index|.
CycleFingerprintStateForUserIndex(size_t user_index)317   void CycleFingerprintStateForUserIndex(size_t user_index) {
318     DCHECK(user_index >= 0 && user_index < debug_users_.size());
319     UserMetadata* debug_user = &debug_users_[user_index];
320 
321     debug_user->fingerprint_state = static_cast<FingerprintState>(
322         (static_cast<int>(debug_user->fingerprint_state) + 1) %
323         (static_cast<int>(FingerprintState::kMaxValue) + 1));
324     debug_dispatcher_.SetFingerprintState(debug_user->account_id,
325                                           debug_user->fingerprint_state);
326   }
AuthenticateFingerprintForUserIndex(size_t user_index,bool success)327   void AuthenticateFingerprintForUserIndex(size_t user_index, bool success) {
328     DCHECK(user_index >= 0 && user_index < debug_users_.size());
329     UserMetadata* debug_user = &debug_users_[user_index];
330     debug_dispatcher_.NotifyFingerprintAuthResult(debug_user->account_id,
331                                                   success);
332   }
333 
334   // Force online sign-in for the user at |user_index|.
ForceOnlineSignInForUserIndex(size_t user_index)335   void ForceOnlineSignInForUserIndex(size_t user_index) {
336     DCHECK(user_index >= 0 && user_index < debug_users_.size());
337     debug_dispatcher_.ForceOnlineSignInForUser(
338         debug_users_[user_index].account_id);
339   }
340 
341   // Enables or disables user management for the user at |user_index|.
ToggleManagementForUserIndex(size_t user_index)342   void ToggleManagementForUserIndex(size_t user_index) {
343     DCHECK(user_index >= 0 && user_index < debug_users_.size());
344     lock_debug_view_->lock()->ToggleManagementForUserForDebug(
345         debug_users_[user_index].account_id);
346   }
347 
348   // Updates |auth_disabled_reason_| with the next enum value in a cyclic
349   // manner.
UpdateAuthDisabledReason()350   void UpdateAuthDisabledReason() {
351     switch (auth_disabled_reason_) {
352       case AuthDisabledReason::kTimeLimitOverride:
353         auth_disabled_reason_ = AuthDisabledReason::kTimeUsageLimit;
354         break;
355       case AuthDisabledReason::kTimeUsageLimit:
356         auth_disabled_reason_ = AuthDisabledReason::kTimeWindowLimit;
357         break;
358       case AuthDisabledReason::kTimeWindowLimit:
359         auth_disabled_reason_ = AuthDisabledReason::kTimeLimitOverride;
360         break;
361     }
362   }
363 
364   // Toggle the unlock allowed state for the user at |user_index|.
ToggleAuthEnabledForUserIndex(size_t user_index)365   void ToggleAuthEnabledForUserIndex(size_t user_index) {
366     DCHECK(user_index >= 0 && user_index < debug_users_.size());
367     UserMetadata& user = debug_users_[user_index];
368     user.enable_auth = !user.enable_auth;
369     if (user.enable_auth) {
370       debug_dispatcher_.EnableAuthForUser(user.account_id);
371     } else {
372       debug_dispatcher_.DisableAuthForUser(
373           user.account_id,
374           AuthDisabledData(auth_disabled_reason_,
375                            base::Time::Now() +
376                                base::TimeDelta::FromHours(user_index) +
377                                base::TimeDelta::FromHours(8),
378                            base::TimeDelta::FromMinutes(15),
379                            true /*bool disable_lock_screen_media*/));
380       UpdateAuthDisabledReason();
381     }
382   }
383 
384   // Convert user type to regular user or public account for the user at
385   // |user_index|.
TogglePublicAccountForUserIndex(size_t user_index)386   void TogglePublicAccountForUserIndex(size_t user_index) {
387     DCHECK(user_index >= 0 && user_index < debug_users_.size());
388     UserMetadata& user = debug_users_[user_index];
389     // Swap the type between regular and public account.
390     user.type = user.type == user_manager::USER_TYPE_REGULAR
391                     ? user_manager::USER_TYPE_PUBLIC_ACCOUNT
392                     : user_manager::USER_TYPE_REGULAR;
393 
394     std::vector<LoginUserInfo> users = BuildUserList(debug_users_.size());
395     // Update display name and email in debug users.
396     debug_users_[user_index] = UserMetadata(users[user_index].basic_user_info);
397     NotifyUsers(std::move(users));
398   }
399 
ToggleLockScreenNoteButton()400   void ToggleLockScreenNoteButton() {
401     if (lock_screen_note_state_ == mojom::TrayActionState::kAvailable) {
402       lock_screen_note_state_ = mojom::TrayActionState::kNotAvailable;
403     } else {
404       lock_screen_note_state_ = mojom::TrayActionState::kAvailable;
405     }
406 
407     debug_dispatcher_.SetLockScreenNoteState(lock_screen_note_state_);
408   }
409 
AddKioskApp(ShelfWidget * shelf_widget)410   void AddKioskApp(ShelfWidget* shelf_widget) {
411     KioskAppMenuEntry menu_item;
412     menu_item.app_id = kDebugKioskAppId;
413     menu_item.name = base::UTF8ToUTF16(kDebugKioskAppName);
414     kiosk_apps_.push_back(std::move(menu_item));
415     shelf_widget->login_shelf_view()->SetKioskApps(kiosk_apps_, {}, {});
416   }
417 
RemoveKioskApp(ShelfWidget * shelf_widget)418   void RemoveKioskApp(ShelfWidget* shelf_widget) {
419     if (kiosk_apps_.empty())
420       return;
421     kiosk_apps_.pop_back();
422     shelf_widget->login_shelf_view()->SetKioskApps(kiosk_apps_, {}, {});
423   }
424 
AddSystemInfo(const std::string & os_version,const std::string & enterprise_info,const std::string & bluetooth_name,bool adb_sideloading_enabled)425   void AddSystemInfo(const std::string& os_version,
426                      const std::string& enterprise_info,
427                      const std::string& bluetooth_name,
428                      bool adb_sideloading_enabled) {
429     debug_dispatcher_.SetSystemInfo(true /*show*/, false /*enforced*/,
430                                     os_version, enterprise_info, bluetooth_name,
431                                     adb_sideloading_enabled);
432   }
433 
UpdateWarningMessage(const base::string16 & message)434   void UpdateWarningMessage(const base::string16& message) {
435     debug_dispatcher_.UpdateWarningMessage(message);
436   }
437 
438   // LoginDataDispatcher::Observer:
OnUsersChanged(const std::vector<LoginUserInfo> & users)439   void OnUsersChanged(const std::vector<LoginUserInfo>& users) override {
440     // Update root_users_ to new source data.
441     root_users_.clear();
442     for (auto& user : users)
443       root_users_.push_back(user);
444 
445     // Rebuild debug users using new source data.
446     SetUserCount(root_users_.size());
447 
448     on_users_received_.Run();
449   }
OnPinEnabledForUserChanged(const AccountId & user,bool enabled)450   void OnPinEnabledForUserChanged(const AccountId& user,
451                                   bool enabled) override {
452     // Forward notification only if the user is currently being shown.
453     for (size_t i = 0u; i < debug_users_.size(); ++i) {
454       if (debug_users_[i].account_id == user) {
455         debug_users_[i].enable_pin = enabled;
456         debug_dispatcher_.SetPinEnabledForUser(user, enabled);
457         break;
458       }
459     }
460   }
OnTapToUnlockEnabledForUserChanged(const AccountId & user,bool enabled)461   void OnTapToUnlockEnabledForUserChanged(const AccountId& user,
462                                           bool enabled) override {
463     // Forward notification only if the user is currently being shown.
464     for (size_t i = 0u; i < debug_users_.size(); ++i) {
465       if (debug_users_[i].account_id == user) {
466         debug_users_[i].enable_tap_to_unlock = enabled;
467         debug_dispatcher_.SetTapToUnlockEnabledForUser(user, enabled);
468         break;
469       }
470     }
471   }
OnLockScreenNoteStateChanged(mojom::TrayActionState state)472   void OnLockScreenNoteStateChanged(mojom::TrayActionState state) override {
473     lock_screen_note_state_ = state;
474     debug_dispatcher_.SetLockScreenNoteState(state);
475   }
OnShowEasyUnlockIcon(const AccountId & user,const EasyUnlockIconOptions & icon)476   void OnShowEasyUnlockIcon(const AccountId& user,
477                             const EasyUnlockIconOptions& icon) override {
478     debug_dispatcher_.ShowEasyUnlockIcon(user, icon);
479   }
OnDetachableBasePairingStatusChanged(DetachableBasePairingStatus pairing_status)480   void OnDetachableBasePairingStatusChanged(
481       DetachableBasePairingStatus pairing_status) override {
482     debug_dispatcher_.SetDetachableBasePairingStatus(pairing_status);
483   }
484 
OnPublicSessionKeyboardLayoutsChanged(const AccountId & account_id,const std::string & locale,const std::vector<InputMethodItem> & keyboard_layouts)485   void OnPublicSessionKeyboardLayoutsChanged(
486       const AccountId& account_id,
487       const std::string& locale,
488       const std::vector<InputMethodItem>& keyboard_layouts) override {
489     debug_dispatcher_.SetPublicSessionKeyboardLayouts(account_id, locale,
490                                                       keyboard_layouts);
491   }
492 
OnPublicSessionShowFullManagementDisclosureChanged(bool show_full_management_disclosure)493   void OnPublicSessionShowFullManagementDisclosureChanged(
494       bool show_full_management_disclosure) override {
495     debug_dispatcher_.SetPublicSessionShowFullManagementDisclosure(
496         show_full_management_disclosure);
497   }
498 
499  private:
500   // The debug overlay UI takes ground-truth data from |root_dispatcher_|,
501   // applies a series of transformations to it, and exposes it to the UI via
502   // |debug_dispatcher_|.
503   LoginDataDispatcher* root_dispatcher_;  // Unowned.
504   LoginDataDispatcher debug_dispatcher_;
505 
506   // Original set of users from |root_dispatcher_|.
507   std::vector<LoginUserInfo> root_users_;
508 
509   // Metadata for users that the UI is displaying.
510   std::vector<UserMetadata> debug_users_;
511 
512   // The current lock screen note action state.
513   mojom::TrayActionState lock_screen_note_state_;
514 
515   // List of kiosk apps loaded.
516   std::vector<KioskAppMenuEntry> kiosk_apps_;
517 
518   // Called when a new user list has been received.
519   base::RepeatingClosure on_users_received_;
520 
521   // Called for testing functions not belonging to the login data dispatcher.
522   // In such a case, we want to bypass the event handling mechanism and do
523   // direct calls to the lock screen. We need either an instance of
524   // LockDebugView or LockContentsView in order to do so.
525   LockDebugView* const lock_debug_view_;
526 
527   // When auth is disabled, this property is used to define the reason, which
528   // customizes the UI accordingly.
529   AuthDisabledReason auth_disabled_reason_ =
530       AuthDisabledReason::kTimeLimitOverride;
531 
532   DISALLOW_COPY_AND_ASSIGN(DebugDataDispatcherTransformer);
533 };
534 
535 // In-memory wrapper around LoginDetachableBaseModel used by lock UI.
536 // It provides, methods to override the detachable base pairing state seen by
537 // the UI.
538 class LockDebugView::DebugLoginDetachableBaseModel
539     : public LoginDetachableBaseModel {
540  public:
541   static constexpr int kNullBaseId = -1;
542 
543   DebugLoginDetachableBaseModel() = default;
544   ~DebugLoginDetachableBaseModel() override = default;
545 
debugging_pairing_state() const546   bool debugging_pairing_state() const { return pairing_status_.has_value(); }
547 
548   // Calculates the pairing status to which the model should be changed when
549   // button for cycling detachable base pairing statuses is clicked.
NextPairingStatus() const550   DetachableBasePairingStatus NextPairingStatus() const {
551     if (!pairing_status_.has_value())
552       return DetachableBasePairingStatus::kNone;
553 
554     switch (*pairing_status_) {
555       case DetachableBasePairingStatus::kNone:
556         return DetachableBasePairingStatus::kAuthenticated;
557       case DetachableBasePairingStatus::kAuthenticated:
558         return DetachableBasePairingStatus::kNotAuthenticated;
559       case DetachableBasePairingStatus::kNotAuthenticated:
560         return DetachableBasePairingStatus::kInvalidDevice;
561       case DetachableBasePairingStatus::kInvalidDevice:
562         return DetachableBasePairingStatus::kNone;
563     }
564 
565     return DetachableBasePairingStatus::kNone;
566   }
567 
568   // Calculates the debugging detachable base ID that should become the paired
569   // base in the model when the button for cycling paired bases is clicked.
NextBaseId() const570   int NextBaseId() const {
571     return (base_id_ + 1) % base::size(kDebugDetachableBases);
572   }
573 
574   // Gets the descripting text for currently paired base, if any.
BaseButtonText() const575   std::string BaseButtonText() const {
576     if (base_id_ < 0)
577       return "No base";
578     return kDebugDetachableBases[base_id_];
579   }
580 
581   // Sets the model's pairing state - base pairing status, and the currently
582   // paired base ID. ID should be an index in |kDebugDetachableBases| array, and
583   // it should be set if pairing status is kAuthenticated. The base ID is
584   // ignored if pairing state is different than kAuthenticated.
SetPairingState(DetachableBasePairingStatus pairing_status,int base_id)585   void SetPairingState(DetachableBasePairingStatus pairing_status,
586                        int base_id) {
587     pairing_status_ = pairing_status;
588     if (pairing_status == DetachableBasePairingStatus::kAuthenticated) {
589       CHECK_GE(base_id, 0);
590       CHECK_LT(base_id, static_cast<int>(base::size(kDebugDetachableBases)));
591       base_id_ = base_id;
592     } else {
593       base_id_ = kNullBaseId;
594     }
595 
596     Shell::Get()
597         ->login_screen_controller()
598         ->data_dispatcher()
599         ->SetDetachableBasePairingStatus(pairing_status);
600   }
601 
602   // Marks the paired base (as seen by the model) as the user's last used base.
603   // No-op if the current pairing status is different than kAuthenticated.
SetBaseLastUsedForUser(const AccountId & account_id)604   void SetBaseLastUsedForUser(const AccountId& account_id) {
605     if (GetPairingStatus() != DetachableBasePairingStatus::kAuthenticated)
606       return;
607     DCHECK_GE(base_id_, 0);
608 
609     last_used_bases_[account_id] = base_id_;
610     Shell::Get()
611         ->login_screen_controller()
612         ->data_dispatcher()
613         ->SetDetachableBasePairingStatus(*pairing_status_);
614   }
615 
616   // Clears all in-memory pairing state.
ClearDebugPairingState()617   void ClearDebugPairingState() {
618     pairing_status_ = base::nullopt;
619     base_id_ = kNullBaseId;
620     last_used_bases_.clear();
621 
622     Shell::Get()
623         ->login_screen_controller()
624         ->data_dispatcher()
625         ->SetDetachableBasePairingStatus(DetachableBasePairingStatus::kNone);
626   }
627 
628   // LoginDetachableBaseModel:
GetPairingStatus()629   DetachableBasePairingStatus GetPairingStatus() override {
630     if (!pairing_status_.has_value())
631       return DetachableBasePairingStatus::kNone;
632     return *pairing_status_;
633   }
PairedBaseMatchesLastUsedByUser(const UserInfo & user_info)634   bool PairedBaseMatchesLastUsedByUser(const UserInfo& user_info) override {
635     if (GetPairingStatus() != DetachableBasePairingStatus::kAuthenticated)
636       return false;
637 
638     if (last_used_bases_.count(user_info.account_id) == 0)
639       return true;
640     return last_used_bases_[user_info.account_id] == base_id_;
641   }
SetPairedBaseAsLastUsedByUser(const UserInfo & user_info)642   bool SetPairedBaseAsLastUsedByUser(const UserInfo& user_info) override {
643     if (GetPairingStatus() != DetachableBasePairingStatus::kAuthenticated)
644       return false;
645 
646     last_used_bases_[user_info.account_id] = base_id_;
647     return true;
648   }
649 
650  private:
651   // In-memory detachable base pairing state.
652   base::Optional<DetachableBasePairingStatus> pairing_status_;
653   int base_id_ = kNullBaseId;
654   // Maps user account to the last used detachable base ID (base ID being the
655   // base's index in kDebugDetachableBases array).
656   std::map<AccountId, int> last_used_bases_;
657 
658   DISALLOW_COPY_AND_ASSIGN(DebugLoginDetachableBaseModel);
659 };
660 
LockDebugView(mojom::TrayActionState initial_note_action_state,LockScreen::ScreenType screen_type)661 LockDebugView::LockDebugView(mojom::TrayActionState initial_note_action_state,
662                              LockScreen::ScreenType screen_type)
663     : debug_data_dispatcher_(std::make_unique<DebugDataDispatcherTransformer>(
664           initial_note_action_state,
665           Shell::Get()->login_screen_controller()->data_dispatcher(),
666           base::BindRepeating(
667               &LockDebugView::UpdatePerUserActionContainerAndLayout,
668               base::Unretained(this)),
669           this)),
670       next_auth_error_type_(AuthErrorType::kFirstUnlockFailed) {
671   SetLayoutManager(std::make_unique<views::BoxLayout>(
672       views::BoxLayout::Orientation::kHorizontal));
673 
674   auto debug_detachable_base_model =
675       std::make_unique<DebugLoginDetachableBaseModel>();
676   debug_detachable_base_model_ = debug_detachable_base_model.get();
677 
678   lock_ = new LockContentsView(initial_note_action_state, screen_type,
679                                debug_data_dispatcher_->debug_dispatcher(),
680                                std::move(debug_detachable_base_model));
681   AddChildView(lock_);
682 
683   container_ = new NonAccessibleView();
684   container_->SetLayoutManager(std::make_unique<views::BoxLayout>(
685       views::BoxLayout::Orientation::kVertical));
686   AddChildView(container_);
687 
688   auto* margin = new NonAccessibleView();
689   margin->SetPreferredSize(gfx::Size(10, 10));
690   container_->AddChildView(margin);
691 
692   global_action_view_container_ = new NonAccessibleView();
693   global_action_view_container_->SetLayoutManager(
694       std::make_unique<views::BoxLayout>(
695           views::BoxLayout::Orientation::kVertical));
696 
697   auto add_horizontal_container = [&]() {
698     auto* container = new NonAccessibleView();
699     container->SetLayoutManager(std::make_unique<views::BoxLayout>(
700         views::BoxLayout::Orientation::kHorizontal));
701     global_action_view_container_->AddChildView(container);
702     return container;
703   };
704 
705   auto* change_users_container = add_horizontal_container();
706   AddButton("Add user",
707             base::BindRepeating(&LockDebugView::AddOrRemoveUsersButtonPressed,
708                                 base::Unretained(this), 1),
709             change_users_container);
710   AddButton("Add 10 users",
711             base::BindRepeating(&LockDebugView::AddOrRemoveUsersButtonPressed,
712                                 base::Unretained(this), 10),
713             change_users_container);
714   AddButton("Remove user",
715             base::BindRepeating(&LockDebugView::AddOrRemoveUsersButtonPressed,
716                                 base::Unretained(this), -1),
717             change_users_container);
718 
719   auto* toggle_container = add_horizontal_container();
720   AddButton("Blur", base::BindRepeating([]() {
721               auto* const wallpaper_controller =
722                   Shell::Get()->wallpaper_controller();
723               wallpaper_controller->UpdateWallpaperBlurForLockState(
724                   !wallpaper_controller->IsWallpaperBlurredForLockState());
725             }),
726             toggle_container);
727   AddButton("Toggle note action",
728             base::BindRepeating(
729                 &DebugDataDispatcherTransformer::ToggleLockScreenNoteButton,
730                 base::Unretained(debug_data_dispatcher_.get())),
731             toggle_container);
732   AddButton("Toggle caps lock", base::BindRepeating([]() {
733               ImeControllerImpl* ime_controller =
734                   Shell::Get()->ime_controller();
735               ime_controller->SetCapsLockEnabled(
736                   !ime_controller->IsCapsLockEnabled());
737             }),
738             toggle_container);
739   global_action_add_system_info_ =
740       AddButton("Add system info",
741                 base::BindRepeating(&LockDebugView::AddSystemInfoButtonPressed,
742                                     base::Unretained(this)),
743                 toggle_container);
744   global_action_toggle_auth_ =
745       AddButton("Auth (allowed)",
746                 base::BindRepeating(&LockDebugView::ToggleAuthButtonPressed,
747                                     base::Unretained(this)),
748                 toggle_container);
749   AddButton("Cycle auth error",
750             base::BindRepeating(&LockDebugView::CycleAuthErrorMessage,
751                                 base::Unretained(this)),
752             toggle_container);
753   AddButton(
754       "Toggle warning banner",
755       base::BindRepeating(&LockDebugView::ToggleWarningBannerButtonPressed,
756                           base::Unretained(this)),
757       toggle_container);
758   AddButton("Show parent access",
759             base::BindRepeating(&LockContentsView::ShowParentAccessDialog,
760                                 base::Unretained(lock_)),
761             toggle_container);
762 
763   auto* kiosk_container = add_horizontal_container();
764   AddButton("Add kiosk app",
765             base::BindRepeating(&LockDebugView::AddKioskAppButtonPressed,
766                                 base::Unretained(this)),
767             kiosk_container);
768   AddButton("Remove kiosk app",
769             base::BindRepeating(&LockDebugView::RemoveKioskAppButtonPressed,
770                                 base::Unretained(this)),
771             kiosk_container);
772   AddButton("Show kiosk error",
773             base::BindRepeating(
774                 &LoginScreenController::ShowKioskAppError,
775                 base::Unretained(Shell::Get()->login_screen_controller()),
776                 "Test error message."),
777             kiosk_container);
778 
779   auto* managed_sessions_container = add_horizontal_container();
780   AddButton("Toggle managed session disclosure",
781             base::BindRepeating(
782                 &LockDebugView::ToggleManagedSessionDisclosureButtonPressed,
783                 base::Unretained(this)),
784             managed_sessions_container);
785 
786   global_action_detachable_base_group_ = add_horizontal_container();
787   UpdateDetachableBaseColumn();
788 
789   per_user_action_view_container_ = new NonAccessibleView();
790   per_user_action_view_container_->SetLayoutManager(
791       std::make_unique<views::BoxLayout>(
792           views::BoxLayout::Orientation::kVertical));
793   UpdatePerUserActionContainer();
794 
795   auto make_scroll = [](views::View* content,
796                         int height) -> std::unique_ptr<views::View> {
797     std::unique_ptr<views::ScrollView> scroll =
798         views::ScrollView::CreateScrollViewWithBorder();
799     scroll->SetPreferredSize(gfx::Size(600, height));
800     scroll->SetContents(base::WrapUnique(content));
801     scroll->SetBackgroundColor(base::nullopt);
802     scroll->SetVerticalScrollBar(
803         std::make_unique<views::OverlayScrollBar>(false));
804     scroll->SetHorizontalScrollBar(
805         std::make_unique<views::OverlayScrollBar>(true));
806     return scroll;
807   };
808   container_->AddChildView(make_scroll(global_action_view_container_, 110));
809   container_->AddChildView(make_scroll(per_user_action_view_container_, 100));
810 
811   Layout();
812 }
813 
~LockDebugView()814 LockDebugView::~LockDebugView() {
815   // Make sure debug_data_dispatcher_ lives longer than LockContentsView so
816   // pointer debug_dispatcher_ is always valid for LockContentsView.
817   delete lock_;
818 }
819 
Layout()820 void LockDebugView::Layout() {
821   global_action_view_container_->SizeToPreferredSize();
822   per_user_action_view_container_->SizeToPreferredSize();
823 
824   views::View::Layout();
825 
826   lock_->SetBoundsRect(GetLocalBounds());
827   container_->SetPosition(gfx::Point());
828   container_->SizeToPreferredSize();
829 }
830 
AddOrRemoveUsersButtonPressed(int delta)831 void LockDebugView::AddOrRemoveUsersButtonPressed(int delta) {
832   debug_data_dispatcher_->SetUserCount(
833       std::max(0, debug_data_dispatcher_->GetUserCount() + delta));
834   UpdatePerUserActionContainer();
835   Layout();
836 }
837 
AddSystemInfoButtonPressed()838 void LockDebugView::AddSystemInfoButtonPressed() {
839   ++num_system_info_clicks_;
840   if (num_system_info_clicks_ >= 7)
841     global_action_add_system_info_->SetEnabled(false);
842 
843   std::string os_version = num_system_info_clicks_ / 4 ? kDebugOsVersion : "";
844   std::string enterprise_info =
845       (num_system_info_clicks_ % 4) / 2 ? kDebugEnterpriseInfo : "";
846   std::string bluetooth_name =
847       num_system_info_clicks_ % 2 ? kDebugBluetoothName : "";
848   bool adb_sideloading_enabled = num_system_info_clicks_ % 3;
849   debug_data_dispatcher_->AddSystemInfo(
850       os_version, enterprise_info, bluetooth_name, adb_sideloading_enabled);
851 }
852 
ToggleAuthButtonPressed()853 void LockDebugView::ToggleAuthButtonPressed() {
854   auto get_next_auth_state = [](LoginScreenController::ForceFailAuth auth) {
855     switch (auth) {
856       case LoginScreenController::ForceFailAuth::kOff:
857         return LoginScreenController::ForceFailAuth::kImmediate;
858       case LoginScreenController::ForceFailAuth::kImmediate:
859         return LoginScreenController::ForceFailAuth::kDelayed;
860       case LoginScreenController::ForceFailAuth::kDelayed:
861         return LoginScreenController::ForceFailAuth::kOff;
862     }
863   };
864   auto get_auth_label = [](LoginScreenController::ForceFailAuth auth) {
865     switch (auth) {
866       case LoginScreenController::ForceFailAuth::kOff:
867         return "Auth (allowed)";
868       case LoginScreenController::ForceFailAuth::kImmediate:
869         return "Auth (immediate fail)";
870       case LoginScreenController::ForceFailAuth::kDelayed:
871         return "Auth (delayed fail)";
872     }
873   };
874   force_fail_auth_ = get_next_auth_state(force_fail_auth_);
875   global_action_toggle_auth_->SetText(
876       base::ASCIIToUTF16(get_auth_label(force_fail_auth_)));
877   Layout();
878   Shell::Get()
879       ->login_screen_controller()
880       ->set_force_fail_auth_for_debug_overlay(force_fail_auth_);
881 }
882 
AddKioskAppButtonPressed()883 void LockDebugView::AddKioskAppButtonPressed() {
884   debug_data_dispatcher_->AddKioskApp(
885       Shelf::ForWindow(GetWidget()->GetNativeWindow())->shelf_widget());
886 }
887 
RemoveKioskAppButtonPressed()888 void LockDebugView::RemoveKioskAppButtonPressed() {
889   debug_data_dispatcher_->RemoveKioskApp(
890       Shelf::ForWindow(GetWidget()->GetNativeWindow())->shelf_widget());
891 }
892 
ToggleDebugDetachableBaseButtonPressed()893 void LockDebugView::ToggleDebugDetachableBaseButtonPressed() {
894   if (debug_detachable_base_model_->debugging_pairing_state()) {
895     debug_detachable_base_model_->ClearDebugPairingState();
896     // In authenticated state, per user column has a button to mark the
897     // current base as last used for the user - it should get removed when the
898     // detachable base debugging gets disabled.
899     UpdatePerUserActionContainer();
900   } else {
901     debug_detachable_base_model_->SetPairingState(
902         DetachableBasePairingStatus::kNone,
903         DebugLoginDetachableBaseModel::kNullBaseId);
904   }
905   UpdateDetachableBaseColumn();
906   Layout();
907 }
908 
CycleDetachableBaseStatusButtonPressed()909 void LockDebugView::CycleDetachableBaseStatusButtonPressed() {
910   debug_detachable_base_model_->SetPairingState(
911       debug_detachable_base_model_->NextPairingStatus(),
912       debug_detachable_base_model_->NextBaseId());
913   UpdatePerUserActionContainer();
914   UpdateDetachableBaseColumn();
915   Layout();
916 }
917 
CycleDetachableBaseIdButtonPressed()918 void LockDebugView::CycleDetachableBaseIdButtonPressed() {
919   debug_detachable_base_model_->SetPairingState(
920       DetachableBasePairingStatus::kAuthenticated,
921       debug_detachable_base_model_->NextBaseId());
922   UpdateDetachableBaseColumn();
923   Layout();
924 }
925 
ToggleWarningBannerButtonPressed()926 void LockDebugView::ToggleWarningBannerButtonPressed() {
927   debug_data_dispatcher_->UpdateWarningMessage(
928       is_warning_banner_shown_
929           ? base::string16()
930           : base::ASCIIToUTF16("A critical update is ready to install. Sign "
931                                "in to get started."));
932   is_warning_banner_shown_ = !is_warning_banner_shown_;
933 }
934 
ToggleManagedSessionDisclosureButtonPressed()935 void LockDebugView::ToggleManagedSessionDisclosureButtonPressed() {
936   is_managed_session_disclosure_shown_ = !is_managed_session_disclosure_shown_;
937   debug_data_dispatcher_->OnPublicSessionShowFullManagementDisclosureChanged(
938       is_managed_session_disclosure_shown_);
939 }
940 
UseDetachableBaseButtonPressed(int index)941 void LockDebugView::UseDetachableBaseButtonPressed(int index) {
942   debug_detachable_base_model_->SetBaseLastUsedForUser(
943       debug_data_dispatcher_->GetAccountIdForUserIndex(index));
944 }
945 
TogglePublicAccountButtonPressed(int index)946 void LockDebugView::TogglePublicAccountButtonPressed(int index) {
947   debug_data_dispatcher_->TogglePublicAccountForUserIndex(index);
948   UpdatePerUserActionContainer();
949   Layout();
950 }
951 
CycleAuthErrorMessage()952 void LockDebugView::CycleAuthErrorMessage() {
953   switch (next_auth_error_type_) {
954     case AuthErrorType::kFirstUnlockFailed:
955       next_auth_error_type_ = AuthErrorType::kFirstUnlockFailedCapsLockOn;
956       Shell::Get()->ime_controller()->UpdateCapsLockState(
957           false /*caps_enabled*/);
958       debug_detachable_base_model_->SetPairingState(
959           DetachableBasePairingStatus::kNone,
960           DebugLoginDetachableBaseModel::kNullBaseId);
961       lock_->ShowAuthErrorMessageForDebug(1 /*unlock_attempt*/);
962       return;
963     case AuthErrorType::kFirstUnlockFailedCapsLockOn:
964       next_auth_error_type_ = AuthErrorType::kSecondUnlockFailed;
965       Shell::Get()->ime_controller()->UpdateCapsLockState(
966           true /*caps_enabled*/);
967       lock_->ShowAuthErrorMessageForDebug(1 /*unlock_attempt*/);
968       return;
969     case AuthErrorType::kSecondUnlockFailed:
970       next_auth_error_type_ = AuthErrorType::kSecondUnlockFailedCapsLockOn;
971       Shell::Get()->ime_controller()->UpdateCapsLockState(
972           false /*caps_enabled*/);
973       lock_->ShowAuthErrorMessageForDebug(2 /*unlock_attempt*/);
974       return;
975     case AuthErrorType::kSecondUnlockFailedCapsLockOn:
976       next_auth_error_type_ = AuthErrorType::kDetachableBaseFailed;
977       Shell::Get()->ime_controller()->UpdateCapsLockState(
978           true /*caps_enabled*/);
979       lock_->ShowAuthErrorMessageForDebug(2 /*unlock_attempt*/);
980       return;
981     case AuthErrorType::kDetachableBaseFailed:
982       next_auth_error_type_ = AuthErrorType::kFirstUnlockFailed;
983       debug_detachable_base_model_->SetPairingState(
984           DetachableBasePairingStatus::kNotAuthenticated,
985           DebugLoginDetachableBaseModel::kNullBaseId);
986       return;
987     default:
988       NOTREACHED();
989   }
990 }
991 
UpdatePerUserActionContainer()992 void LockDebugView::UpdatePerUserActionContainer() {
993   per_user_action_view_container_->RemoveAllChildViews(
994       true /*delete_children*/);
995 
996   int num_users = debug_data_dispatcher_->GetUserCount();
997   for (int i = 0; i < num_users; ++i) {
998     auto* row = new NonAccessibleView();
999     row->SetLayoutManager(std::make_unique<views::BoxLayout>(
1000         views::BoxLayout::Orientation::kHorizontal));
1001 
1002     auto* name = new views::Label();
1003     name->SetText(debug_data_dispatcher_->GetDisplayNameForUserIndex(i));
1004     name->SetSubpixelRenderingEnabled(false);
1005     name->SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor(
1006         AshColorProvider::ContentLayerType::kTextColorPrimary));
1007     name->SetAutoColorReadabilityEnabled(false);
1008     row->AddChildView(name);
1009 
1010     AddButton("Toggle PIN",
1011               base::BindRepeating(
1012                   &DebugDataDispatcherTransformer::TogglePinStateForUserIndex,
1013                   base::Unretained(debug_data_dispatcher_.get()), i),
1014               row);
1015     AddButton(
1016         "Toggle Smart card",
1017         base::BindRepeating(&DebugDataDispatcherTransformer::
1018                                 ToggleChallengeResponseStateForUserIndex,
1019                             base::Unretained(debug_data_dispatcher_.get()), i),
1020         row);
1021     AddButton("Toggle Tap",
1022               base::BindRepeating(
1023                   &DebugDataDispatcherTransformer::ToggleTapStateForUserIndex,
1024                   base::Unretained(debug_data_dispatcher_.get()), i),
1025               row);
1026     AddButton("Cycle easy unlock",
1027               base::BindRepeating(
1028                   &DebugDataDispatcherTransformer::CycleEasyUnlockForUserIndex,
1029                   base::Unretained(debug_data_dispatcher_.get()), i),
1030               row);
1031     AddButton(
1032         "Cycle fingerprint state",
1033         base::BindRepeating(
1034             &DebugDataDispatcherTransformer::CycleFingerprintStateForUserIndex,
1035             base::Unretained(debug_data_dispatcher_.get()), i),
1036         row);
1037     AddButton("Send fingerprint auth success",
1038               base::BindRepeating(
1039                   &DebugDataDispatcherTransformer::
1040                       AuthenticateFingerprintForUserIndex,
1041                   base::Unretained(debug_data_dispatcher_.get()), i, true),
1042               row);
1043     AddButton("Send fingerprint auth fail",
1044               base::BindRepeating(
1045                   &DebugDataDispatcherTransformer::
1046                       AuthenticateFingerprintForUserIndex,
1047                   base::Unretained(debug_data_dispatcher_.get()), i, false),
1048               row);
1049     AddButton(
1050         "Force online sign-in",
1051         base::BindRepeating(
1052             &DebugDataDispatcherTransformer::ForceOnlineSignInForUserIndex,
1053             base::Unretained(debug_data_dispatcher_.get()), i),
1054         row);
1055     AddButton("Toggle user is managed",
1056               base::BindRepeating(
1057                   &DebugDataDispatcherTransformer::ToggleManagementForUserIndex,
1058                   base::Unretained(debug_data_dispatcher_.get()), i),
1059               row);
1060     AddButton(
1061         "Toggle auth enabled",
1062         base::BindRepeating(
1063             &DebugDataDispatcherTransformer::ToggleAuthEnabledForUserIndex,
1064             base::Unretained(debug_data_dispatcher_.get()), i),
1065         row);
1066 
1067     if (debug_detachable_base_model_->debugging_pairing_state() &&
1068         debug_detachable_base_model_->GetPairingStatus() ==
1069             DetachableBasePairingStatus::kAuthenticated) {
1070       AddButton(
1071           "Set base used",
1072           base::BindRepeating(&LockDebugView::UseDetachableBaseButtonPressed,
1073                               base::Unretained(this), i),
1074           row);
1075     }
1076 
1077     AddButton(
1078         "Toggle Public Account",
1079         base::BindRepeating(&LockDebugView::TogglePublicAccountButtonPressed,
1080                             base::Unretained(this), i),
1081         row)
1082         ->set_tag(i);
1083 
1084     per_user_action_view_container_->AddChildView(row);
1085   }
1086 }
1087 
UpdatePerUserActionContainerAndLayout()1088 void LockDebugView::UpdatePerUserActionContainerAndLayout() {
1089   UpdatePerUserActionContainer();
1090   Layout();
1091 }
1092 
UpdateDetachableBaseColumn()1093 void LockDebugView::UpdateDetachableBaseColumn() {
1094   global_action_detachable_base_group_->RemoveAllChildViews(
1095       true /*delete_children*/);
1096 
1097   AddButton("Debug detachable base",
1098             base::BindRepeating(
1099                 &LockDebugView::ToggleDebugDetachableBaseButtonPressed,
1100                 base::Unretained(this)),
1101             global_action_detachable_base_group_);
1102   if (!debug_detachable_base_model_->debugging_pairing_state())
1103     return;
1104 
1105   const std::string kPairingStatusText =
1106       "Pairing status: " +
1107       DetachableBasePairingStatusToString(
1108           debug_detachable_base_model_->GetPairingStatus());
1109   AddButton(kPairingStatusText,
1110             base::BindRepeating(
1111                 &LockDebugView::CycleDetachableBaseStatusButtonPressed,
1112                 base::Unretained(this)),
1113             global_action_detachable_base_group_);
1114 
1115   views::LabelButton* cycle_detachable_base_id = AddButton(
1116       debug_detachable_base_model_->BaseButtonText(),
1117       base::BindRepeating(&LockDebugView::CycleDetachableBaseIdButtonPressed,
1118                           base::Unretained(this)),
1119       global_action_detachable_base_group_);
1120   bool base_authenticated = debug_detachable_base_model_->GetPairingStatus() ==
1121                             DetachableBasePairingStatus::kAuthenticated;
1122   cycle_detachable_base_id->SetEnabled(base_authenticated);
1123 }
1124 
AddButton(const std::string & text,views::Button::PressedCallback callback,views::View * container)1125 views::LabelButton* LockDebugView::AddButton(
1126     const std::string& text,
1127     views::Button::PressedCallback callback,
1128     views::View* container) {
1129   // Creates a button with |text| that cannot be focused.
1130   auto button = std::make_unique<views::MdTextButton>(std::move(callback),
1131                                                       base::ASCIIToUTF16(text));
1132   button->SetFocusBehavior(views::View::FocusBehavior::NEVER);
1133 
1134   views::LabelButton* view = button.get();
1135   container->AddChildView(
1136       login_views_utils::WrapViewForPreferredSize(std::move(button)));
1137   return view;
1138 }
1139 
1140 }  // namespace ash
1141