Skip to content

Commit

Permalink
[PaymentRequest] Fix payments view accessibility visibility
Browse files Browse the repository at this point in the history
This ensures that invisible payments views are ignored in accessibility
contexts such as a screen reader. See the bug for more context, in
summary we used to rely on screen readers ignoring invisible elements,
which is no longer the case.

- Behind the PaymentHandlerMinimalHeaderUX feature, the finished
  progress bar which is used as a separator is set to ignored once it's
  done loading. The origin label is also set to accessibility focusable.
- The processing spinner, present and invisible on most payment sheets,
  is set to ignored when invisible.
- Hidden payment sheets, made invisible within a stack of payment sheet
  views used for animation, are set to ignored when invisible.

Bug: 1418659, 1420720
Change-Id: I54d43bf3de29b84941c6a0a906c41139df0e4cf6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4294863
Reviewed-by: Peter Kotwicz <pkotwicz@chromium.org>
Commit-Queue: Nick Burris <nburris@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1112179}
  • Loading branch information
nickburris authored and Chromium LUCI CQ committed Mar 2, 2023
1 parent 7c9d25c commit a73e70d
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 0 deletions.
Expand Up @@ -43,6 +43,7 @@
#include "ui/gfx/color_utils.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/background.h"
#include "ui/views/border.h"
#include "ui/views/controls/button/image_button.h"
Expand Down Expand Up @@ -393,6 +394,7 @@ void PaymentHandlerWebFlowViewController::PopulateSheetHeaderView(
origin, url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC)));
origin_label->SetElideBehavior(gfx::ELIDE_HEAD);
origin_label->SetID(static_cast<int>(DialogViewID::SHEET_TITLE));
origin_label->SetFocusBehavior(views::View::FocusBehavior::ACCESSIBLE_ONLY);
// Turn off autoreadability because the computed foreground color takes
// contrast into account.
SkColor background_color = container->background()->get_color();
Expand Down Expand Up @@ -567,6 +569,11 @@ void PaymentHandlerWebFlowViewController::LoadProgressChanged(double progress) {
// The progress bar reflects the load progress until it reaches 1.0, at
// which point it's reset to 0 to just show the separator color.
progress_bar_->SetValue(progress < 1.0 ? progress : 0);

// The progress bar is accessibility-visible while loading, and then ignored
// once it just serves as a separator.
progress_bar_->GetViewAccessibility().OverrideIsIgnored(progress == 1.0);
progress_bar_->GetViewAccessibility().OverrideIsLeaf(progress == 1.0);
} else {
progress_bar_->SetValue(progress);
const bool show_progress = progress < 1.0;
Expand Down
10 changes: 10 additions & 0 deletions chrome/browser/ui/views/payments/payment_request_dialog_view.cc
Expand Up @@ -36,6 +36,7 @@
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/color/color_id.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/background.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/box_layout.h"
Expand Down Expand Up @@ -136,6 +137,8 @@ void PaymentRequestDialogView::ShowErrorMessage() {
void PaymentRequestDialogView::ShowProcessingSpinner() {
throbber_->Start();
throbber_overlay_->SetVisible(true);
throbber_overlay_->GetViewAccessibility().OverrideIsIgnored(false);
throbber_overlay_->GetViewAccessibility().OverrideIsLeaf(false);
if (observer_for_testing_)
observer_for_testing_->OnProcessingSpinnerShown();
}
Expand Down Expand Up @@ -417,7 +420,14 @@ void PaymentRequestDialogView::EditorViewUpdated() {

void PaymentRequestDialogView::HideProcessingSpinner() {
throbber_->Stop();
// TODO(crbug.com/1418659): Instead of setting the throbber to invisible, can
// we destroy and remove it from the view when it's not being used?
throbber_overlay_->SetVisible(false);
// Screen readers do not ignore invisible elements, so force the screen
// reader to skip the invisible throbber by making it an ignored leaf node in
// the accessibility tree.
throbber_overlay_->GetViewAccessibility().OverrideIsIgnored(true);
throbber_overlay_->GetViewAccessibility().OverrideIsLeaf(true);
if (observer_for_testing_)
observer_for_testing_->OnProcessingSpinnerHidden();
}
Expand Down
Expand Up @@ -23,6 +23,7 @@
#include "ui/compositor/layer.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/background.h"
#include "ui/views/border.h"
#include "ui/views/controls/button/image_button.h"
Expand Down Expand Up @@ -127,6 +128,16 @@ class SheetView : public views::BoxLayoutView, public views::FocusTraversable {
first_focusable_ = nullptr;
}

void SetVisible(bool visible) override {
views::View::SetVisible(visible);

// Screen readers do not ignore invisible elements, so force the screen
// reader to skip invisible sheet views by making it an ignored leaf node in
// the accessibility tree.
GetViewAccessibility().OverrideIsIgnored(!visible);
GetViewAccessibility().OverrideIsLeaf(!visible);
}

raw_ptr<views::View> first_focusable_ = nullptr;
std::unique_ptr<views::FocusSearch> focus_search_ =
std::make_unique<views::FocusSearch>(/*root=*/this,
Expand Down
@@ -0,0 +1,119 @@
// Copyright 2023 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/payments/payment_request_browsertest_base.h"
#include "chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "content/public/test/browser_test.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/views/accessibility/view_accessibility.h"

namespace payments {

class PaymentRequestSheetControllerTest : public PaymentRequestBrowserTestBase {
public:
PaymentRequestSheetControllerTest() = default;
~PaymentRequestSheetControllerTest() override = default;
};

IN_PROC_BROWSER_TEST_F(PaymentRequestSheetControllerTest,
ProcessingSpinnerViewAccessibility) {
// Installs two apps so that the Payment Request UI will be shown.
std::string a_method_name;
InstallPaymentApp("a.com", "/payment_request_success_responder.js",
&a_method_name);
std::string b_method_name;
InstallPaymentApp("b.com", "/payment_request_success_responder.js",
&b_method_name);

NavigateTo("/payment_request_retry_with_payer_errors.html");
autofill::AutofillProfile contact = autofill::test::GetFullProfile();
AddAutofillProfile(contact);

InvokePaymentRequestUIWithJs(
content::JsReplace("buyWithMethods([{supportedMethods:$1}"
", {supportedMethods:$2}]);",
a_method_name, b_method_name));

// Click on pay.
EXPECT_TRUE(IsPayButtonEnabled());
ResetEventWaiterForSequence({DialogEvent::PROCESSING_SPINNER_SHOWN});
ClickOnDialogViewAndWait(DialogViewID::PAY_BUTTON, dialog_view());

EXPECT_TRUE(dialog_view()->throbber_overlay_for_testing()->GetVisible());
EXPECT_FALSE(dialog_view()
->throbber_overlay_for_testing()
->GetViewAccessibility()
.IsIgnored());
EXPECT_FALSE(dialog_view()
->throbber_overlay_for_testing()
->GetViewAccessibility()
.IsLeaf());

// Wait for the response to settle.
ASSERT_TRUE(
content::ExecJs(GetActiveWebContents(), "processShowResponse();"));

// Call retry to finish the dialog loading state and hide the spinner.
ResetEventWaiterForSequence({DialogEvent::PROCESSING_SPINNER_HIDDEN,
DialogEvent::SPEC_DONE_UPDATING,
DialogEvent::PROCESSING_SPINNER_HIDDEN,
DialogEvent::BACK_TO_PAYMENT_SHEET_NAVIGATION,
DialogEvent::CONTACT_INFO_EDITOR_OPENED});
ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(),
"retry({"
" payer: {"
" email: 'EMAIL ERROR',"
" name: 'NAME ERROR',"
" phone: 'PHONE ERROR'"
" }"
"});"));
WaitForObservedEvent();

EXPECT_FALSE(dialog_view()->throbber_overlay_for_testing()->GetVisible());
EXPECT_TRUE(dialog_view()
->throbber_overlay_for_testing()
->GetViewAccessibility()
.IsIgnored());
EXPECT_TRUE(dialog_view()
->throbber_overlay_for_testing()
->GetViewAccessibility()
.IsLeaf());
}

IN_PROC_BROWSER_TEST_F(PaymentRequestSheetControllerTest,
HiddenSheetViewAccessibility) {
// Installs two apps so that the Payment Request UI will be shown.
std::string a_method_name;
InstallPaymentApp("a.com", "/payment_request_success_responder.js",
&a_method_name);
std::string b_method_name;
InstallPaymentApp("b.com", "/payment_request_success_responder.js",
&b_method_name);

NavigateTo("/payment_request_contact_details_test.html");
InvokePaymentRequestUIWithJs(
content::JsReplace("buyWithMethods([{supportedMethods:$1}"
", {supportedMethods:$2}]);",
a_method_name, b_method_name));

// Expect that the payment request view is accessibility visible.
views::View* payment_request_view =
GetByDialogViewID(DialogViewID::PAYMENT_REQUEST_SHEET);
EXPECT_FALSE(payment_request_view->GetViewAccessibility().IsIgnored());
EXPECT_FALSE(payment_request_view->GetViewAccessibility().IsLeaf());

OpenContactInfoEditorScreen();

// Expect that the now hidden payment request view is not accessibility
// visible, and that the contact info view is.
EXPECT_TRUE(payment_request_view->GetViewAccessibility().IsIgnored());
EXPECT_TRUE(payment_request_view->GetViewAccessibility().IsLeaf());
views::View* contact_info_view =
GetByDialogViewID(DialogViewID::CONTACT_INFO_EDITOR_SHEET);
EXPECT_FALSE(contact_info_view->GetViewAccessibility().IsIgnored());
EXPECT_FALSE(contact_info_view->GetViewAccessibility().IsLeaf());
}

} // namespace payments
1 change: 1 addition & 0 deletions chrome/test/BUILD.gn
Expand Up @@ -3523,6 +3523,7 @@ if (!is_android) {
"../browser/ui/views/payments/payment_request_payment_app_browsertest.cc",
"../browser/ui/views/payments/payment_request_payment_response_browsertest.cc",
"../browser/ui/views/payments/payment_request_retry_browsertest.cc",
"../browser/ui/views/payments/payment_request_sheet_controller_browsertest.cc",
"../browser/ui/views/payments/payment_request_shipping_address_instance_browsertest.cc",
"../browser/ui/views/payments/payment_request_show_promise_browsertest.cc",
"../browser/ui/views/payments/payment_request_update_with_browsertest.cc",
Expand Down

0 comments on commit a73e70d

Please sign in to comment.