blob: bfee9686620882a59058edd4ba2681485cf19a61 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/in_session_auth/auth_dialog_contents_view.h"
#include <memory>
#include <utility>
#include "ash/login/resources/grit/login_resources.h"
#include "ash/login/ui/horizontal_image_sequence_animation_decoder.h"
#include "ash/login/ui/login_password_view.h"
#include "ash/login/ui/login_pin_input_view.h"
#include "ash/login/ui/login_pin_view.h"
#include "ash/login/ui/non_accessible_view.h"
#include "ash/login/ui/views_utils.h"
#include "ash/public/cpp/in_session_auth_dialog_controller.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/strings/grit/ash_strings.h"
#include "base/callback_helpers.h"
#include "base/strings/utf_string_conversions.h"
#include "base/timer/timer.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/views/background.h"
#include "ui/views/bubble/bubble_border.h"
#include "ui/views/controls/button/md_text_button.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/fill_layout.h"
namespace ash {
namespace {
constexpr int kContainerPreferredWidth = 340;
constexpr int kBorderTopDp = 36;
constexpr int kBorderLeftDp = 24;
constexpr int kBorderBottomDp = 20;
constexpr int kBorderRightDp = 24;
constexpr int kCornerRadius = 12;
constexpr int kTitleFontSizeDeltaDp = 4;
constexpr int kOriginNameLineHeight = 18;
constexpr int kSpacingAfterAvatar = 18;
constexpr int kSpacingAfterTitle = 8;
constexpr int kSpacingAfterOriginName = 32;
constexpr int kSpacingAfterInputField = 16;
constexpr int kAvatarSizeDp = 36;
constexpr int kFingerprintIconSizeDp = 28;
constexpr int kSpacingBetweenPinPadAndFingerprintIcon = 24;
constexpr int kSpacingBetweenFingerprintIconAndLabelDp = 15;
constexpr int kFingerprintViewWidthDp = 204;
constexpr int kFingerprintFailedAnimationNumFrames = 45;
constexpr base::TimeDelta kResetToDefaultIconDelay =
base::TimeDelta::FromMilliseconds(1300);
constexpr base::TimeDelta kResetToDefaultMessageDelay =
base::TimeDelta::FromMilliseconds(3000);
constexpr base::TimeDelta kFingerprintFailedAnimationDuration =
base::TimeDelta::FromMilliseconds(700);
// 38% opacity.
constexpr SkColor kDisabledFingerprintIconColor =
SkColorSetA(gfx::kGoogleGrey900, 97);
constexpr SkColor kBackgroundColor = SK_ColorWHITE;
constexpr SkColor kTextColorSecondary = gfx::kGoogleGrey700;
constexpr SkColor kTextColorPrimary = gfx::kGoogleGrey900;
constexpr SkColor kErrorColor = gfx::kGoogleRed600;
constexpr int kSpacingBeforeButtons = 32;
constexpr int kMaxPinAttempts = 5;
} // namespace
// Consists of fingerprint icon view and a label.
class AuthDialogContentsView::FingerprintView : public views::View {
public:
// Use a subclass that inherit views::Label so that GetAccessibleNodeData
// override is respected.
class FingerprintLabel : public views::Label {
public:
// views::View
void GetAccessibleNodeData(ui::AXNodeData* node_data) override {
node_data->role = ax::mojom::Role::kStaticText;
node_data->SetName(accessible_name_);
}
void SetAccessibleName(const base::string16& name) {
accessible_name_ = name;
NotifyAccessibilityEvent(ax::mojom::Event::kTextChanged,
true /*send_native_event*/);
}
private:
base::string16 accessible_name_;
};
FingerprintView() {
auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kVertical, gfx::Insets(),
kSpacingBetweenFingerprintIconAndLabelDp));
layout->set_main_axis_alignment(
views::BoxLayout::MainAxisAlignment::kCenter);
icon_ = AddChildView(std::make_unique<AnimatedRoundedImageView>(
gfx::Size(kFingerprintIconSizeDp, kFingerprintIconSizeDp),
0 /*corner_radius*/));
label_ = AddChildView(std::make_unique<FingerprintLabel>());
label_->SetSubpixelRenderingEnabled(false);
label_->SetAutoColorReadabilityEnabled(false);
label_->SetEnabledColor(kTextColorPrimary);
label_->SetMultiLine(true);
label_->SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY);
DisplayCurrentState();
}
FingerprintView(const FingerprintView&) = delete;
FingerprintView& operator=(const FingerprintView&) = delete;
~FingerprintView() override = default;
void SetState(FingerprintState state) {
if (state_ == state)
return;
state_ = state;
DisplayCurrentState();
}
void SetCanUsePin(bool can_use_pin) {
if (can_use_pin_ == can_use_pin)
return;
can_use_pin_ = can_use_pin;
DisplayCurrentState();
}
// Notify the user of the fingerprint auth result. Should be called after
// SetState. If fingerprint auth failed and retry is allowed, reset to
// default state after animation.
void NotifyFingerprintAuthResult(bool success) {
reset_state_.Stop();
if (state_ == FingerprintState::DISABLED_FROM_ATTEMPTS) {
label_->SetText(l10n_util::GetStringUTF16(
IDS_ASH_IN_SESSION_AUTH_FINGERPRINT_DISABLED_FROM_ATTEMPTS));
label_->SetAccessibleName(l10n_util::GetStringUTF16(
IDS_ASH_IN_SESSION_AUTH_FINGERPRINT_ACCESSIBLE_DISABLED_FROM_ATTEMPTS));
} else if (success) {
label_->SetText(l10n_util::GetStringUTF16(
IDS_ASH_IN_SESSION_AUTH_FINGERPRINT_SUCCESS));
label_->SetAccessibleName(l10n_util::GetStringUTF16(
IDS_ASH_IN_SESSION_AUTH_FINGERPRINT_ACCESSIBLE_SUCCESS));
} else {
label_->SetText(l10n_util::GetStringUTF16(
IDS_ASH_IN_SESSION_AUTH_FINGERPRINT_FAILED));
label_->SetAccessibleName(l10n_util::GetStringUTF16(
IDS_ASH_IN_SESSION_AUTH_FINGERPRINT_ACCESSIBLE_FAILED));
}
if (!success) {
// This is just to display the "fingerprint auth failure" animation. It
// does not necessarily mean |state_| is DISABLED_FROM_ATTEMPTS.
SetIcon(FingerprintState::DISABLED_FROM_ATTEMPTS);
// base::Unretained is safe because reset_state_ is owned by |this|.
reset_state_.Start(FROM_HERE, kResetToDefaultIconDelay,
base::BindOnce(&FingerprintView::DisplayCurrentState,
base::Unretained(this)));
label_->NotifyAccessibilityEvent(ax::mojom::Event::kAlert,
true /*send_native_event*/);
}
}
// views::View:
gfx::Size CalculatePreferredSize() const override {
gfx::Size size = views::View::CalculatePreferredSize();
size.set_width(kFingerprintViewWidthDp);
return size;
}
// views::View:
void OnGestureEvent(ui::GestureEvent* event) override {
if (event->type() != ui::ET_GESTURE_TAP)
return;
if (state_ == FingerprintState::AVAILABLE_DEFAULT ||
state_ == FingerprintState::AVAILABLE_WITH_TOUCH_SENSOR_WARNING) {
SetState(FingerprintState::AVAILABLE_WITH_TOUCH_SENSOR_WARNING);
reset_state_.Start(
FROM_HERE, kResetToDefaultMessageDelay,
base::BindOnce(&FingerprintView::SetState, base::Unretained(this),
FingerprintState::AVAILABLE_DEFAULT));
}
}
private:
void DisplayCurrentState() {
SetVisible(state_ != FingerprintState::UNAVAILABLE);
SetIcon(state_);
if (state_ != FingerprintState::UNAVAILABLE) {
base::string16 fingerprint_text =
l10n_util::GetStringUTF16(GetTextIdFromState());
label_->SetText(fingerprint_text);
label_->SetAccessibleName(
state_ == FingerprintState::DISABLED_FROM_ATTEMPTS
? l10n_util::GetStringUTF16(
IDS_ASH_IN_SESSION_AUTH_FINGERPRINT_ACCESSIBLE_DISABLED_FROM_ATTEMPTS)
: fingerprint_text);
}
}
void SetIcon(FingerprintState state) {
const SkColor color =
(state == FingerprintState::AVAILABLE_DEFAULT ||
state == FingerprintState::AVAILABLE_WITH_TOUCH_SENSOR_WARNING
? kTextColorPrimary
: kDisabledFingerprintIconColor);
switch (state) {
case FingerprintState::UNAVAILABLE:
case FingerprintState::AVAILABLE_DEFAULT:
case FingerprintState::AVAILABLE_WITH_TOUCH_SENSOR_WARNING:
case FingerprintState::DISABLED_FROM_TIMEOUT:
icon_->SetImage(gfx::CreateVectorIcon(kLockScreenFingerprintIcon,
kFingerprintIconSizeDp, color));
break;
case FingerprintState::DISABLED_FROM_ATTEMPTS:
icon_->SetAnimationDecoder(
std::make_unique<HorizontalImageSequenceAnimationDecoder>(
*ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
IDR_LOGIN_FINGERPRINT_UNLOCK_SPINNER),
kFingerprintFailedAnimationDuration,
kFingerprintFailedAnimationNumFrames),
AnimatedRoundedImageView::Playback::kSingle);
break;
}
}
int GetTextIdFromState() const {
switch (state_) {
case FingerprintState::AVAILABLE_DEFAULT:
return IDS_ASH_IN_SESSION_AUTH_FINGERPRINT_AVAILABLE;
case FingerprintState::AVAILABLE_WITH_TOUCH_SENSOR_WARNING:
return IDS_ASH_IN_SESSION_AUTH_FINGERPRINT_TOUCH_SENSOR;
case FingerprintState::DISABLED_FROM_ATTEMPTS:
return IDS_ASH_IN_SESSION_AUTH_FINGERPRINT_DISABLED_FROM_ATTEMPTS;
case FingerprintState::DISABLED_FROM_TIMEOUT:
if (can_use_pin_)
return IDS_ASH_IN_SESSION_AUTH_FINGERPRINT_PIN_OR_PASSWORD_REQUIRED;
return IDS_ASH_IN_SESSION_AUTH_FINGERPRINT_PASSWORD_REQUIRED;
case FingerprintState::UNAVAILABLE:
NOTREACHED();
return 0;
}
}
FingerprintLabel* label_ = nullptr;
AnimatedRoundedImageView* icon_ = nullptr;
FingerprintState state_ = FingerprintState::AVAILABLE_DEFAULT;
bool can_use_pin_ = false;
base::OneShotTimer reset_state_;
};
class AuthDialogContentsView::TitleLabel : public views::Label {
public:
TitleLabel() {
SetSubpixelRenderingEnabled(false);
SetAutoColorReadabilityEnabled(false);
SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY);
const gfx::FontList& base_font_list = views::Label::GetDefaultFontList();
SetFontList(base_font_list.Derive(kTitleFontSizeDeltaDp,
gfx::Font::FontStyle::NORMAL,
gfx::Font::Weight::MEDIUM));
SetMaximumWidth(kContainerPreferredWidth);
SetElideBehavior(gfx::ElideBehavior::ELIDE_TAIL);
SetPreferredSize(gfx::Size(kContainerPreferredWidth,
GetHeightForWidth(kContainerPreferredWidth)));
SetHorizontalAlignment(gfx::ALIGN_CENTER);
}
bool IsShowingError() const { return is_showing_error_; }
void ShowTitle() {
base::string16 title =
l10n_util::GetStringUTF16(IDS_ASH_IN_SESSION_AUTH_TITLE);
SetText(title);
SetEnabledColor(kTextColorPrimary);
is_showing_error_ = false;
SetAccessibleName(title);
}
void ShowError(const base::string16& error_text) {
SetText(error_text);
SetEnabledColor(kErrorColor);
is_showing_error_ = true;
SetAccessibleName(error_text);
NotifyAccessibilityEvent(ax::mojom::Event::kAlert,
true /*send_native_event*/);
}
// views::View
void GetAccessibleNodeData(ui::AXNodeData* node_data) override {
node_data->role = ax::mojom::Role::kStaticText;
node_data->SetName(accessible_name_);
}
private:
void SetAccessibleName(const base::string16& name) {
accessible_name_ = name;
NotifyAccessibilityEvent(ax::mojom::Event::kTextChanged,
true /*send_native_event*/);
}
bool is_showing_error_ = false;
base::string16 accessible_name_;
};
AuthDialogContentsView::AuthDialogContentsView(
uint32_t auth_methods,
const std::string& origin_name,
const AuthMethodsMetadata& auth_metadata,
const UserAvatar& avatar)
: auth_methods_(auth_methods),
origin_name_(origin_name),
auth_metadata_(auth_metadata) {
DCHECK(auth_methods_ & kAuthPassword);
SetLayoutManager(std::make_unique<views::FillLayout>());
auto border = std::make_unique<views::BubbleBorder>(
views::BubbleBorder::FLOAT, views::BubbleBorder::STANDARD_SHADOW,
kBackgroundColor);
border->SetCornerRadius(kCornerRadius);
SetBackground(std::make_unique<views::BubbleBackground>(border.get()));
SetBorder(std::move(border));
container_ = AddChildView(std::make_unique<NonAccessibleView>());
container_->SetBorder(views::CreateEmptyBorder(
kBorderTopDp, kBorderLeftDp, kBorderBottomDp, kBorderRightDp));
main_layout_ =
container_->SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kVertical));
main_layout_->set_main_axis_alignment(
views::BoxLayout::MainAxisAlignment::kStart);
main_layout_->set_cross_axis_alignment(
views::BoxLayout::CrossAxisAlignment::kCenter);
AddAvatarView(avatar);
AddVerticalSpacing(kSpacingAfterAvatar);
AddTitleView();
AddVerticalSpacing(kSpacingAfterTitle);
AddOriginNameView();
AddVerticalSpacing(kSpacingAfterOriginName);
if (auth_methods_ & kAuthPin) {
if (LoginPinInputView::IsAutosubmitSupported(
auth_metadata_.autosubmit_pin_length)) {
pin_autosubmit_on_ = true;
AddPinDigitInputView();
} else {
pin_autosubmit_on_ = false;
AddPinTextInputView();
}
AddVerticalSpacing(kSpacingAfterInputField);
// PIN pad is always visible regardless of PIN autosubmit status.
AddPinPadView();
}
if (auth_methods_ & kAuthFingerprint) {
if (pin_pad_view_)
AddVerticalSpacing(kSpacingBetweenPinPadAndFingerprintIcon);
fingerprint_view_ =
container_->AddChildView(std::make_unique<FingerprintView>());
fingerprint_view_->SetCanUsePin(auth_methods_ & kAuthPin);
}
AddVerticalSpacing(kSpacingBeforeButtons);
AddActionButtonsView();
}
AuthDialogContentsView::~AuthDialogContentsView() = default;
void AuthDialogContentsView::AddedToWidget() {
if (auth_methods_ & kAuthFingerprint) {
// Inject a callback from the contents view so that we can show retry
// prompt.
InSessionAuthDialogController::Get()->AuthenticateUserWithFingerprint(
base::BindOnce(&AuthDialogContentsView::OnFingerprintAuthComplete,
weak_factory_.GetWeakPtr()));
}
}
void AuthDialogContentsView::AddAvatarView(const UserAvatar& avatar) {
avatar_view_ =
container_->AddChildView(std::make_unique<AnimatedRoundedImageView>(
gfx::Size(kAvatarSizeDp, kAvatarSizeDp),
kAvatarSizeDp / 2 /*corner_radius*/));
avatar_view_->SetImage(avatar.image);
}
void AuthDialogContentsView::AddTitleView() {
title_ = container_->AddChildView(std::make_unique<TitleLabel>());
title_->ShowTitle();
}
void AuthDialogContentsView::AddOriginNameView() {
origin_name_view_ =
container_->AddChildView(std::make_unique<views::Label>());
origin_name_view_->SetEnabledColor(kTextColorSecondary);
origin_name_view_->SetSubpixelRenderingEnabled(false);
origin_name_view_->SetAutoColorReadabilityEnabled(false);
origin_name_view_->SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY);
origin_name_view_->SetText(
l10n_util::GetStringFUTF16(IDS_ASH_IN_SESSION_AUTH_ORIGIN_NAME_PROMPT,
base::UTF8ToUTF16(origin_name_)));
origin_name_view_->SetMaximumWidth(kContainerPreferredWidth);
origin_name_view_->SetMultiLine(true);
origin_name_view_->SetLineHeight(kOriginNameLineHeight);
origin_name_view_->SetPreferredSize(gfx::Size(
kContainerPreferredWidth,
origin_name_view_->GetHeightForWidth(kContainerPreferredWidth)));
origin_name_view_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
}
void AuthDialogContentsView::AddPinTextInputView() {
pin_text_input_view_ =
container_->AddChildView(std::make_unique<LoginPasswordView>(palette_));
pin_text_input_view_->SetPaintToLayer();
pin_text_input_view_->layer()->SetFillsBoundsOpaquely(false);
pin_text_input_view_->SetDisplayPasswordButtonVisible(true);
pin_text_input_view_->SetEnabled(true);
pin_text_input_view_->SetEnabledOnEmptyPassword(false);
pin_text_input_view_->SetFocusEnabledForTextfield(true);
pin_text_input_view_->SetVisible(true);
pin_text_input_view_->SetPlaceholderText(
l10n_util::GetStringUTF16(IDS_ASH_IN_SESSION_AUTH_PIN_PLACEHOLDER));
}
void AuthDialogContentsView::AddPinDigitInputView() {
pin_digit_input_view_ =
container_->AddChildView(std::make_unique<LoginPinInputView>(palette_));
pin_digit_input_view_->UpdateLength(auth_metadata_.autosubmit_pin_length);
pin_digit_input_view_->SetVisible(true);
}
void AuthDialogContentsView::AddPinPadView() {
DCHECK(auth_methods_ & kAuthPin);
if (pin_autosubmit_on_) {
pin_pad_view_ = container_->AddChildView(std::make_unique<LoginPinView>(
LoginPinView::Style::kAlphanumeric, palette_,
base::BindRepeating(&AuthDialogContentsView::OnInsertDigitFromPinPad,
base::Unretained(this)),
base::BindRepeating(&AuthDialogContentsView::OnBackspaceFromPinPad,
base::Unretained(this))));
pin_digit_input_view_->Init(
base::BindRepeating(&AuthDialogContentsView::OnAuthSubmit,
base::Unretained(this)),
base::BindRepeating(&AuthDialogContentsView::OnPinTextChanged,
base::Unretained(this)));
} else {
pin_pad_view_ = container_->AddChildView(std::make_unique<LoginPinView>(
LoginPinView::Style::kAlphanumeric, palette_,
base::BindRepeating(&AuthDialogContentsView::OnInsertDigitFromPinPad,
base::Unretained(this)),
base::BindRepeating(&AuthDialogContentsView::OnBackspaceFromPinPad,
base::Unretained(this)),
base::BindRepeating(&LoginPasswordView::SubmitPassword,
base::Unretained(pin_text_input_view_))));
pin_text_input_view_->Init(
base::BindRepeating(&AuthDialogContentsView::OnAuthSubmit,
base::Unretained(this)),
base::BindRepeating(&AuthDialogContentsView::OnPinTextChanged,
base::Unretained(this)),
base::DoNothing(), views::Button::PressedCallback());
}
pin_pad_view_->SetVisible(true);
}
void AuthDialogContentsView::OnInsertDigitFromPinPad(int digit) {
// Ignore anything if reached max attempts.
if (pin_attempts_ >= kMaxPinAttempts)
return;
if (title_->IsShowingError())
title_->ShowTitle();
if (pin_autosubmit_on_) {
pin_digit_input_view_->InsertDigit(digit);
} else {
pin_text_input_view_->InsertNumber(digit);
}
}
void AuthDialogContentsView::OnBackspaceFromPinPad() {
// Ignore anything if reached max attempts.
if (pin_attempts_ >= kMaxPinAttempts)
return;
if (title_->IsShowingError())
title_->ShowTitle();
if (pin_autosubmit_on_) {
pin_digit_input_view_->Backspace();
} else {
pin_text_input_view_->Backspace();
}
}
void AuthDialogContentsView::OnPinTextChanged(bool is_empty) {
// If the user is interacting with the input field, restore the title (clear
// error message).
//
// If |is_empty| is true, this call may come from resetting
// |pin_text_input_view_| or |pin_digit_input_view_|, when the error message
// hasn't been shown and read yet. In this case we don't restore the title.
if (title_->IsShowingError() && !is_empty)
title_->ShowTitle();
pin_pad_view_->OnPasswordTextChanged(is_empty);
}
void AuthDialogContentsView::AddVerticalSpacing(int height) {
auto* spacing =
container_->AddChildView(std::make_unique<NonAccessibleView>());
spacing->SetPreferredSize(gfx::Size(kContainerPreferredWidth, height));
}
void AuthDialogContentsView::AddActionButtonsView() {
action_view_container_ =
container_->AddChildView(std::make_unique<NonAccessibleView>());
auto* buttons_layout = action_view_container_->SetLayoutManager(
std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal));
buttons_layout->set_main_axis_alignment(
views::BoxLayout::MainAxisAlignment::kStart);
help_button_ =
action_view_container_->AddChildView(std::make_unique<views::LabelButton>(
base::BindRepeating(&AuthDialogContentsView::OnNeedHelpButtonPressed,
base::Unretained(this)),
l10n_util::GetStringUTF16(IDS_ASH_IN_SESSION_AUTH_HELP),
views::style::CONTEXT_BUTTON));
help_button_->SetEnabledTextColors(kTextColorPrimary);
auto* spacing = action_view_container_->AddChildView(
std::make_unique<NonAccessibleView>());
buttons_layout->SetFlexForView(spacing, 1);
cancel_button_ = action_view_container_->AddChildView(
std::make_unique<views::MdTextButton>(
base::BindRepeating(&AuthDialogContentsView::OnCancelButtonPressed,
base::Unretained(this)),
l10n_util::GetStringUTF16(IDS_ASH_IN_SESSION_AUTH_CANCEL)));
action_view_container_->SetPreferredSize(
gfx::Size(kContainerPreferredWidth, cancel_button_->height()));
}
void AuthDialogContentsView::OnCancelButtonPressed(const ui::Event& event) {
InSessionAuthDialogController::Get()->Cancel();
}
void AuthDialogContentsView::OnNeedHelpButtonPressed(const ui::Event& event) {
InSessionAuthDialogController::Get()->OpenInSessionAuthHelpPage();
}
void AuthDialogContentsView::OnAuthSubmit(const base::string16& pin) {
if (pin_autosubmit_on_) {
pin_digit_input_view_->SetReadOnly(true);
} else {
pin_text_input_view_->SetReadOnly(true);
}
InSessionAuthDialogController::Get()->AuthenticateUserWithPin(
base::UTF16ToUTF8(pin),
base::BindOnce(&AuthDialogContentsView::OnPinAuthComplete,
weak_factory_.GetWeakPtr()));
}
// TODO(b/156258540): Clear PIN if auth failed and retry is allowed.
void AuthDialogContentsView::OnPinAuthComplete(base::Optional<bool> success) {
// On success, do nothing, and the dialog will dismiss.
if (success.has_value() && success.value())
return;
pin_attempts_++;
base::string16 error_text =
pin_attempts_ >= kMaxPinAttempts
? l10n_util::GetStringUTF16(
IDS_ASH_IN_SESSION_AUTH_PIN_TOO_MANY_ATTEMPTS)
: l10n_util::GetStringUTF16(IDS_ASH_IN_SESSION_AUTH_PIN_INCORRECT);
title_->ShowError(error_text);
if (pin_attempts_ < kMaxPinAttempts) {
if (pin_autosubmit_on_) {
pin_digit_input_view_->Reset();
pin_digit_input_view_->SetReadOnly(false);
} else {
pin_text_input_view_->Reset();
pin_text_input_view_->SetReadOnly(false);
}
}
}
void AuthDialogContentsView::OnFingerprintAuthComplete(
bool success,
FingerprintState fingerprint_state) {
fingerprint_view_->SetState(fingerprint_state);
// Prepare for the next fingerprint scan.
if (!success && fingerprint_state == FingerprintState::AVAILABLE_DEFAULT) {
InSessionAuthDialogController::Get()->AuthenticateUserWithFingerprint(
base::BindOnce(&AuthDialogContentsView::OnFingerprintAuthComplete,
weak_factory_.GetWeakPtr()));
}
fingerprint_view_->NotifyFingerprintAuthResult(success);
}
void AuthDialogContentsView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
views::View::GetAccessibleNodeData(node_data);
node_data->role = ax::mojom::Role::kDialog;
node_data->SetName(
l10n_util::GetStringFUTF16(IDS_ASH_IN_SESSION_AUTH_ACCESSIBLE_TITLE,
base::UTF8ToUTF16(origin_name_)));
}
void AuthDialogContentsView::RequestFocus() {
if (auth_methods_ == kAuthFingerprint) {
// There's no PIN input field, so let the focus be on the cancel button
// (instead of the help button) because it is more often used.
cancel_button_->RequestFocus();
return;
}
// For other cases, the base method correctly sets focus to the input field.
views::View::RequestFocus();
}
} // namespace ash