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 #include "ash/login/ui/pin_request_view.h"
6
7 #include "ash/login/ui/arrow_button_view.h"
8 #include "ash/login/ui/login_pin_view.h"
9 #include "ash/login/ui/pin_request_widget.h"
10 #include "ash/public/cpp/shelf_config.h"
11 #include "ash/resources/vector_icons/vector_icons.h"
12 #include "ash/shell.h"
13 #include "ash/strings/grit/ash_strings.h"
14 #include "ash/style/ash_color_provider.h"
15 #include "ash/wallpaper/wallpaper_controller_impl.h"
16 #include "ui/accessibility/ax_enums.mojom.h"
17 #include "ui/accessibility/ax_node_data.h"
18 #include "ui/base/l10n/l10n_util.h"
19 #include "ui/gfx/canvas.h"
20 #include "ui/gfx/color_analysis.h"
21 #include "ui/gfx/color_utils.h"
22 #include "ui/gfx/paint_vector_icon.h"
23 #include "ui/views/background.h"
24 #include "ui/views/controls/button/label_button.h"
25 #include "ui/views/controls/focus_ring.h"
26 #include "ui/views/controls/label.h"
27 #include "ui/views/layout/box_layout.h"
28 #include "ui/views/layout/fill_layout.h"
29 #include "ui/views/vector_icons.h"
30
31 namespace ash {
32
33 namespace {
34
35 constexpr int kPinRequestViewWidthDp = 340;
36 constexpr int kPinKeyboardHeightDp = 224;
37 constexpr int kPinRequestViewRoundedCornerRadiusDp = 8;
38 constexpr int kPinRequestViewVerticalInsetDp = 8;
39 // Inset for all elements except the back button.
40 constexpr int kPinRequestViewMainHorizontalInsetDp = 36;
41 // Minimum inset (= back button inset).
42 constexpr int kPinRequestViewHorizontalInsetDp = 8;
43
44 constexpr int kCrossSizeDp = 20;
45 constexpr int kBackButtonSizeDp = 36;
46 constexpr int kLockIconSizeDp = 24;
47 constexpr int kBackButtonLockIconVerticalOverlapDp = 8;
48 constexpr int kHeaderHeightDp =
49 kBackButtonSizeDp + kLockIconSizeDp - kBackButtonLockIconVerticalOverlapDp;
50
51 constexpr int kIconToTitleDistanceDp = 24;
52 constexpr int kTitleToDescriptionDistanceDp = 8;
53 constexpr int kDescriptionToAccessCodeDistanceDp = 32;
54 constexpr int kAccessCodeToPinKeyboardDistanceDp = 16;
55 constexpr int kPinKeyboardToFooterDistanceDp = 16;
56 constexpr int kSubmitButtonBottomMarginDp = 28;
57
58 constexpr int kTitleFontSizeDeltaDp = 4;
59 constexpr int kTitleLineWidthDp = 268;
60 constexpr int kTitleLineHeightDp = 24;
61 constexpr int kTitleMaxLines = 4;
62 constexpr int kDescriptionFontSizeDeltaDp = 0;
63 constexpr int kDescriptionLineWidthDp = 268;
64 constexpr int kDescriptionTextLineHeightDp = 18;
65 constexpr int kDescriptionMaxLines = 4;
66
67 constexpr int kArrowButtonSizeDp = 48;
68
69 constexpr int kPinRequestViewMinimumHeightDp =
70 kPinRequestViewMainHorizontalInsetDp + kLockIconSizeDp +
71 kIconToTitleDistanceDp + kTitleToDescriptionDistanceDp +
72 kDescriptionToAccessCodeDistanceDp +
73 AccessCodeInput::kAccessCodeInputFieldHeightDp +
74 kAccessCodeToPinKeyboardDistanceDp + kPinKeyboardToFooterDistanceDp +
75 kArrowButtonSizeDp + kPinRequestViewMainHorizontalInsetDp; // = 266
76
77 constexpr int kAlpha70Percent = 178;
78 constexpr int kAlpha74Percent = 189;
79
80 constexpr SkColor kErrorColor = gfx::kGoogleRed300;
81
IsTabletMode()82 bool IsTabletMode() {
83 return Shell::Get()->tablet_mode_controller()->InTabletMode();
84 }
85
86 } // namespace
87
88 PinRequest::PinRequest() = default;
89 PinRequest::PinRequest(PinRequest&&) = default;
90 PinRequest& PinRequest::operator=(PinRequest&&) = default;
91 PinRequest::~PinRequest() = default;
92
93 // Label button that displays focus ring.
94 class PinRequestView::FocusableLabelButton : public views::LabelButton {
95 public:
FocusableLabelButton(PressedCallback callback,const base::string16 & text)96 FocusableLabelButton(PressedCallback callback, const base::string16& text)
97 : views::LabelButton(std::move(callback), text) {
98 SetInstallFocusRingOnFocus(true);
99 focus_ring()->SetColor(ShelfConfig::Get()->shelf_focus_border_color());
100 SetFocusBehavior(FocusBehavior::ALWAYS);
101 }
102
103 FocusableLabelButton(const FocusableLabelButton&) = delete;
104 FocusableLabelButton& operator=(const FocusableLabelButton&) = delete;
105 ~FocusableLabelButton() override = default;
106 };
107
TestApi(PinRequestView * view)108 PinRequestView::TestApi::TestApi(PinRequestView* view) : view_(view) {
109 DCHECK(view_);
110 }
111
112 PinRequestView::TestApi::~TestApi() = default;
113
back_button()114 LoginButton* PinRequestView::TestApi::back_button() {
115 return view_->back_button_;
116 }
117
title_label()118 views::Label* PinRequestView::TestApi::title_label() {
119 return view_->title_label_;
120 }
121
description_label()122 views::Label* PinRequestView::TestApi::description_label() {
123 return view_->description_label_;
124 }
125
access_code_view()126 views::View* PinRequestView::TestApi::access_code_view() {
127 return view_->access_code_view_;
128 }
129
help_button()130 views::LabelButton* PinRequestView::TestApi::help_button() {
131 return view_->help_button_;
132 }
133
submit_button()134 ArrowButtonView* PinRequestView::TestApi::submit_button() {
135 return view_->submit_button_;
136 }
137
pin_keyboard_view()138 LoginPinView* PinRequestView::TestApi::pin_keyboard_view() {
139 return view_->pin_keyboard_view_;
140 }
141
GetInputTextField(int index)142 views::Textfield* PinRequestView::TestApi::GetInputTextField(int index) {
143 return FixedLengthCodeInput::TestApi(
144 static_cast<FixedLengthCodeInput*>(view_->access_code_view_))
145 .GetInputTextField(index);
146 }
147
state() const148 PinRequestViewState PinRequestView::TestApi::state() const {
149 return view_->state_;
150 }
151
152 // static
GetChildUserDialogColor(bool using_blur)153 SkColor PinRequestView::GetChildUserDialogColor(bool using_blur) {
154 SkColor color = AshColorProvider::Get()->GetBaseLayerColor(
155 AshColorProvider::BaseLayerType::kOpaque);
156
157 SkColor extracted_color =
158 Shell::Get()->wallpaper_controller()->GetProminentColor(
159 color_utils::ColorProfile(color_utils::LumaRange::DARK,
160 color_utils::SaturationRange::MUTED));
161
162 if (extracted_color != kInvalidWallpaperColor &&
163 extracted_color != SK_ColorTRANSPARENT) {
164 color = color_utils::GetResultingPaintColor(
165 SkColorSetA(SK_ColorBLACK, kAlpha70Percent), extracted_color);
166 }
167
168 return using_blur ? SkColorSetA(color, kAlpha74Percent) : color;
169 }
170
171 // TODO(crbug.com/1061008): Make dialog look good on small screens with high
172 // zoom factor.
PinRequestView(PinRequest request,Delegate * delegate)173 PinRequestView::PinRequestView(PinRequest request, Delegate* delegate)
174 : delegate_(delegate),
175 on_pin_request_done_(std::move(request.on_pin_request_done)),
176 pin_keyboard_always_enabled_(request.pin_keyboard_always_enabled),
177 default_title_(request.title),
178 default_description_(request.description),
179 default_accessible_title_(request.accessible_title.empty()
180 ? request.title
181 : request.accessible_title) {
182 // MODAL_TYPE_SYSTEM is used to get a semi-transparent background behind the
183 // pin request view, when it is used directly on a widget. The overlay
184 // consumes all the inputs from the user, so that they can only interact with
185 // the pin request view while it is visible.
186 SetModalType(ui::MODAL_TYPE_SYSTEM);
187
188 // Main view contains all other views aligned vertically and centered.
189 auto layout = std::make_unique<views::BoxLayout>(
190 views::BoxLayout::Orientation::kVertical,
191 gfx::Insets(kPinRequestViewVerticalInsetDp,
192 kPinRequestViewHorizontalInsetDp),
193 0);
194 layout->set_main_axis_alignment(views::BoxLayout::MainAxisAlignment::kStart);
195 layout->set_cross_axis_alignment(
196 views::BoxLayout::CrossAxisAlignment::kCenter);
197 SetLayoutManager(std::move(layout));
198
199 SetPaintToLayer();
200 layer()->SetFillsBoundsOpaquely(false);
201 layer()->SetRoundedCornerRadius(
202 gfx::RoundedCornersF(kPinRequestViewRoundedCornerRadiusDp));
203 layer()->SetBackgroundBlur(ShelfConfig::Get()->shelf_blur_radius());
204
205 const int child_view_width =
206 kPinRequestViewWidthDp - 2 * kPinRequestViewMainHorizontalInsetDp;
207
208 // Header view which contains the back button that is aligned top right and
209 // the lock icon which is in the bottom center.
210 auto header_layout = std::make_unique<views::FillLayout>();
211 auto* header = new NonAccessibleView();
212 header->SetLayoutManager(std::move(header_layout));
213 AddChildView(header);
214 auto* header_spacer = new NonAccessibleView();
215 header_spacer->SetPreferredSize(gfx::Size(0, kHeaderHeightDp));
216 header->AddChildView(header_spacer);
217
218 // Main view icon.
219 auto* icon_view = new NonAccessibleView();
220 icon_view->SetPreferredSize(gfx::Size(0, kHeaderHeightDp));
221 auto icon_layout = std::make_unique<views::BoxLayout>(
222 views::BoxLayout::Orientation::kVertical, gfx::Insets(), 0);
223 icon_layout->set_main_axis_alignment(
224 views::BoxLayout::MainAxisAlignment::kEnd);
225 icon_layout->set_cross_axis_alignment(
226 views::BoxLayout::CrossAxisAlignment::kCenter);
227 icon_view->SetLayoutManager(std::move(icon_layout));
228 header->AddChildView(icon_view);
229
230 views::ImageView* icon = new views::ImageView();
231 icon->SetPreferredSize(gfx::Size(kLockIconSizeDp, kLockIconSizeDp));
232 icon->SetImage(gfx::CreateVectorIcon(
233 kPinRequestLockIcon,
234 AshColorProvider::Get()->GetContentLayerColor(
235 AshColorProvider::ContentLayerType::kIconColorPrimary)));
236 icon_view->AddChildView(icon);
237
238 // Back button. Note that it should be the last view added to |header| in
239 // order to be clickable.
240 auto* back_button_view = new NonAccessibleView();
241 back_button_view->SetPreferredSize(
242 gfx::Size(child_view_width + 2 * (kPinRequestViewMainHorizontalInsetDp -
243 kPinRequestViewHorizontalInsetDp),
244 kHeaderHeightDp));
245 auto back_button_layout = std::make_unique<views::BoxLayout>(
246 views::BoxLayout::Orientation::kHorizontal, gfx::Insets(), 0);
247 back_button_layout->set_main_axis_alignment(
248 views::BoxLayout::MainAxisAlignment::kEnd);
249 back_button_layout->set_cross_axis_alignment(
250 views::BoxLayout::CrossAxisAlignment::kStart);
251 back_button_view->SetLayoutManager(std::move(back_button_layout));
252 header->AddChildView(back_button_view);
253
254 back_button_ = new LoginButton(
255 base::BindRepeating(&PinRequestView::OnBack, base::Unretained(this)));
256 back_button_->SetPreferredSize(
257 gfx::Size(kBackButtonSizeDp, kBackButtonSizeDp));
258 back_button_->SetBackground(
259 views::CreateSolidBackground(SK_ColorTRANSPARENT));
260 back_button_->SetImage(
261 views::Button::STATE_NORMAL,
262 gfx::CreateVectorIcon(
263 views::kIcCloseIcon, kCrossSizeDp,
264 AshColorProvider::Get()->GetContentLayerColor(
265 AshColorProvider::ContentLayerType::kIconColorPrimary)));
266 back_button_->SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER);
267 back_button_->SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
268 back_button_->SetAccessibleName(
269 l10n_util::GetStringUTF16(IDS_ASH_LOGIN_BACK_BUTTON_ACCESSIBLE_NAME));
270 back_button_->SetFocusBehavior(FocusBehavior::ALWAYS);
271 back_button_view->AddChildView(back_button_);
272
273 auto add_spacer = [&](int height) {
274 auto* spacer = new NonAccessibleView();
275 spacer->SetPreferredSize(gfx::Size(0, height));
276 AddChildView(spacer);
277 };
278
279 add_spacer(kIconToTitleDistanceDp);
280
281 auto decorate_label = [](views::Label* label) {
282 label->SetSubpixelRenderingEnabled(false);
283 label->SetAutoColorReadabilityEnabled(false);
284 label->SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor(
285 AshColorProvider::ContentLayerType::kTextColorPrimary));
286 label->SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY);
287 };
288
289 // Main view title.
290 title_label_ = new views::Label(default_title_, views::style::CONTEXT_LABEL,
291 views::style::STYLE_PRIMARY);
292 title_label_->SetMultiLine(true);
293 title_label_->SetMaxLines(kTitleMaxLines);
294 title_label_->SizeToFit(kTitleLineWidthDp);
295 title_label_->SetLineHeight(kTitleLineHeightDp);
296 title_label_->SetFontList(gfx::FontList().Derive(
297 kTitleFontSizeDeltaDp, gfx::Font::NORMAL, gfx::Font::Weight::MEDIUM));
298 decorate_label(title_label_);
299 AddChildView(title_label_);
300
301 add_spacer(kTitleToDescriptionDistanceDp);
302
303 // Main view description.
304 description_label_ =
305 new views::Label(default_description_, views::style::CONTEXT_LABEL,
306 views::style::STYLE_PRIMARY);
307 description_label_->SetMultiLine(true);
308 description_label_->SetMaxLines(kDescriptionMaxLines);
309 description_label_->SizeToFit(kDescriptionLineWidthDp);
310 description_label_->SetLineHeight(kDescriptionTextLineHeightDp);
311 description_label_->SetFontList(
312 gfx::FontList().Derive(kDescriptionFontSizeDeltaDp, gfx::Font::NORMAL,
313 gfx::Font::Weight::NORMAL));
314 decorate_label(description_label_);
315 AddChildView(description_label_);
316
317 add_spacer(kDescriptionToAccessCodeDistanceDp);
318
319 LoginPalette palette = CreateDefaultLoginPalette();
320
321 // Access code input view.
322 if (request.pin_length.has_value()) {
323 CHECK_GT(request.pin_length.value(), 0);
324 access_code_view_ = AddChildView(std::make_unique<FixedLengthCodeInput>(
325 request.pin_length.value(),
326 base::BindRepeating(&PinRequestView::OnInputChange,
327 base::Unretained(this)),
328 base::BindRepeating(&PinRequestView::SubmitCode,
329 base::Unretained(this)),
330 base::BindRepeating(&PinRequestView::OnBack, base::Unretained(this)),
331 request.obscure_pin, palette.pin_input_text_color));
332 access_code_view_->SetFocusBehavior(FocusBehavior::ALWAYS);
333 } else {
334 auto flex_code_input = std::make_unique<FlexCodeInput>(
335 base::BindRepeating(&PinRequestView::OnInputChange,
336 base::Unretained(this), false),
337 base::BindRepeating(&PinRequestView::SubmitCode,
338 base::Unretained(this)),
339 base::BindRepeating(&PinRequestView::OnBack, base::Unretained(this)),
340 request.obscure_pin, palette.pin_input_text_color);
341 flex_code_input->SetAccessibleName(default_accessible_title_);
342 access_code_view_ = AddChildView(std::move(flex_code_input));
343 }
344
345 add_spacer(kAccessCodeToPinKeyboardDistanceDp);
346
347 // Pin keyboard. Note that the keyboard's own submit button is disabled via
348 // passing a null |on_submit| callback.
349 pin_keyboard_view_ = new LoginPinView(
350 LoginPinView::Style::kAlphanumeric, CreateDefaultLoginPalette(),
351 base::BindRepeating(&AccessCodeInput::InsertDigit,
352 base::Unretained(access_code_view_)),
353 base::BindRepeating(&AccessCodeInput::Backspace,
354 base::Unretained(access_code_view_)),
355 /*on_submit=*/LoginPinView::OnPinSubmit());
356 // Backspace key is always enabled and |access_code_| field handles it.
357 pin_keyboard_view_->OnPasswordTextChanged(false);
358 AddChildView(pin_keyboard_view_);
359
360 add_spacer(kPinKeyboardToFooterDistanceDp);
361
362 // Footer view contains help text button aligned to its start, submit
363 // button aligned to its end and spacer view in between.
364 auto* footer = new NonAccessibleView();
365 footer->SetPreferredSize(gfx::Size(child_view_width, kArrowButtonSizeDp));
366 auto* bottom_layout =
367 footer->SetLayoutManager(std::make_unique<views::BoxLayout>(
368 views::BoxLayout::Orientation::kHorizontal, gfx::Insets(), 0));
369 AddChildView(footer);
370
371 help_button_ = new FocusableLabelButton(
372 base::BindRepeating(
373 [](PinRequestView* view) {
374 view->delegate_->OnHelp(view->GetWidget()->GetNativeWindow());
375 },
376 this),
377 l10n_util::GetStringUTF16(IDS_ASH_LOGIN_PIN_REQUEST_HELP));
378 help_button_->SetPaintToLayer();
379 help_button_->layer()->SetFillsBoundsOpaquely(false);
380 help_button_->SetTextSubpixelRenderingEnabled(false);
381 help_button_->SetEnabledTextColors(
382 AshColorProvider::Get()->GetContentLayerColor(
383 AshColorProvider::ContentLayerType::kTextColorPrimary));
384 help_button_->SetVisible(request.help_button_enabled);
385 footer->AddChildView(help_button_);
386
387 auto* horizontal_spacer = new NonAccessibleView();
388 footer->AddChildView(horizontal_spacer);
389 bottom_layout->SetFlexForView(horizontal_spacer, 1);
390
391 submit_button_ = new ArrowButtonView(
392 base::BindRepeating(&PinRequestView::SubmitCode, base::Unretained(this)),
393 kArrowButtonSizeDp);
394 submit_button_->SetPreferredSize(
395 gfx::Size(kArrowButtonSizeDp, kArrowButtonSizeDp));
396 submit_button_->SetEnabled(false);
397 submit_button_->SetAccessibleName(
398 l10n_util::GetStringUTF16(IDS_ASH_LOGIN_SUBMIT_BUTTON_ACCESSIBLE_NAME));
399 submit_button_->SetFocusBehavior(FocusBehavior::ALWAYS);
400 footer->AddChildView(submit_button_);
401 add_spacer(kSubmitButtonBottomMarginDp);
402
403 pin_keyboard_view_->SetVisible(PinKeyboardVisible());
404
405 tablet_mode_observer_.Add(Shell::Get()->tablet_mode_controller());
406
407 SetPreferredSize(GetPinRequestViewSize());
408 }
409
410 PinRequestView::~PinRequestView() = default;
411
OnPaint(gfx::Canvas * canvas)412 void PinRequestView::OnPaint(gfx::Canvas* canvas) {
413 views::View::OnPaint(canvas);
414
415 cc::PaintFlags flags;
416 flags.setStyle(cc::PaintFlags::kFill_Style);
417 flags.setColor(GetChildUserDialogColor(true));
418 canvas->DrawRoundRect(GetContentsBounds(),
419 kPinRequestViewRoundedCornerRadiusDp, flags);
420 }
421
RequestFocus()422 void PinRequestView::RequestFocus() {
423 access_code_view_->RequestFocus();
424 }
425
CalculatePreferredSize() const426 gfx::Size PinRequestView::CalculatePreferredSize() const {
427 return GetPinRequestViewSize();
428 }
429
GetInitiallyFocusedView()430 views::View* PinRequestView::GetInitiallyFocusedView() {
431 return access_code_view_;
432 }
433
GetAccessibleWindowTitle() const434 base::string16 PinRequestView::GetAccessibleWindowTitle() const {
435 return default_accessible_title_;
436 }
437
OnTabletModeStarted()438 void PinRequestView::OnTabletModeStarted() {
439 if (!pin_keyboard_always_enabled_) {
440 VLOG(1) << "Showing PIN keyboard in PinRequestView";
441 pin_keyboard_view_->SetVisible(true);
442 // This will trigger ChildPreferredSizeChanged in parent view and Layout()
443 // in view. As the result whole hierarchy will go through re-layout.
444 UpdatePreferredSize();
445 }
446 }
447
OnTabletModeEnded()448 void PinRequestView::OnTabletModeEnded() {
449 if (!pin_keyboard_always_enabled_) {
450 VLOG(1) << "Hiding PIN keyboard in PinRequestView";
451 DCHECK(pin_keyboard_view_);
452 pin_keyboard_view_->SetVisible(false);
453 // This will trigger ChildPreferredSizeChanged in parent view and Layout()
454 // in view. As the result whole hierarchy will go through re-layout.
455 UpdatePreferredSize();
456 }
457 }
458
OnTabletControllerDestroyed()459 void PinRequestView::OnTabletControllerDestroyed() {
460 tablet_mode_observer_.RemoveAll();
461 }
462
SubmitCode()463 void PinRequestView::SubmitCode() {
464 base::Optional<std::string> code = access_code_view_->GetCode();
465 DCHECK(code.has_value());
466
467 SubmissionResult result = delegate_->OnPinSubmitted(*code);
468 switch (result) {
469 case SubmissionResult::kPinAccepted: {
470 std::move(on_pin_request_done_).Run(true /* success */);
471 return;
472 }
473 case SubmissionResult::kPinError: {
474 // Caller is expected to call UpdateState() to allow for customization of
475 // error messages.
476 return;
477 }
478 case SubmissionResult::kSubmitPending: {
479 // Waiting on validation result - do nothing for now.
480 return;
481 }
482 }
483 }
484
OnBack()485 void PinRequestView::OnBack() {
486 delegate_->OnBack();
487 if (PinRequestWidget::Get()) {
488 PinRequestWidget::Get()->Close(false /* success */);
489 }
490 }
491
UpdateState(PinRequestViewState state,const base::string16 & title,const base::string16 & description)492 void PinRequestView::UpdateState(PinRequestViewState state,
493 const base::string16& title,
494 const base::string16& description) {
495 state_ = state;
496 title_label_->SetText(title);
497 description_label_->SetText(description);
498 UpdatePreferredSize();
499 switch (state_) {
500 case PinRequestViewState::kNormal: {
501 const SkColor kTextColor = AshColorProvider::Get()->GetContentLayerColor(
502 AshColorProvider::ContentLayerType::kTextColorPrimary);
503 access_code_view_->SetInputColor(kTextColor);
504 title_label_->SetEnabledColor(kTextColor);
505 return;
506 }
507 case PinRequestViewState::kError: {
508 access_code_view_->SetInputColor(kErrorColor);
509 title_label_->SetEnabledColor(kErrorColor);
510 // Read out the error.
511 title_label_->NotifyAccessibilityEvent(ax::mojom::Event::kAlert, true);
512 return;
513 }
514 }
515 }
516
ClearInput()517 void PinRequestView::ClearInput() {
518 access_code_view_->ClearInput();
519 }
520
SetInputEnabled(bool input_enabled)521 void PinRequestView::SetInputEnabled(bool input_enabled) {
522 access_code_view_->SetInputEnabled(input_enabled);
523 }
524
UpdatePreferredSize()525 void PinRequestView::UpdatePreferredSize() {
526 SetPreferredSize(CalculatePreferredSize());
527 if (GetWidget())
528 GetWidget()->CenterWindow(GetPreferredSize());
529 }
530
FocusSubmitButton()531 void PinRequestView::FocusSubmitButton() {
532 submit_button_->RequestFocus();
533 }
534
OnInputChange(bool last_field_active,bool complete)535 void PinRequestView::OnInputChange(bool last_field_active, bool complete) {
536 if (state_ == PinRequestViewState::kError) {
537 UpdateState(PinRequestViewState::kNormal, default_title_,
538 default_description_);
539 }
540
541 submit_button_->SetEnabled(complete);
542
543 if (complete && last_field_active) {
544 if (auto_submit_enabled_) {
545 auto_submit_enabled_ = false;
546 SubmitCode();
547 return;
548 }
549
550 // Moving focus is delayed by using PostTask to allow for proper
551 // a11y announcements.
552 base::ThreadTaskRunnerHandle::Get()->PostTask(
553 FROM_HERE, base::BindOnce(&PinRequestView::FocusSubmitButton,
554 weak_ptr_factory_.GetWeakPtr()));
555 }
556 }
557
GetAccessibleNodeData(ui::AXNodeData * node_data)558 void PinRequestView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
559 views::View::GetAccessibleNodeData(node_data);
560 node_data->role = ax::mojom::Role::kDialog;
561 node_data->SetName(default_accessible_title_);
562 }
563
564 // If |pin_keyboard_always_enabled_| is not set, pin keyboard is only shown in
565 // tablet mode.
PinKeyboardVisible() const566 bool PinRequestView::PinKeyboardVisible() const {
567 return pin_keyboard_always_enabled_ || IsTabletMode();
568 }
569
GetPinRequestViewSize() const570 gfx::Size PinRequestView::GetPinRequestViewSize() const {
571 int height = kPinRequestViewMinimumHeightDp +
572 std::min(int{title_label_->GetRequiredLines()}, kTitleMaxLines) *
573 kTitleLineHeightDp +
574 std::min(int{description_label_->GetRequiredLines()},
575 kDescriptionMaxLines) *
576 kDescriptionTextLineHeightDp;
577 if (PinKeyboardVisible())
578 height += kPinKeyboardHeightDp;
579 return gfx::Size(kPinRequestViewWidthDp, height);
580 }
581
582 } // namespace ash
583