Commit 9f1c196b authored by Dana Fried's avatar Dana Fried Committed by Commit Bot

Fix accessibility of TabbedPane

Previous to this change, neither the tabbed pane itself nor its contents
pane would report a meaningful accessible name/title. When using
accessible keyboard navigation (tab, arrows) to navigate a dialog that
had a tabbed pane (such as the site cookies dialog), when entering the
tabbed pane a screen reader user would simply hear "tabbed pane", and
when using the arrow keys to select the tab, the user would hear the
(unspecified) accessible title of the pane view inside the tab, which
was usually just "pane" or nothing at all.

This CL makes the following changes:
 - the title of the entire TabbedPane now reflects the currently active
   tab title
 - by default, the contents pane of each tab is assigned the same
   accessible name/title and role as the tab (it can be overridden later
   if necessary)

Now, for example, when using NVDA, when the user first enters the
cookies dialog, they hear: "allowed tab control". When navigating
between tabs using the arrow keys, they will continue to hear "allowed
tab" and "blocked tab" as they switch back and forth.

Bug: 962966
Change-Id: I805281bf5429e03ca77f98e167041a5df3cbee8c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1717228Reviewed-by: default avatarAllen Bauer <kylixrd@chromium.org>
Commit-Queue: Dana Fried <dfried@chromium.org>
Cr-Commit-Position: refs/heads/master@{#680630}
parent 1977a058
......@@ -750,6 +750,7 @@ void TabbedPane::AddTabInternal(size_t index,
std::unique_ptr<View> contents) {
DCHECK_LE(index, GetTabCount());
contents->SetVisible(false);
contents->GetViewAccessibility().OverrideName(title);
tab_strip_->AddChildViewAt(
std::make_unique<MdTab>(this, title, contents.get()),
......@@ -864,6 +865,9 @@ bool TabbedPane::AcceleratorPressed(const ui::Accelerator& accelerator) {
void TabbedPane::GetAccessibleNodeData(ui::AXNodeData* node_data) {
node_data->role = ax::mojom::Role::kTabList;
const Tab* const selected_tab = GetSelectedTab();
if (selected_tab)
node_data->SetName(selected_tab->GetTitleText());
}
BEGIN_METADATA(TabbedPane)
......
......@@ -13,6 +13,7 @@
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/events/keycodes/keyboard_code_conversion.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/test/test_views.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/widget.h"
......@@ -27,6 +28,12 @@ base::string16 DefaultTabTitle() {
return ASCIIToUTF16("tab");
}
base::string16 GetAccessibleName(View* view) {
ui::AXNodeData ax_node_data;
view->GetViewAccessibility().GetAccessibleNodeData(&ax_node_data);
return ax_node_data.GetString16Attribute(ax::mojom::StringAttribute::kName);
}
} // namespace
class TabbedPaneTest : public ViewsTestBase {
......@@ -37,6 +44,21 @@ class TabbedPaneTest : public ViewsTestBase {
ViewsTestBase::SetUp();
tabbed_pane_ = std::make_unique<TabbedPane>();
tabbed_pane_->set_owned_by_client();
// Create a widget so that accessibility data will be returned correctly.
widget_ = std::make_unique<Widget>();
Widget::InitParams params =
CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.bounds = gfx::Rect(0, 0, 650, 650);
widget_->Init(params);
widget_->SetContentsView(tabbed_pane_.get());
}
void TearDown() override {
tabbed_pane_.reset();
widget_.reset();
ViewsTestBase::TearDown();
}
protected:
......@@ -60,6 +82,7 @@ class TabbedPaneTest : public ViewsTestBase {
ui::UsLayoutKeyboardCodeToDomCode(keyboard_code), 0));
}
std::unique_ptr<Widget> widget_;
std::unique_ptr<TabbedPane> tabbed_pane_;
private:
......@@ -250,5 +273,26 @@ TEST_F(TabbedPaneTest, SelectTabWithAccessibleAction) {
widget->CloseNow();
}
TEST_F(TabbedPaneTest, AccessiblePaneTitleTracksActiveTabTitle) {
const base::string16 kFirstTitle = ASCIIToUTF16("Tab1");
const base::string16 kSecondTitle = ASCIIToUTF16("Tab2");
tabbed_pane_->AddTab(kFirstTitle, std::make_unique<View>());
tabbed_pane_->AddTab(kSecondTitle, std::make_unique<View>());
EXPECT_EQ(kFirstTitle, GetAccessibleName(tabbed_pane_.get()));
tabbed_pane_->SelectTabAt(1);
EXPECT_EQ(kSecondTitle, GetAccessibleName(tabbed_pane_.get()));
}
TEST_F(TabbedPaneTest, AccessiblePaneContentsTitleTracksTabTitle) {
const base::string16 kFirstTitle = ASCIIToUTF16("Tab1");
const base::string16 kSecondTitle = ASCIIToUTF16("Tab2");
View* const tab1_contents =
tabbed_pane_->AddTab(kFirstTitle, std::make_unique<View>());
View* const tab2_contents =
tabbed_pane_->AddTab(kSecondTitle, std::make_unique<View>());
EXPECT_EQ(kFirstTitle, GetAccessibleName(tab1_contents));
EXPECT_EQ(kSecondTitle, GetAccessibleName(tab2_contents));
}
} // namespace test
} // namespace views
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