Skip to content

Commit

Permalink
SPC No matching credential UI, Desktop Implementation
Browse files Browse the repository at this point in the history
Desktop version of SPC no matching credential UI needed for user
privacy.
Uses the shopping cart header image instead of the fingerprint icon.

Bug: 1233636
Change-Id: I8b4d728fc6d84d8772c7a4f813edb4115c874f48
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3069244
Commit-Queue: Jenny Lei <jennylei@google.com>
Reviewed-by: Liquan (Max) Gu <maxlg@chromium.org>
Reviewed-by: Rouslan Solomakhin <rouslan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#908960}
  • Loading branch information
jennyy-lei authored and Chromium LUCI CQ committed Aug 5, 2021
1 parent 6fe5634 commit 23ac3ba
Show file tree
Hide file tree
Showing 12 changed files with 430 additions and 11 deletions.
2 changes: 2 additions & 0 deletions chrome/browser/ui/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -4252,6 +4252,8 @@ static_library("ui") {
"views/payments/profile_list_view_controller.h",
"views/payments/secure_payment_confirmation_dialog_view.cc",
"views/payments/secure_payment_confirmation_dialog_view.h",
"views/payments/secure_payment_confirmation_no_creds_dialog_view.cc",
"views/payments/secure_payment_confirmation_no_creds_dialog_view.h",
"views/payments/secure_payment_confirmation_views_util.cc",
"views/payments/secure_payment_confirmation_views_util.h",
"views/payments/shipping_address_editor_view_controller.cc",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
// 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 "chrome/browser/ui/views/payments/secure_payment_confirmation_no_creds_dialog_view.h"

#include "chrome/browser/ui/views/payments/secure_payment_confirmation_views_util.h"
#include "components/constrained_window/constrained_window_views.h"
#include "components/payments/content/payment_ui_observer.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/views/border.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/layout/grid_layout.h"
#include "ui/views/layout/layout_provider.h"

namespace payments {

// static
base::WeakPtr<SecurePaymentConfirmationNoCredsView>
SecurePaymentConfirmationNoCredsView::Create() {
// On desktop, the SecurePaymentConfirmationNoCredsView object is memory
// managed by the views:: machinery. It is deleted when the window is closed
// and views::DialogDelegateView::DeleteDelegate() is called by its
// corresponding views::Widget.
return (new SecurePaymentConfirmationNoCredsDialogView(
/*observer_for_test=*/nullptr))
->GetWeakPtr();
}

SecurePaymentConfirmationNoCredsDialogView::
SecurePaymentConfirmationNoCredsDialogView(
ObserverForTest* observer_for_test)
: observer_for_test_(observer_for_test) {}
SecurePaymentConfirmationNoCredsDialogView::
~SecurePaymentConfirmationNoCredsDialogView() = default;

void SecurePaymentConfirmationNoCredsDialogView::ShowDialog(
content::WebContents* web_contents,
const std::u16string& no_creds_text,
ResponseCallback response_callback) {
set_fixed_width(views::LayoutProvider::Get()->GetDistanceMetric(
views::DISTANCE_MODAL_DIALOG_PREFERRED_WIDTH));

SetButtons(ui::DIALOG_BUTTON_OK);
SetDefaultButton(ui::DIALOG_BUTTON_OK);

InitChildViews(no_creds_text);

SetAccessibleTitle(no_creds_text);

response_callback_ = std::move(response_callback);

SetAcceptCallback(base::BindOnce(
&SecurePaymentConfirmationNoCredsDialogView::OnDialogClosed,
weak_ptr_factory_.GetWeakPtr()));

SetModalType(ui::MODAL_TYPE_CHILD);

constrained_window::ShowWebModalDialogViews(this, web_contents);

// observer_for_test_ is used in views browsertests.
if (observer_for_test_)
observer_for_test_->OnDialogOpened();
}

void SecurePaymentConfirmationNoCredsDialogView::HideDialog() {
if (GetWidget())
GetWidget()->Close();
}

bool SecurePaymentConfirmationNoCredsDialogView::ShouldShowCloseButton() const {
return false;
}

base::WeakPtr<SecurePaymentConfirmationNoCredsDialogView>
SecurePaymentConfirmationNoCredsDialogView::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}

void SecurePaymentConfirmationNoCredsDialogView::OnDialogClosed() {
std::move(response_callback_).Run();
HideDialog();

if (observer_for_test_)
observer_for_test_->OnDialogClosed();
}

void SecurePaymentConfirmationNoCredsDialogView::InitChildViews(
const std::u16string& no_creds_text) {
RemoveAllChildViews(true);

SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kVertical, gfx::Insets(), 0));

