Commit 2be1b2e1 authored by Maksim Ivanov's avatar Maksim Ivanov Committed by Commit Bot

Animate the "Start" button for smart card user pod

Implement the animation of the "Start" ("->") button on the Login
Screen for the users that use challenge-response authentication
(a.k.a. smart card login).

The animation is, in accordance with the UI mocks, a continuously
increasing arc around the button.

This change also removes the code that was hiding the "Start"
button - this is replaced by the animation.

Bug: 1016839
Test: log in as a smart card user, log out, click "->" to log in again, verify that the "->" button is animated with a continuously increasing arc
Change-Id: I77e830522c5a0770d583d661122cb3831fbb5390
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2005988Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Reviewed-by: default avatarToni Baržić <tbarzic@chromium.org>
Commit-Queue: Maksim Ivanov <emaxx@chromium.org>
Cr-Commit-Position: refs/heads/master@{#734251}
parent b2a8b8b0
......@@ -5,9 +5,16 @@
#include "ash/login/ui/arrow_button_view.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "base/time/time.h"
#include "cc/paint/paint_flags.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/gfx/animation/multi_animation.h"
#include "ui/gfx/animation/tween.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/color_palette.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/gfx/skia_util.h"
namespace ash {
namespace {
......@@ -16,6 +23,28 @@ namespace {
constexpr int kArrowIconSizeDp = 20;
// An alpha value for disabled button.
constexpr SkAlpha kButtonDisabledAlpha = 0x80;
// How long does a single step of the loading animation take - i.e., the time it
// takes for the arc to grow from a point to a full circle.
constexpr base::TimeDelta kLoadingAnimationStepDuration =
base::TimeDelta::FromSeconds(2);
void PaintLoadingArc(gfx::Canvas* canvas,
const gfx::Rect& bounds,
double loading_fraction) {
gfx::Rect oval = bounds;
// Inset to make sure the whole arc is inside the visible rect.
oval.Inset(/*horizontal=*/1, /*vertical=*/1);
SkPath path;
path.arcTo(RectToSkRect(oval), /*startAngle=*/-90,
/*sweepAngle=*/360 * loading_fraction, /*forceMoveTo=*/true);
cc::PaintFlags flags;
flags.setColor(gfx::kGoogleGrey100);
flags.setStyle(cc::PaintFlags::kStroke_Style);
flags.setAntiAlias(true);
canvas->DrawPath(path, flags);
}
} // namespace
......@@ -51,7 +80,12 @@ void ArrowButtonView::PaintButtonContents(gfx::Canvas* canvas) {
// Draw arrow icon.
views::ImageButton::PaintButtonContents(canvas);
// Draw the arc of the loading animation.
if (loading_animation_)
PaintLoadingArc(canvas, rect, loading_animation_->GetCurrentValue());
}
void ArrowButtonView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
LoginButton::GetAccessibleNodeData(node_data);
// TODO(tbarzic): Fix this - https://crbug.com/961930.
......@@ -64,4 +98,40 @@ void ArrowButtonView::SetBackgroundColor(SkColor color) {
SchedulePaint();
}
void ArrowButtonView::EnableLoadingAnimation(bool enabled) {
if (!enabled) {
if (!loading_animation_)
return;
loading_animation_.reset();
SchedulePaint();
return;
}
if (loading_animation_)
return;
// Use MultiAnimation in order to have a continuously running analog of
// LinearAnimation.
loading_animation_ = std::make_unique<gfx::MultiAnimation>(
gfx::MultiAnimation::Parts{
gfx::MultiAnimation::Part(kLoadingAnimationStepDuration,
gfx::Tween::LINEAR),
},
gfx::MultiAnimation::kDefaultTimerInterval);
loading_animation_->set_delegate(&loading_animation_delegate_);
loading_animation_->Start();
}
ArrowButtonView::LoadingAnimationDelegate::LoadingAnimationDelegate(
ArrowButtonView* owner)
: owner_(owner) {}
ArrowButtonView::LoadingAnimationDelegate::~LoadingAnimationDelegate() =
default;
void ArrowButtonView::LoadingAnimationDelegate::AnimationProgressed(
const gfx::Animation* /*animation*/) {
owner_->SchedulePaint();
}
} // namespace ash
......@@ -5,9 +5,16 @@
#ifndef ASH_LOGIN_UI_ARROW_BUTTON_VIEW_H_
#define ASH_LOGIN_UI_ARROW_BUTTON_VIEW_H_
#include <memory>
#include "ash/login/ui/login_button.h"
#include "ui/gfx/animation/animation_delegate.h"
#include "ui/views/controls/image_view.h"
namespace gfx {
class MultiAnimation;
}
namespace ash {
// A round button with arrow icon in the middle.
......@@ -25,9 +32,33 @@ class ArrowButtonView : public LoginButton {
// Set background color of the button.
void SetBackgroundColor(SkColor color);
// Allows to control the loading animation (disabled by default). The
// animation is an arc that gradually increases from a point to a full circle;
// the animation is looped.
void EnableLoadingAnimation(bool enabled);
private:
// Helper class that translates events from the loading animation events into
// scheduling painting.
class LoadingAnimationDelegate : public gfx::AnimationDelegate {
public:
explicit LoadingAnimationDelegate(ArrowButtonView* owner);
LoadingAnimationDelegate(const LoadingAnimationDelegate&) = delete;
LoadingAnimationDelegate& operator=(const LoadingAnimationDelegate&) =
delete;
~LoadingAnimationDelegate() override;
// views::AnimationDelegateViews:
void AnimationProgressed(const gfx::Animation* animation) override;
private:
ArrowButtonView* const owner_;
};
int size_;
SkColor background_color_;
LoadingAnimationDelegate loading_animation_delegate_{this};
std::unique_ptr<gfx::MultiAnimation> loading_animation_;
DISALLOW_COPY_AND_ASSIGN(ArrowButtonView);
};
......
......@@ -561,7 +561,7 @@ class LoginAuthUserView::ChallengeResponseView : public views::View,
arrow_to_icon_spacer_ = AddChildView(std::make_unique<NonAccessibleView>());
arrow_to_icon_spacer_->SetPreferredSize(
gfx::Size(0, GetArrowToIconSpacerHeight()));
gfx::Size(0, kSpacingBetweenChallengeResponseArrowAndIconDp));
icon_ = AddChildView(std::make_unique<views::ImageView>());
icon_->SetImage(GetImageForIcon());
......@@ -587,8 +587,9 @@ class LoginAuthUserView::ChallengeResponseView : public views::View,
// views::ButtonListener:
void ButtonPressed(views::Button* sender, const ui::Event& event) override {
if (sender == arrow_button_) {
DCHECK_NE(state_, State::kAuthenticating);
on_start_tap_.Run();
// Ignore further clicks while handling the previous one.
if (state_ != State::kAuthenticating)
on_start_tap_.Run();
} else {
NOTREACHED();
}
......@@ -607,9 +608,7 @@ class LoginAuthUserView::ChallengeResponseView : public views::View,
base::Unretained(this), State::kInitial));
}
arrow_button_->SetVisible(state_ != State::kAuthenticating);
arrow_to_icon_spacer_->SetPreferredSize(
gfx::Size(0, GetArrowToIconSpacerHeight()));
arrow_button_->EnableLoadingAnimation(state == State::kAuthenticating);
icon_->SetImage(GetImageForIcon());
label_->SetText(GetTextForLabel());
......@@ -619,15 +618,6 @@ class LoginAuthUserView::ChallengeResponseView : public views::View,
void RequestFocus() override { arrow_button_->RequestFocus(); }
private:
int GetArrowToIconSpacerHeight() const {
int spacer_height = kSpacingBetweenChallengeResponseArrowAndIconDp;
// During authentication, the arrow button is hidden, so the spacer should
// consume this space to avoid moving controls below it.
if (state_ == State::kAuthenticating)
spacer_height += kChallengeResponseArrowSizeDp;
return spacer_height;
}
gfx::ImageSkia GetImageForIcon() const {
switch (state_) {
case State::kInitial:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment