1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
|
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/views/webauthn/authenticator_gpm_pin_view.h"
#include <memory>
#include <string>
#include <utility>
#include "base/functional/bind.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string_util.h"
#include "chrome/browser/ui/views/webauthn/pin_textfield.h"
#include "chrome/browser/ui/views/webauthn/reveal_button_util.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/events/types/event_type.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/layout/box_layout.h"
namespace {
constexpr int kBetweenChildSpacing = 8;
} // namespace
AuthenticatorGPMPinView::AuthenticatorGPMPinView(
int pin_digits_count,
bool ui_disabled,
const std::u16string& pin,
const std::u16string& pin_accessible_description,
Delegate* delegate)
: delegate_(delegate) {
auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>());
layout->set_main_axis_alignment(views::BoxLayout::MainAxisAlignment::kStart);
layout->set_cross_axis_alignment(
views::BoxLayout::CrossAxisAlignment::kCenter);
layout->set_between_child_spacing(kBetweenChildSpacing);
auto pin_textfield = std::make_unique<PinTextfield>(pin_digits_count);
pin_textfield->SetController(this);
pin_textfield->GetViewAccessibility().SetName(
delegate_->GetPinAccessibleName());
if (!pin_accessible_description.empty()) {
pin_textfield->GetViewAccessibility().SetDescription(
pin_accessible_description);
}
pin_textfield->SetDisabled(ui_disabled);
pin_textfield->SetPin(pin);
pin_textfield->SetEnabled(!ui_disabled);
pin_textfield_ = AddChildView(std::move(pin_textfield));
reveal_button_ = AddChildView(CreateRevealButton(
base::BindRepeating(&AuthenticatorGPMPinView::OnRevealButtonClicked,
base::Unretained(this))));
reveal_button_->SetEnabled(!ui_disabled);
}
AuthenticatorGPMPinView::~AuthenticatorGPMPinView() = default;
void AuthenticatorGPMPinView::RequestFocus() {
pin_textfield_->RequestFocus();
}
bool AuthenticatorGPMPinView::HandleKeyEvent(views::Textfield* textfield,
const ui::KeyEvent& event) {
if (event.type() != ui::EventType::kKeyPressed) {
return false;
}
base::WeakPtr<AuthenticatorGPMPinView> weak_this =
weak_ptr_factory_.GetWeakPtr();
bool pin_changed = false;
char16_t c = event.GetCharacter();
bool is_digit = base::IsAsciiDigit(c);
if (is_digit) {
pin_changed = pin_textfield_->AppendDigit(std::u16string(1, c));
} else if (event.key_code() == ui::VKEY_BACK) {
pin_changed = pin_textfield_->RemoveDigit();
}
if (pin_changed) {
delegate_->OnPinChanged(pin_textfield_->GetPin());
// The view might be destroyed in `OnPinChanged` (e.g. after typing last
// digit during UV).
if (!weak_this) {
return true;
}
// Pin textfield accessibility label contains information about the
// currently focused digit.
pin_textfield_->GetViewAccessibility().SetName(
delegate_->GetPinAccessibleName());
}
// This might result in recreating this view if the hint visibility changes,
// hence it should be the last call in this function.
if (base::IsAsciiPrintable(c)) {
delegate_->PinCharTyped(is_digit);
}
return true;
}
void AuthenticatorGPMPinView::OnRevealButtonClicked() {
pin_revealed_ = !pin_revealed_;
reveal_button_->SetToggled(pin_revealed_);
pin_textfield_->SetObscured(!pin_revealed_);
}
BEGIN_METADATA(AuthenticatorGPMPinView)
END_METADATA
|