AddChildView(CreateSecurePaymentConfirmationHeaderView(
static_cast<int>(DialogViewID::PROGRESS_BAR),
static_cast<int>(DialogViewID::HEADER_IMAGE), /*use_cart_image=*/true));

AddChildView(CreateBodyView(no_creds_text));

InvalidateLayout();
}

// Creates the body.
// +------------------------------------------+
// | [header image] |
// | |
// | No matching credentials text |
// | [OK] |
// +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
std::unique_ptr<views::View>
SecurePaymentConfirmationNoCredsDialogView::CreateBodyView(
const std::u16string& no_creds_text) {
std::unique_ptr<views::Label> no_matching_creds_view =
std::make_unique<views::Label>(no_creds_text,
views::style::CONTEXT_DIALOG_BODY_TEXT,
views::style::STYLE_PRIMARY);
no_matching_creds_view->SetMultiLine(true);
no_matching_creds_view->SetLineHeight(kDescriptionLineHeight);
no_matching_creds_view->SetHorizontalAlignment(gfx::ALIGN_TO_HEAD);
no_matching_creds_view->SetAllowCharacterBreak(true);
no_matching_creds_view->SetID(
static_cast<int>(DialogViewID::NO_MATCHING_CREDS_TEXT));
no_matching_creds_view->SetBorder(
views::CreateEmptyBorder(gfx::Insets(kBodyExtraInset)));

return no_matching_creds_view;
}

BEGIN_METADATA(SecurePaymentConfirmationNoCredsDialogView,
views::DialogDelegateView)
END_METADATA

} // namespace payments
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// 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.

#ifndef CHROME_BROWSER_UI_VIEWS_PAYMENTS_SECURE_PAYMENT_CONFIRMATION_NO_CREDS_DIALOG_VIEW_H_
#define CHROME_BROWSER_UI_VIEWS_PAYMENTS_SECURE_PAYMENT_CONFIRMATION_NO_CREDS_DIALOG_VIEW_H_

#include "base/memory/weak_ptr.h"
#include "components/payments/content/secure_payment_confirmation_no_creds_view.h"
#include "ui/views/window/dialog_delegate.h"

namespace payments {

// Draws the user interface in the secure payment confirmation no matching
// credentials flow.
class SecurePaymentConfirmationNoCredsDialogView
: public SecurePaymentConfirmationNoCredsView,
public views::DialogDelegateView {
public:
METADATA_HEADER(SecurePaymentConfirmationNoCredsDialogView);

class ObserverForTest {
public:
virtual void OnDialogOpened() = 0;
virtual void OnDialogClosed() = 0;
};

// IDs that identify a view within the secure payment confirmation no creds
// dialog. Used to validate views in browsertests.
enum class DialogViewID : int {
VIEW_ID_NONE = 0,
HEADER_IMAGE,
PROGRESS_BAR,
NO_MATCHING_CREDS_TEXT
};

explicit SecurePaymentConfirmationNoCredsDialogView(
ObserverForTest* observer_for_test);
~SecurePaymentConfirmationNoCredsDialogView() override;

SecurePaymentConfirmationNoCredsDialogView(
const SecurePaymentConfirmationNoCredsDialogView& other) = delete;
SecurePaymentConfirmationNoCredsDialogView& operator=(
const SecurePaymentConfirmationNoCredsDialogView& other) = delete;

// SecurePaymentConfirmationNoCredsView:
void ShowDialog(content::WebContents* web_contents,
const std::u16string& no_creds_text,
ResponseCallback response_callback) override;
void HideDialog() override;

// views::DialogDelegate:
bool ShouldShowCloseButton() const override;

base::WeakPtr<SecurePaymentConfirmationNoCredsDialogView> GetWeakPtr();

private:
void OnDialogClosed();

void InitChildViews(const std::u16string& no_creds_text);
std::unique_ptr<views::View> CreateBodyView(
const std::u16string& no_creds_text);

// May be null.
ObserverForTest* observer_for_test_ = nullptr;

ResponseCallback response_callback_;

base::WeakPtrFactory<SecurePaymentConfirmationNoCredsDialogView>
weak_ptr_factory_{this};
};

} // namespace payments

