1 // Copyright 2019 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 #ifndef ASH_LOGIN_UI_PIN_REQUEST_VIEW_H_
6 #define ASH_LOGIN_UI_PIN_REQUEST_VIEW_H_
7 
8 #include <string>
9 
10 #include "ash/ash_export.h"
11 #include "ash/login/ui/access_code_input.h"
12 #include "ash/public/cpp/login_types.h"
13 #include "ash/public/cpp/tablet_mode_observer.h"
14 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
15 #include "ui/views/window/dialog_delegate.h"
16 
17 namespace views {
18 class Label;
19 class LabelButton;
20 class Textfield;
21 }  // namespace views
22 
23 namespace ash {
24 class ArrowButtonView;
25 class LoginButton;
26 class LoginPinView;
27 
28 // State of the PinRequestView.
29 enum class PinRequestViewState {
30   kNormal,
31   kError,
32 };
33 
34 struct ASH_EXPORT PinRequest {
35   PinRequest();
36   PinRequest(PinRequest&&);
37   PinRequest& operator=(PinRequest&&);
38   ~PinRequest();
39 
40   // Callback for PIN validations. It is called when the validation has finished
41   // and the view is closing.
42   // |success| indicates whether the validation was successful.
43   using OnPinRequestDone = base::OnceCallback<void(bool success)>;
44   OnPinRequestDone on_pin_request_done = base::NullCallback();
45 
46   // Whether the help button is displayed.
47   bool help_button_enabled = false;
48 
49   base::Optional<int> pin_length;
50 
51   // When |pin_keyboard_always_enabled| is set, the PIN keyboard is displayed at
52   // all times. Otherwise, it is only displayed when the device is in tablet
53   // mode.
54   bool pin_keyboard_always_enabled = false;
55 
56   // The pin widget is a modal and already contains a dimmer, however
57   // when another modal is the parent of the widget, the dimmer will be placed
58   // behind the two windows. |extra_dimmer| will create an extra dimmer between
59   // the two.
60   bool extra_dimmer = false;
61 
62   // Whether the entered PIN should be displayed clearly or only as bullets.
63   bool obscure_pin = true;
64 
65   // Strings for UI.
66   base::string16 title;
67   base::string16 description;
68   base::string16 accessible_title;
69 };
70 
71 // The view that allows for input of pins to authorize certain actions.
72 class ASH_EXPORT PinRequestView : public views::DialogDelegateView,
73                                   public TabletModeObserver {
74  public:
75   enum class SubmissionResult {
76     // Closes the UI and calls |on_pin_request_done_|.
77     kPinAccepted,
78     // PIN rejected - keeps the UI in its current state.
79     kPinError,
80     // Async waiting for result - keeps the UI in its current state.
81     kSubmitPending,
82   };
83 
84   class Delegate {
85    public:
86     virtual SubmissionResult OnPinSubmitted(const std::string& pin) = 0;
87     virtual void OnBack() = 0;
88     virtual void OnHelp(gfx::NativeWindow parent_window) = 0;
89 
90    protected:
91     virtual ~Delegate() = default;
92   };
93 
94   class ASH_EXPORT TestApi {
95    public:
96     explicit TestApi(PinRequestView* view);
97     ~TestApi();
98 
99     LoginButton* back_button();
100     views::Label* title_label();
101     views::Label* description_label();
102     views::View* access_code_view();
103     views::LabelButton* help_button();
104     ArrowButtonView* submit_button();
105     LoginPinView* pin_keyboard_view();
106 
107     views::Textfield* GetInputTextField(int index);
108     PinRequestViewState state() const;
109 
110    private:
111     PinRequestView* const view_;
112   };
113 
114   // Returns color used for dialog and UI elements specific for child user.
115   // |using_blur| should be true if the UI element is using background blur
116   // (color transparency depends on it).
117   static SkColor GetChildUserDialogColor(bool using_blur);
118 
119   // Creates pin request view that will enable the user to enter a pin.
120   // |request| is used to configure callbacks and UI details.
121   PinRequestView(PinRequest request, Delegate* delegate);
122   ~PinRequestView() override;
123 
124   // views::View:
125   void OnPaint(gfx::Canvas* canvas) override;
126   void RequestFocus() override;
127   gfx::Size CalculatePreferredSize() const override;
128   void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
129 
130   // views::DialogDelegateView:
131   views::View* GetInitiallyFocusedView() override;
132   base::string16 GetAccessibleWindowTitle() const override;
133 
134   // TabletModeObserver:
135   void OnTabletModeStarted() override;
136   void OnTabletModeEnded() override;
137   void OnTabletControllerDestroyed() override;
138 
139   // Sets whether the user can enter a PIN. Other buttons (back, submit etc.)
140   // are unaffected.
141   void SetInputEnabled(bool input_enabled);
142 
143   // Clears previously entered PIN from the PIN input field(s).
144   void ClearInput();
145 
146   // Updates state of the view.
147   void UpdateState(PinRequestViewState state,
148                    const base::string16& title,
149                    const base::string16& description);
150 
151  private:
152   class FocusableLabelButton;
153 
154   // Submits access code for validation.
155   void SubmitCode();
156 
157   // Closes the view.
158   void OnBack();
159 
160   // Updates view's preferred size.
161   void UpdatePreferredSize();
162 
163   // Moves focus to |submit_button_|.
164   void FocusSubmitButton();
165 
166   // Called when access code input changes. |complete| brings information
167   // whether current input code is complete. |last_field_active| contains
168   // information whether last input field is currently active.
169   void OnInputChange(bool last_field_active, bool complete);
170 
171   // Returns if the pin keyboard should be visible.
172   bool PinKeyboardVisible() const;
173 
174   // Size that depends on the pin keyboards visibility.
175   gfx::Size GetPinRequestViewSize() const;
176 
177   PinRequestViewState state_ = PinRequestViewState::kNormal;
178 
179   // Unowned pointer to the delegate. The delegate should outlive this instance.
180   Delegate* delegate_;
181 
182   // Callback to close the UI.
183   PinRequest::OnPinRequestDone on_pin_request_done_;
184 
185   // Auto submit code when the last input has been inserted.
186   bool auto_submit_enabled_ = true;
187 
188   // If false, |pin_keyboard_view| is only displayed in tablet mode.
189   bool pin_keyboard_always_enabled_ = true;
190 
191   // Strings as on view construction to enable restoring the original state.
192   base::string16 default_title_;
193   base::string16 default_description_;
194   base::string16 default_accessible_title_;
195 
196   views::Label* title_label_ = nullptr;
197   views::Label* description_label_ = nullptr;
198   AccessCodeInput* access_code_view_ = nullptr;
199   LoginPinView* pin_keyboard_view_ = nullptr;
200   LoginButton* back_button_ = nullptr;
201   FocusableLabelButton* help_button_ = nullptr;
202   ArrowButtonView* submit_button_ = nullptr;
203 
204   ScopedObserver<TabletModeController, TabletModeObserver>
205       tablet_mode_observer_{this};
206 
207   base::WeakPtrFactory<PinRequestView> weak_ptr_factory_{this};
208 
209   DISALLOW_COPY_AND_ASSIGN(PinRequestView);
210 };
211 
212 }  // namespace ash
213 
214 #endif  // ASH_LOGIN_UI_PIN_REQUEST_VIEW_H_
215