Commit c7fff20e authored by Balazs Engedy's avatar Balazs Engedy Committed by Commit Bot

Add activity indicator to WebAuthn UX.

Add a progress bar style (linear) activity indicator to be shown at the
top of the dialog during certain steps of the WebAuthn UI flow.

Bug: 849323
Change-Id: Ib7faa0528a2914d61ad8bed1e935fe9b083307c3
Reviewed-on: https://chromium-review.googlesource.com/1181906Reviewed-by: default avatarJun Choi <hongjunchoi@chromium.org>
Commit-Queue: Balazs Engedy <engedy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#584716}
parent 645ae486
......@@ -34,6 +34,7 @@ class TestSheetModel : public AuthenticatorRequestSheetModel {
private:
// AuthenticatorRequestSheetModel:
bool IsActivityIndicatorVisible() const override { return true; }
bool IsBackButtonVisible() const override { return true; }
bool IsCancelButtonVisible() const override { return true; }
base::string16 GetCancelButtonLabel() const override {
......
......@@ -17,9 +17,23 @@
#include "ui/views/controls/button/image_button_factory.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/progress_bar.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/fill_layout.h"
namespace {
// Fixed height of the illustration shown in the top half of the sheet.
constexpr int kIllustrationHeight = 148;
// Foreground/background color, and the height of the progress bar style
// activity indicator shown at the top of some sheets.
constexpr SkColor kActivityIndicateFgColor = SkColorSetRGB(0xf2, 0x99, 0x00);
constexpr SkColor kActivityIndicateBkColor = SkColorSetRGB(0xf6, 0xe6, 0xc8);
constexpr int kActivityIndicatorHeight = 4;
} // namespace
using views::BoxLayout;
AuthenticatorRequestSheetView::AuthenticatorRequestSheetView(
......@@ -54,42 +68,55 @@ void AuthenticatorRequestSheetView::ButtonPressed(views::Button* sender,
std::unique_ptr<views::View>
AuthenticatorRequestSheetView::CreateIllustrationWithOverlays() {
const int illustration_width = ChromeLayoutProvider::Get()->GetDistanceMetric(
DISTANCE_MODAL_DIALOG_PREFERRED_WIDTH);
const gfx::Size illustration_size(illustration_width, kIllustrationHeight);
// The container view has no layout, so its preferred size is hardcoded to
// match the size of the image, and all overlays are absolutely positioned.
auto image_with_overlays = std::make_unique<views::View>();
image_with_overlays->SetLayoutManager(std::make_unique<views::FillLayout>());
image_with_overlays->SetPreferredSize(illustration_size);
auto image_view = std::make_unique<views::ImageView>();
image_view->SetImage(model()->GetStepIllustration());
image_view->SetPreferredSize(illustration_size);
image_view->SizeToPreferredSize();
image_with_overlays->AddChildView(image_view.release());
if (model()->IsActivityIndicatorVisible()) {
auto activity_indicator = std::make_unique<views::ProgressBar>(
kActivityIndicatorHeight, false /* allow_round_corner */);
activity_indicator->SetValue(-1 /* inifinite animation */);
activity_indicator->set_foreground_color(kActivityIndicateFgColor);
activity_indicator->set_background_color(kActivityIndicateBkColor);
activity_indicator->SetPreferredSize(
gfx::Size(illustration_width, kActivityIndicatorHeight));
activity_indicator->SizeToPreferredSize();
image_with_overlays->AddChildView(activity_indicator.release());
}
if (model()->IsBackButtonVisible()) {
std::unique_ptr<views::ImageButton> back_arrow(
views::CreateVectorImageButton(this));
back_arrow->SetFocusForPlatform();
back_arrow->SetAccessibleName(l10n_util::GetStringUTF16(IDS_BACK_BUTTON));
// Position the back button so that there is the standard amount of padding
// between the top/left side of the back button and the dialog borders.
const gfx::Insets dialog_insets =
views::LayoutProvider::Get()->GetDialogInsetsForContentType(
views::CONTROL, views::CONTROL);
auto color_reference = std::make_unique<views::Label>(
base::string16(), views::style::CONTEXT_DIALOG_TITLE,
views::style::STYLE_PRIMARY);
views::SetImageFromVectorIcon(
back_arrow.get(), vector_icons::kBackArrowIcon,
color_utils::DeriveDefaultIconColor(color_reference->enabled_color()));
back_arrow->SizeToPreferredSize();
back_arrow->SetX(dialog_insets.left());
back_arrow->SetY(dialog_insets.top());
back_arrow_button_ = back_arrow.get();
// The |overlaly_container| will be stretched to fill |image_with_overlays|
// while allowing |back_arrow| to be absolutely positioned inside it, and
// rendered on top of the image due to being higher in the z-order.
auto overlay_container = std::make_unique<views::View>();
overlay_container->AddChildView(back_arrow.release());
image_with_overlays->AddChildView(overlay_container.release());
// Position the back button so that there is the standard amount of padding
// between the top/left side of the back button and the dialog borders.
gfx::Insets dialog_insets =
views::LayoutProvider::Get()->GetDialogInsetsForContentType(
views::CONTROL, views::CONTROL);
back_arrow_button_->SizeToPreferredSize();
back_arrow_button_->SetX(dialog_insets.left());
back_arrow_button_->SetY(dialog_insets.top());
image_with_overlays->AddChildView(back_arrow.release());
}
return image_with_overlays;
......
......@@ -17,6 +17,7 @@ class AuthenticatorRequestSheetModel;
// Defines the basic structure of sheets shown in the authenticator request
// dialog. Each sheet corresponds to a given step of the authentication flow,
// and encapsulates the controls above the Ok/Cancel buttons, namely:
// -- an optional progress-bar-style activity indicator (at the top),
// -- an optional `back icon`,
// -- a pretty illustration in the top half of the dialog,
// -- the title of the current step,
......@@ -25,7 +26,7 @@ class AuthenticatorRequestSheetModel;
// the rest of the space.
//
// +-------------------------------------------------+
// |. . . . . . . . . . . . . . . . . . . . . . . . .|
// |*************************************************|
// |. (<-). . . . . . . . . . . . . . . . . . . . . .|
// |. . . . I L L U S T R A T I O N H E R E . . . .|
// |. . . . . . . . . . . . . . . . . . . . . . . . .|
......@@ -70,7 +71,8 @@ class AuthenticatorRequestSheetView : public views::View,
private:
// Creates the upper half of the sheet, consisting of a pretty illustration
// overlayed with absolutely positioned controls rendered on top.
// overlayed with absolutely positioned controls (the activity indicator and
// the back button) rendered on top.
std::unique_ptr<views::View> CreateIllustrationWithOverlays();
// Creates the lower half of the sheet, consisting of the title, description,
......
......@@ -36,6 +36,7 @@ class AuthenticatorRequestSheetModel {
public:
virtual ~AuthenticatorRequestSheetModel() {}
virtual bool IsActivityIndicatorVisible() const = 0;
virtual bool IsBackButtonVisible() const = 0;
virtual bool IsCancelButtonVisible() const = 0;
......
......@@ -36,6 +36,10 @@ gfx::ImageSkia* AuthenticatorSheetModelBase::GetImage(int resource_id) {
return ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id);
}
bool AuthenticatorSheetModelBase::IsActivityIndicatorVisible() const {
return false;
}
bool AuthenticatorSheetModelBase::IsBackButtonVisible() const {
return true;
}
......@@ -142,6 +146,11 @@ void AuthenticatorTransportSelectorSheetModel::OnTransportSelected(
// AuthenticatorInsertAndActivateUsbSheetModel ----------------------
bool AuthenticatorInsertAndActivateUsbSheetModel::IsActivityIndicatorVisible()
const {
return true;
}
gfx::ImageSkia*
AuthenticatorInsertAndActivateUsbSheetModel::GetStepIllustration() const {
return GetImage(IDR_WEBAUTHN_ILLUSTRATION_USB_1X);
......@@ -279,6 +288,11 @@ base::string16 AuthenticatorBleEnterPairingModeSheetModel::GetStepDescription()
// AuthenticatorBleDeviceSelectionSheetModel ----------------------------------
bool AuthenticatorBleDeviceSelectionSheetModel::IsActivityIndicatorVisible()
const {
return true;
}
gfx::ImageSkia* AuthenticatorBleDeviceSelectionSheetModel::GetStepIllustration()
const {
return GetImage(IDR_WEBAUTHN_ILLUSTRATION_BLE_NAME_1X);
......@@ -325,6 +339,10 @@ base::string16 AuthenticatorBlePinEntrySheetModel::GetAcceptButtonLabel()
// AuthenticatorBleVerifyingSheetModel ----------------------------------------
bool AuthenticatorBleVerifyingSheetModel::IsActivityIndicatorVisible() const {
return true;
}
gfx::ImageSkia* AuthenticatorBleVerifyingSheetModel::GetStepIllustration()
const {
return GetImage(IDR_WEBAUTHN_ILLUSTRATION_BLE_1X);
......@@ -340,6 +358,10 @@ base::string16 AuthenticatorBleVerifyingSheetModel::GetStepDescription() const {
// AuthenticatorBleActivateSheetModel -----------------------------------------
bool AuthenticatorBleActivateSheetModel::IsActivityIndicatorVisible() const {
return true;
}
gfx::ImageSkia* AuthenticatorBleActivateSheetModel::GetStepIllustration()
const {
return GetImage(IDR_WEBAUTHN_ILLUSTRATION_BLE_TAP_1X);
......@@ -356,6 +378,10 @@ base::string16 AuthenticatorBleActivateSheetModel::GetStepDescription() const {
// AuthenticatorTouchIdSheetModel -----------------------------------------
bool AuthenticatorTouchIdSheetModel::IsActivityIndicatorVisible() const {
return true;
}
gfx::ImageSkia* AuthenticatorTouchIdSheetModel::GetStepIllustration() const {
#if defined(OS_MACOSX)
return GetImage(IDR_WEBAUTHN_ILLUSTRATION_TOUCHID_1X);
......@@ -380,6 +406,10 @@ base::string16 AuthenticatorTouchIdSheetModel::GetStepDescription() const {
// AuthenticatorPaaskSheetModel -----------------------------------------
bool AuthenticatorPaaskSheetModel::IsActivityIndicatorVisible() const {
return true;
}
gfx::ImageSkia* AuthenticatorPaaskSheetModel::GetStepIllustration() const {
return GetImage(IDR_WEBAUTHN_ILLUSTRATION_PHONE_1X);
}
......
......@@ -33,6 +33,7 @@ class AuthenticatorSheetModelBase
base::string16 GetRelyingPartyIdString() const;
// AuthenticatorRequestSheetModel:
bool IsActivityIndicatorVisible() const override;
bool IsBackButtonVisible() const override;
bool IsCancelButtonVisible() const override;
base::string16 GetCancelButtonLabel() const override;
......@@ -93,6 +94,7 @@ class AuthenticatorInsertAndActivateUsbSheetModel
private:
// AuthenticatorSheetModelBase:
bool IsActivityIndicatorVisible() const override;
gfx::ImageSkia* GetStepIllustration() const override;
base::string16 GetStepTitle() const override;
base::string16 GetStepDescription() const override;
......@@ -172,6 +174,7 @@ class AuthenticatorBleDeviceSelectionSheetModel
private:
// AuthenticatorSheetModelBase:
bool IsActivityIndicatorVisible() const override;
gfx::ImageSkia* GetStepIllustration() const override;
base::string16 GetStepTitle() const override;
base::string16 GetStepDescription() const override;
......@@ -197,6 +200,7 @@ class AuthenticatorBleVerifyingSheetModel : public AuthenticatorSheetModelBase {
private:
// AuthenticatorSheetModelBase:
bool IsActivityIndicatorVisible() const override;
gfx::ImageSkia* GetStepIllustration() const override;
base::string16 GetStepTitle() const override;
base::string16 GetStepDescription() const override;
......@@ -208,6 +212,7 @@ class AuthenticatorBleActivateSheetModel : public AuthenticatorSheetModelBase {
private:
// AuthenticatorSheetModelBase:
bool IsActivityIndicatorVisible() const override;
gfx::ImageSkia* GetStepIllustration() const override;
base::string16 GetStepTitle() const override;
base::string16 GetStepDescription() const override;
......@@ -219,6 +224,7 @@ class AuthenticatorTouchIdSheetModel : public AuthenticatorSheetModelBase {
private:
// AuthenticatorSheetModelBase:
bool IsActivityIndicatorVisible() const override;
gfx::ImageSkia* GetStepIllustration() const override;
base::string16 GetStepTitle() const override;
base::string16 GetStepDescription() const override;
......@@ -230,6 +236,7 @@ class AuthenticatorPaaskSheetModel : public AuthenticatorSheetModelBase {
private:
// AuthenticatorSheetModelBase:
bool IsActivityIndicatorVisible() const override;
gfx::ImageSkia* GetStepIllustration() const override;
base::string16 GetStepTitle() const override;
base::string16 GetStepDescription() const override;
......
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