[go: nahoru, domu]

blob: cf2ea9c4fb088265fcb3208e65b634a286ac68af [file] [log] [blame]
// Copyright 2021 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/login/ui/smart_lock_auth_factor_model.h"
#include "ash/login/ui/auth_icon_view.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/style/ash_color_provider.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/gfx/vector_icon_types.h"
namespace ash {
// static
SmartLockAuthFactorModel::Factory*
SmartLockAuthFactorModel::Factory::factory_instance_ = nullptr;
// static
std::unique_ptr<SmartLockAuthFactorModel>
SmartLockAuthFactorModel::Factory::Create(
SmartLockState initial_state,
base::RepeatingCallback<void()> arrow_button_tap_callback) {
if (factory_instance_)
return factory_instance_->CreateInstance(initial_state,
arrow_button_tap_callback);
return std::make_unique<SmartLockAuthFactorModel>(initial_state,
arrow_button_tap_callback);
}
// static
void SmartLockAuthFactorModel::Factory::SetFactoryForTesting(
SmartLockAuthFactorModel::Factory* factory) {
factory_instance_ = factory;
}
SmartLockAuthFactorModel::SmartLockAuthFactorModel(
SmartLockState initial_state,
base::RepeatingCallback<void()> arrow_button_tap_callback)
: state_(initial_state),
arrow_button_tap_callback_(arrow_button_tap_callback) {}
SmartLockAuthFactorModel::~SmartLockAuthFactorModel() = default;
void SmartLockAuthFactorModel::OnArrowButtonTapOrClickEvent() {
if (state_ == SmartLockState::kPhoneAuthenticated) {
arrow_button_tap_callback_.Run();
}
}
void SmartLockAuthFactorModel::SetSmartLockState(SmartLockState state) {
if (state_ == state)
return;
// Clear out the timeout if the state changes. This shouldn't happen
// ordinarily -- permanent error states are permanent after all -- but this is
// required for the debug overlay to work properly when cycling states.
has_permanent_error_display_timed_out_ = false;
state_ = state;
RefreshUI();
}
void SmartLockAuthFactorModel::NotifySmartLockAuthResult(bool result) {
auth_result_ = result;
RefreshUI();
}
AuthFactorModel::AuthFactorState SmartLockAuthFactorModel::GetAuthFactorState()
const {
if (auth_result_.has_value()) {
return auth_result_.value() ? AuthFactorState::kAuthenticated
: AuthFactorState::kErrorPermanent;
}
switch (state_) {
case SmartLockState::kDisabled:
[[fallthrough]];
case SmartLockState::kInactive:
return AuthFactorState::kUnavailable;
case SmartLockState::kPhoneNotFound:
[[fallthrough]];
case SmartLockState::kConnectingToPhone:
[[fallthrough]];
case SmartLockState::kPhoneFoundLockedAndDistant:
[[fallthrough]];
case SmartLockState::kPhoneFoundUnlockedAndDistant:
return AuthFactorState::kAvailable;
case SmartLockState::kPhoneAuthenticated:
return AuthFactorState::kClickRequired;
case SmartLockState::kPhoneFoundLockedAndProximate:
return AuthFactorState::kReady;
case SmartLockState::kPasswordReentryRequired:
[[fallthrough]];
case SmartLockState::kPrimaryUserAbsent:
[[fallthrough]];
case SmartLockState::kPhoneNotAuthenticated:
[[fallthrough]];
case SmartLockState::kBluetoothDisabled:
[[fallthrough]];
case SmartLockState::kPhoneNotLockable:
return AuthFactorState::kErrorPermanent;
}
}
AuthFactorType SmartLockAuthFactorModel::GetType() const {
return AuthFactorType::kSmartLock;
}
int SmartLockAuthFactorModel::GetLabelId() const {
if (auth_result_.has_value()) {
if (auth_result_.value()) {
return IDS_SMART_LOCK_LABEL_PHONE_LOCKED;
}
// Once the Smart Lock error message has timed out, prompt the
// user to enter their password (since Smart Lock has permanently failed).
return has_permanent_error_display_timed_out_
? IDS_AUTH_FACTOR_LABEL_PASSWORD_REQUIRED
: IDS_AUTH_FACTOR_LABEL_CANNOT_UNLOCK;
}
switch (state_) {
case SmartLockState::kDisabled:
[[fallthrough]];
case SmartLockState::kInactive:
[[fallthrough]];
case SmartLockState::kPasswordReentryRequired:
[[fallthrough]];
case SmartLockState::kPrimaryUserAbsent:
[[fallthrough]];
case SmartLockState::kPhoneNotAuthenticated:
return can_use_pin_ ? IDS_AUTH_FACTOR_LABEL_PASSWORD_OR_PIN_REQUIRED
: IDS_AUTH_FACTOR_LABEL_PASSWORD_REQUIRED;
case SmartLockState::kBluetoothDisabled:
return IDS_SMART_LOCK_LABEL_NO_BLUETOOTH;
case SmartLockState::kPhoneNotLockable:
return IDS_SMART_LOCK_LABEL_NO_PHONE_LOCK_SCREEN;
case SmartLockState::kConnectingToPhone:
return IDS_SMART_LOCK_LABEL_LOOKING_FOR_PHONE;
case SmartLockState::kPhoneFoundLockedAndDistant:
[[fallthrough]];
case SmartLockState::kPhoneFoundUnlockedAndDistant:
return IDS_SMART_LOCK_LABEL_PHONE_TOO_FAR;
case SmartLockState::kPhoneNotFound:
return IDS_SMART_LOCK_LABEL_NO_PHONE;
case SmartLockState::kPhoneFoundLockedAndProximate:
return IDS_SMART_LOCK_LABEL_PHONE_LOCKED;
case SmartLockState::kPhoneAuthenticated:
return IDS_AUTH_FACTOR_LABEL_CLICK_TO_ENTER;
}
NOTREACHED();
}
bool SmartLockAuthFactorModel::ShouldAnnounceLabel() const {
return true;
}
int SmartLockAuthFactorModel::GetAccessibleNameId() const {
// TODO(crbug.com/1233614): Determine whether any state needs to have a
// different label for a11y.
return GetLabelId();
}
void SmartLockAuthFactorModel::UpdateIcon(AuthIconView* icon) {
if (auth_result_.has_value() && !auth_result_.value()) {
if (has_permanent_error_display_timed_out_) {
icon->SetIcon(kLockScreenSmartLockDisabledIcon,
AuthIconView::Color::kDisabled);
} else {
// TODO(crbug.com/1233614): Get actual failure icon once asset is ready.
icon->SetIcon(kLockScreenSmartCardFailureIcon,
AuthIconView::Color::kError);
}
icon->StopProgressAnimation();
return;
}
switch (state_) {
case SmartLockState::kPhoneNotFound:
icon->SetIcon(kLockScreenSmartLockBluetoothIcon,
AuthIconView::Color::kPrimary);
icon->RunErrorShakeAnimation();
icon->StopProgressAnimation();
return;
case SmartLockState::kPhoneFoundLockedAndDistant:
[[fallthrough]];
case SmartLockState::kPhoneFoundUnlockedAndDistant:
icon->SetIcon(kLockScreenSmartLockBluetoothIcon,
AuthIconView::Color::kPrimary);
icon->StopProgressAnimation();
return;
case SmartLockState::kConnectingToPhone:
icon->SetIcon(kLockScreenSmartLockBluetoothIcon,
AuthIconView::Color::kPrimary);
icon->StartProgressAnimation();
return;
case SmartLockState::kPhoneFoundLockedAndProximate:
icon->SetIcon(kLockScreenSmartLockPhoneIcon,
AuthIconView::Color::kPrimary);
icon->StopProgressAnimation();
return;
case SmartLockState::kPrimaryUserAbsent:
[[fallthrough]];
case SmartLockState::kPhoneNotAuthenticated:
[[fallthrough]];
case SmartLockState::kPasswordReentryRequired:
[[fallthrough]];
case SmartLockState::kPhoneNotLockable:
[[fallthrough]];
case SmartLockState::kBluetoothDisabled:
icon->SetIcon(kLockScreenSmartLockDisabledIcon,
AuthIconView::Color::kDisabled);
icon->StopProgressAnimation();
return;
case SmartLockState::kPhoneAuthenticated:
// Click to enter -- icon handled by parent view.
[[fallthrough]];
case SmartLockState::kDisabled:
[[fallthrough]];
case SmartLockState::kInactive:
// Intentionally blank.
return;
}
}
void SmartLockAuthFactorModel::DoHandleTapOrClick() {
// Do Nothing: Smart Lock does not react to taps on its icon. Clicks on the
// arrow button are handled in LoginAuthFactorsView.
}
void SmartLockAuthFactorModel::DoHandleErrorTimeout() {
// Do Nothing: Smart Lock has no temporary errors to restore from, so there is
// nothing to do.
}
} // namespace ash