#endif // CHROME_BROWSER_UI_VIEWS_PAYMENTS_SECURE_PAYMENT_CONFIRMATION_NO_CREDS_DIALOG_VIEW_H_
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "chrome/app/vector_icons/vector_icons.h"
#include "chrome/browser/ui/views/accessibility/non_accessible_image_view.h"
#include "chrome/browser/ui/views/chrome_layout_provider.h"
#include "chrome/grit/theme_resources.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/compositor/layer.h"
Expand Down Expand Up @@ -38,13 +39,21 @@ int GetSecurePaymentConfirmationHeaderWidth() {
views::DISTANCE_MODAL_DIALOG_PREFERRED_WIDTH);
}

const gfx::ImageSkia GetHeaderImageSkia(bool dark_mode) {
return ui::ResourceBundle::GetSharedInstance()
.GetImageNamed(dark_mode ? IDR_SAVE_CARD_DARK : IDR_SAVE_CARD)
.AsImageSkia();
}

class SecurePaymentConfirmationIconView : public NonAccessibleImageView {
public:
METADATA_HEADER(SecurePaymentConfirmationIconView);

SecurePaymentConfirmationIconView() {
const gfx::Size header_size(GetSecurePaymentConfirmationHeaderWidth(),
kHeaderIconHeight);
explicit SecurePaymentConfirmationIconView(bool use_cart_image = false)
: use_cart_image_{use_cart_image} {
const gfx::Size header_size(
GetSecurePaymentConfirmationHeaderWidth(),
use_cart_image_ ? kShoppingCartHeaderIconHeight : kHeaderIconHeight);
SetSize(header_size);
SetPreferredSize(header_size);
SetVerticalAlignment(views::ImageView::Alignment::kLeading);
Expand All @@ -54,9 +63,14 @@ class SecurePaymentConfirmationIconView : public NonAccessibleImageView {
// NonAccessibleImageView:
void OnThemeChanged() override {
NonAccessibleImageView::OnThemeChanged();
SetImage(gfx::CreateVectorIcon(
GetPlatformVectorIcon(GetNativeTheme()->ShouldUseDarkColors())));
SetImage(use_cart_image_
? GetHeaderImageSkia(GetNativeTheme()->ShouldUseDarkColors())
: gfx::CreateVectorIcon(GetPlatformVectorIcon(
GetNativeTheme()->ShouldUseDarkColors())));
}

private:
bool use_cart_image_;
};

BEGIN_METADATA(SecurePaymentConfirmationIconView, NonAccessibleImageView)
Expand All @@ -79,7 +93,8 @@ CreateSecurePaymentConfirmationProgressBarView() {

std::unique_ptr<views::View> CreateSecurePaymentConfirmationHeaderView(
int progress_bar_id,
int header_icon_id) {
int header_icon_id,
bool use_cart_image) {
auto header = std::make_unique<views::View>();

views::GridLayout* layout =
Expand All @@ -98,8 +113,11 @@ std::unique_ptr<views::View> CreateSecurePaymentConfirmationHeaderView(
layout->AddPaddingRow(views::GridLayout::kFixedSize, kHeaderIconTopPadding);

// Header icon
layout->StartRow(views::GridLayout::kFixedSize, 0, kHeaderIconHeight);
auto image_view = std::make_unique<SecurePaymentConfirmationIconView>();
layout->StartRow(
views::GridLayout::kFixedSize, 0,
use_cart_image ? kShoppingCartHeaderIconHeight : kHeaderIconHeight);
auto image_view =
std::make_unique<SecurePaymentConfirmationIconView>(use_cart_image);
image_view->SetID(header_icon_id);
layout->AddView(std::move(image_view));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ class ImageView;

namespace payments {

// Height of the header icon.
// Height of the header icons.
constexpr int kHeaderIconHeight = 148;
constexpr int kShoppingCartHeaderIconHeight = 114;

// Padding above the header icon.
constexpr int kHeaderIconTopPadding = 12;
Expand Down Expand Up @@ -61,7 +62,8 @@ CreateSecurePaymentConfirmationProgressBarView();
// +------------------------------------------+
std::unique_ptr<views::View> CreateSecurePaymentConfirmationHeaderView(
int progress_bar_id,
int header_icon_id);
int header_icon_id,
bool use_cart_image = false);

// Creates the label view for the SPC title text.
std::unique_ptr<views::Label> CreateSecurePaymentConfirmationTitleLabel(
Expand Down
9 changes: 8 additions & 1 deletion components/payments/content/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ static_library("content") {
"secure_payment_confirmation_app_factory.h",
"secure_payment_confirmation_model.cc",
"secure_payment_confirmation_model.h",
"secure_payment_confirmation_no_creds.cc",
"secure_payment_confirmation_no_creds.h",
"secure_payment_confirmation_no_creds_view.cc",
"secure_payment_confirmation_no_creds_view.h",
"secure_payment_confirmation_view.h",
"service_worker_payment_app.cc",
"service_worker_payment_app.h",
Expand Down Expand Up @@ -110,7 +114,10 @@ static_library("content") {
}

if (is_android) {
sources += [ "secure_payment_confirmation_view_stub.cc" ]
sources += [
"secure_payment_confirmation_no_creds_view_stub.cc",
"secure_payment_confirmation_view_stub.cc",
]
} else {
sources += [
"content_payment_request_delegate.cc",
Expand Down
18 changes: 18 additions & 0 deletions components/payments/content/payment_request.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "components/payments/content/payment_details_converter.h"
#include "components/payments/content/payment_request_converter.h"
#include "components/payments/content/payment_request_web_contents_manager.h"
#include "components/payments/content/secure_payment_confirmation_no_creds.h"
#include "components/payments/core/can_make_payment_query.h"
#include "components/payments/core/error_message_util.h"
#include "components/payments/core/error_strings.h"
Expand Down Expand Up @@ -635,6 +636,23 @@ void PaymentRequest::AreRequestedMethodsSupportedCallback(
observer_for_testing_->OnAppListReady(weak_ptr_factory_.GetWeakPtr());
}

if (web_contents() && spec_->IsSecurePaymentConfirmationRequested() &&
state()->available_apps().empty() &&
base::FeatureList::IsEnabled(::features::kSecurePaymentConfirmation) &&
base::FeatureList::IsEnabled(
::features::kSecurePaymentConfirmationAPIV3)) {
std::unique_ptr<SecurePaymentConfirmationNoCreds> no_creds_ui =
SecurePaymentConfirmationNoCreds::Create();
no_creds_ui->ShowDialog(
web_contents(),
url_formatter::FormatUrlForSecurityDisplay(
state_->GetTopOrigin(),
url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC),
base::BindOnce(&PaymentRequest::OnUserCancelled,
weak_ptr_factory_.GetWeakPtr()));
return;
}

if (methods_supported) {
if (SatisfiesSkipUIConstraints()) {
Pay();
Expand Down

0 comments on commit 23ac3ba

Please sign in to comment.