Commit f232bf32 authored by Dana Fried's avatar Dana Fried Committed by Commit Bot

Add screen reader support for 'New' feature badging.

See go/newlabel for more information.

This CL adds "this is a new feature" to
the text read by the screen reader, after the hotkey but before the
"item M of N" description.

So for example, a tab context menu item might look like this:
  ...
  Add tab to Read Later [New]     CTRL+SHIFT+Z
  Move tab to new group [New]
  ...

As you scroll through, you will hear:
  "Add tab to read later, control plus shift plus Z, this is a new
   feature, item 4 of 7"
  "Move tab to new group, this is a new feature, item 5 of 7"

Note: The screenshot in the associated png file is of the visual presentation
of the badge, as the actual text read does not appear on-screen.

Bug: 1114082
Change-Id: I758d0b6cb92856e62bde87f9cd55553feb281b3d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2343008Reviewed-by: default avatarPeter Boström <pbos@chromium.org>
Commit-Queue: Dana Fried <dfried@chromium.org>
Cr-Commit-Position: refs/heads/master@{#796157}
parent 2e8f2b9d
...@@ -115,7 +115,7 @@ bool IsRecentTabsCommand(int command_id) { ...@@ -115,7 +115,7 @@ bool IsRecentTabsCommand(int command_id) {
class FullscreenButton : public ImageButton { class FullscreenButton : public ImageButton {
public: public:
explicit FullscreenButton(views::ButtonListener* listener) explicit FullscreenButton(views::ButtonListener* listener)
: ImageButton(listener) { } : ImageButton(listener) {}
FullscreenButton(const FullscreenButton&) = delete; FullscreenButton(const FullscreenButton&) = delete;
FullscreenButton& operator=(const FullscreenButton&) = delete; FullscreenButton& operator=(const FullscreenButton&) = delete;
...@@ -219,13 +219,13 @@ base::string16 GetAccessibleNameForAppMenuItem(ButtonMenuItemModel* model, ...@@ -219,13 +219,13 @@ base::string16 GetAccessibleNameForAppMenuItem(ButtonMenuItemModel* model,
ui::Accelerator menu_accelerator; ui::Accelerator menu_accelerator;
if (add_accelerator_text && if (add_accelerator_text &&
model->GetAcceleratorAt(item_index, &menu_accelerator)) { model->GetAcceleratorAt(item_index, &menu_accelerator)) {
accelerator_text = accelerator_text = ui::Accelerator(menu_accelerator.key_code(),
ui::Accelerator(menu_accelerator.key_code(), menu_accelerator.modifiers())
menu_accelerator.modifiers()).GetShortcutText(); .GetShortcutText();
} }
return MenuItemView::GetAccessibleNameForMenuItem( return MenuItemView::GetAccessibleNameForMenuItem(accessible_name,
accessible_name, accelerator_text); accelerator_text, false);
} }
// A button that lives inside a menu item. // A button that lives inside a menu item.
...@@ -402,7 +402,6 @@ class AppMenu::CutCopyPasteView : public AppMenuView { ...@@ -402,7 +402,6 @@ class AppMenu::CutCopyPasteView : public AppMenuView {
// ZoomView -------------------------------------------------------------------- // ZoomView --------------------------------------------------------------------
// ZoomView contains the various zoom controls: two buttons to increase/decrease // ZoomView contains the various zoom controls: two buttons to increase/decrease
// the zoom, a label showing the current zoom percent, and a button to go // the zoom, a label showing the current zoom percent, and a button to go
// full-screen. // full-screen.
...@@ -556,9 +555,8 @@ class AppMenu::ZoomView : public AppMenuView { ...@@ -556,9 +555,8 @@ class AppMenu::ZoomView : public AppMenuView {
private: private:
content::WebContents* GetActiveWebContents() const { content::WebContents* GetActiveWebContents() const {
return menu() ? return menu() ? menu()->browser_->tab_strip_model()->GetActiveWebContents()
menu()->browser_->tab_strip_model()->GetActiveWebContents() : : nullptr;
nullptr;
} }
void OnZoomLevelChanged(const content::HostZoomMap::ZoomLevelChange& change) { void OnZoomLevelChanged(const content::HostZoomMap::ZoomLevelChange& change) {
...@@ -572,10 +570,8 @@ class AppMenu::ZoomView : public AppMenuView { ...@@ -572,10 +570,8 @@ class AppMenu::ZoomView : public AppMenuView {
auto* zoom_controller = zoom::ZoomController::FromWebContents(contents); auto* zoom_controller = zoom::ZoomController::FromWebContents(contents);
if (zoom_controller) if (zoom_controller)
zoom = zoom_controller->GetZoomPercent(); zoom = zoom_controller->GetZoomPercent();
increment_button_->SetEnabled(zoom < increment_button_->SetEnabled(zoom < contents->GetMaximumZoomPercent());
contents->GetMaximumZoomPercent()); decrement_button_->SetEnabled(zoom > contents->GetMinimumZoomPercent());
decrement_button_->SetEnabled(zoom >
contents->GetMinimumZoomPercent());
} }
zoom_label_->SetText(base::FormatPercent(zoom)); zoom_label_->SetText(base::FormatPercent(zoom));
// An alert notification will ensure that the zoom label is always announced // An alert notification will ensure that the zoom label is always announced
...@@ -790,15 +786,16 @@ void AppMenu::GetLabelStyle(int command_id, LabelStyle* style) const { ...@@ -790,15 +786,16 @@ void AppMenu::GetLabelStyle(int command_id, LabelStyle* style) const {
base::string16 AppMenu::GetTooltipText(int command_id, base::string16 AppMenu::GetTooltipText(int command_id,
const gfx::Point& p) const { const gfx::Point& p) const {
return IsBookmarkCommand(command_id) ? return IsBookmarkCommand(command_id)
bookmark_menu_delegate_->GetTooltipText(command_id, p) : base::string16(); ? bookmark_menu_delegate_->GetTooltipText(command_id, p)
: base::string16();
} }
bool AppMenu::IsTriggerableEvent(views::MenuItemView* menu, bool AppMenu::IsTriggerableEvent(views::MenuItemView* menu,
const ui::Event& e) { const ui::Event& e) {
return IsBookmarkCommand(menu->GetCommand()) ? return IsBookmarkCommand(menu->GetCommand())
bookmark_menu_delegate_->IsTriggerableEvent(menu, e) : ? bookmark_menu_delegate_->IsTriggerableEvent(menu, e)
MenuDelegate::IsTriggerableEvent(menu, e); : MenuDelegate::IsTriggerableEvent(menu, e);
} }
bool AppMenu::GetDropFormats(MenuItemView* menu, bool AppMenu::GetDropFormats(MenuItemView* menu,
...@@ -806,27 +803,27 @@ bool AppMenu::GetDropFormats(MenuItemView* menu, ...@@ -806,27 +803,27 @@ bool AppMenu::GetDropFormats(MenuItemView* menu,
std::set<ui::ClipboardFormatType>* format_types) { std::set<ui::ClipboardFormatType>* format_types) {
CreateBookmarkMenu(); CreateBookmarkMenu();
return bookmark_menu_delegate_.get() && return bookmark_menu_delegate_.get() &&
bookmark_menu_delegate_->GetDropFormats(menu, formats, format_types); bookmark_menu_delegate_->GetDropFormats(menu, formats, format_types);
} }
bool AppMenu::AreDropTypesRequired(MenuItemView* menu) { bool AppMenu::AreDropTypesRequired(MenuItemView* menu) {
CreateBookmarkMenu(); CreateBookmarkMenu();
return bookmark_menu_delegate_.get() && return bookmark_menu_delegate_.get() &&
bookmark_menu_delegate_->AreDropTypesRequired(menu); bookmark_menu_delegate_->AreDropTypesRequired(menu);
} }
bool AppMenu::CanDrop(MenuItemView* menu, const ui::OSExchangeData& data) { bool AppMenu::CanDrop(MenuItemView* menu, const ui::OSExchangeData& data) {
CreateBookmarkMenu(); CreateBookmarkMenu();
return bookmark_menu_delegate_.get() && return bookmark_menu_delegate_.get() &&
bookmark_menu_delegate_->CanDrop(menu, data); bookmark_menu_delegate_->CanDrop(menu, data);
} }
int AppMenu::GetDropOperation(MenuItemView* item, int AppMenu::GetDropOperation(MenuItemView* item,
const ui::DropTargetEvent& event, const ui::DropTargetEvent& event,
DropPosition* position) { DropPosition* position) {
return IsBookmarkCommand(item->GetCommand()) ? return IsBookmarkCommand(item->GetCommand())
bookmark_menu_delegate_->GetDropOperation(item, event, position) : ? bookmark_menu_delegate_->GetDropOperation(item, event, position)
ui::DragDropTypes::DRAG_NONE; : ui::DragDropTypes::DRAG_NONE;
} }
int AppMenu::OnPerformDrop(MenuItemView* menu, int AppMenu::OnPerformDrop(MenuItemView* menu,
...@@ -843,15 +840,16 @@ bool AppMenu::ShowContextMenu(MenuItemView* source, ...@@ -843,15 +840,16 @@ bool AppMenu::ShowContextMenu(MenuItemView* source,
int command_id, int command_id,
const gfx::Point& p, const gfx::Point& p,
ui::MenuSourceType source_type) { ui::MenuSourceType source_type) {
return IsBookmarkCommand(command_id) ? return IsBookmarkCommand(command_id)
bookmark_menu_delegate_->ShowContextMenu(source, command_id, p, ? bookmark_menu_delegate_->ShowContextMenu(source, command_id, p,
source_type) : source_type)
false; : false;
} }
bool AppMenu::CanDrag(MenuItemView* menu) { bool AppMenu::CanDrag(MenuItemView* menu) {
return IsBookmarkCommand(menu->GetCommand()) ? return IsBookmarkCommand(menu->GetCommand())
bookmark_menu_delegate_->CanDrag(menu) : false; ? bookmark_menu_delegate_->CanDrag(menu)
: false;
} }
void AppMenu::WriteDragData(MenuItemView* sender, ui::OSExchangeData* data) { void AppMenu::WriteDragData(MenuItemView* sender, ui::OSExchangeData* data) {
...@@ -860,9 +858,9 @@ void AppMenu::WriteDragData(MenuItemView* sender, ui::OSExchangeData* data) { ...@@ -860,9 +858,9 @@ void AppMenu::WriteDragData(MenuItemView* sender, ui::OSExchangeData* data) {
} }
int AppMenu::GetDragOperations(MenuItemView* sender) { int AppMenu::GetDragOperations(MenuItemView* sender) {
return IsBookmarkCommand(sender->GetCommand()) ? return IsBookmarkCommand(sender->GetCommand())
bookmark_menu_delegate_->GetDragOperations(sender) : ? bookmark_menu_delegate_->GetDragOperations(sender)
MenuDelegate::GetDragOperations(sender); : MenuDelegate::GetDragOperations(sender);
} }
int AppMenu::GetMaxWidthForMenu(MenuItemView* menu) { int AppMenu::GetMaxWidthForMenu(MenuItemView* menu) {
...@@ -905,7 +903,7 @@ bool AppMenu::IsCommandEnabled(int command_id) const { ...@@ -905,7 +903,7 @@ bool AppMenu::IsCommandEnabled(int command_id) const {
void AppMenu::ExecuteCommand(int command_id, int mouse_event_flags) { void AppMenu::ExecuteCommand(int command_id, int mouse_event_flags) {
if (IsBookmarkCommand(command_id)) { if (IsBookmarkCommand(command_id)) {
UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.OpenBookmark", UMA_HISTOGRAM_MEDIUM_TIMES("WrenchMenu.TimeToAction.OpenBookmark",
menu_opened_timer_.Elapsed()); menu_opened_timer_.Elapsed());
UMA_HISTOGRAM_ENUMERATION("WrenchMenu.MenuAction", UMA_HISTOGRAM_ENUMERATION("WrenchMenu.MenuAction",
MENU_ACTION_BOOKMARK_OPEN, LIMIT_MENU_ACTION); MENU_ACTION_BOOKMARK_OPEN, LIMIT_MENU_ACTION);
bookmark_menu_delegate_->ExecuteCommand(command_id, mouse_event_flags); bookmark_menu_delegate_->ExecuteCommand(command_id, mouse_event_flags);
...@@ -963,8 +961,8 @@ void AppMenu::WillHideMenu(MenuItemView* menu) { ...@@ -963,8 +961,8 @@ void AppMenu::WillHideMenu(MenuItemView* menu) {
// It's okay to just turn off the animation and not turn it back on because // It's okay to just turn off the animation and not turn it back on because
// the menu widget will be recreated next time it's opened. See // the menu widget will be recreated next time it's opened. See
// ToolbarView::RunMenu() and Init() of this class. // ToolbarView::RunMenu() and Init() of this class.
menu->GetSubmenu()->GetWidget()-> menu->GetSubmenu()->GetWidget()->SetVisibilityChangedAnimationsEnabled(
SetVisibilityChangedAnimationsEnabled(false); false);
} }
} }
...@@ -1080,9 +1078,8 @@ void AppMenu::PopulateMenu(MenuItemView* parent, MenuModel* model) { ...@@ -1080,9 +1078,8 @@ void AppMenu::PopulateMenu(MenuItemView* parent, MenuModel* model) {
case IDC_RECENT_TABS_MENU: case IDC_RECENT_TABS_MENU:
DCHECK(!recent_tabs_menu_model_delegate_.get()); DCHECK(!recent_tabs_menu_model_delegate_.get());
recent_tabs_menu_model_delegate_.reset( recent_tabs_menu_model_delegate_.reset(new RecentTabsMenuModelDelegate(
new RecentTabsMenuModelDelegate(this, model->GetSubmenuModelAt(i), this, model->GetSubmenuModelAt(i), item));
item));
break; break;
default: default:
...@@ -1164,10 +1161,8 @@ void AppMenu::CreateBookmarkMenu() { ...@@ -1164,10 +1161,8 @@ void AppMenu::CreateBookmarkMenu() {
browser_->window()->GetNativeWindow()); browser_->window()->GetNativeWindow());
bookmark_menu_delegate_.reset( bookmark_menu_delegate_.reset(
new BookmarkMenuDelegate(browser_, browser_, parent)); new BookmarkMenuDelegate(browser_, browser_, parent));
bookmark_menu_delegate_->Init(this, bookmark_menu_delegate_->Init(this, bookmark_menu_,
bookmark_menu_, model->bookmark_bar_node(), 0,
model->bookmark_bar_node(),
0,
BookmarkMenuDelegate::SHOW_PERMANENT_FOLDERS, BookmarkMenuDelegate::SHOW_PERMANENT_FOLDERS,
BOOKMARK_LAUNCH_LOCATION_APP_MENU); BOOKMARK_LAUNCH_LOCATION_APP_MENU);
} }
......
...@@ -384,6 +384,10 @@ need to be translated for each locale.--> ...@@ -384,6 +384,10 @@ need to be translated for each locale.-->
<message name="IDS_MENU_ITEM_NEW_BADGE" desc="Appears as a badge on menu items denoting new features"> <message name="IDS_MENU_ITEM_NEW_BADGE" desc="Appears as a badge on menu items denoting new features">
New New
</message> </message>
<message name="IDS_MENU_ITEM_NEW_BADGE_SCREEN_READER_MESSAGE"
desc="Message appended to screen reader description of menu items which have the 'New' badge">
This is a new feature
</message>
<!-- General application strings --> <!-- General application strings -->
<message name="IDS_SENTENCE_END" desc="The symbol that is used to end a sentence."> <message name="IDS_SENTENCE_END" desc="The symbol that is used to end a sentence.">
......
c88f3adea4b633341c30b3220292ae3cfa4dd50f
\ No newline at end of file
...@@ -219,7 +219,8 @@ void MenuItemView::GetAccessibleNodeData(ui::AXNodeData* node_data) { ...@@ -219,7 +219,8 @@ void MenuItemView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
} else { } else {
item_text = title_; item_text = title_;
} }
node_data->SetName(GetAccessibleNameForMenuItem(item_text, GetMinorText())); node_data->SetName(GetAccessibleNameForMenuItem(item_text, GetMinorText(),
ShouldShowNewBadge()));
switch (type_) { switch (type_) {
case Type::kSubMenu: case Type::kSubMenu:
...@@ -276,7 +277,8 @@ bool MenuItemView::IsBubble(MenuAnchorPosition anchor) { ...@@ -276,7 +277,8 @@ bool MenuItemView::IsBubble(MenuAnchorPosition anchor) {
// static // static
base::string16 MenuItemView::GetAccessibleNameForMenuItem( base::string16 MenuItemView::GetAccessibleNameForMenuItem(
const base::string16& item_text, const base::string16& item_text,
const base::string16& minor_text) { const base::string16& minor_text,
bool is_new_feature) {
base::string16 accessible_name = item_text; base::string16 accessible_name = item_text;
// Filter out the "&" for accessibility clients. // Filter out the "&" for accessibility clients.
...@@ -298,6 +300,12 @@ base::string16 MenuItemView::GetAccessibleNameForMenuItem( ...@@ -298,6 +300,12 @@ base::string16 MenuItemView::GetAccessibleNameForMenuItem(
accessible_name.append(minor_text); accessible_name.append(minor_text);
} }
if (is_new_feature) {
accessible_name.push_back(' ');
accessible_name.append(l10n_util::GetStringUTF16(
IDS_MENU_ITEM_NEW_BADGE_SCREEN_READER_MESSAGE));
}
return accessible_name; return accessible_name;
} }
...@@ -762,6 +770,12 @@ void MenuItemView::SetAlerted() { ...@@ -762,6 +770,12 @@ void MenuItemView::SetAlerted() {
SchedulePaint(); SchedulePaint();
} }
bool MenuItemView::ShouldShowNewBadge() const {
static const bool feature_enabled =
base::FeatureList::IsEnabled(features::kEnableNewBadgeOnMenuItems);
return feature_enabled && is_new_;
}
MenuItemView::MenuItemView(MenuItemView* parent, MenuItemView::MenuItemView(MenuItemView* parent,
int command, int command,
MenuItemView::Type type) { MenuItemView::Type type) {
...@@ -1454,12 +1468,6 @@ bool MenuItemView::HasChecksOrRadioButtons() const { ...@@ -1454,12 +1468,6 @@ bool MenuItemView::HasChecksOrRadioButtons() const {
[](const auto* item) { return item->HasChecksOrRadioButtons(); }); [](const auto* item) { return item->HasChecksOrRadioButtons(); });
} }
bool MenuItemView::ShouldShowNewBadge() const {
static const bool feature_enabled =
base::FeatureList::IsEnabled(features::kEnableNewBadgeOnMenuItems);
return feature_enabled && is_new_;
}
BEGIN_METADATA(MenuItemView) BEGIN_METADATA(MenuItemView)
METADATA_PARENT_CLASS(View) METADATA_PARENT_CLASS(View)
END_METADATA() END_METADATA()
......
...@@ -138,7 +138,8 @@ class VIEWS_EXPORT MenuItemView : public View { ...@@ -138,7 +138,8 @@ class VIEWS_EXPORT MenuItemView : public View {
// removed and the menu item accelerator text is appended. // removed and the menu item accelerator text is appended.
static base::string16 GetAccessibleNameForMenuItem( static base::string16 GetAccessibleNameForMenuItem(
const base::string16& item_text, const base::string16& item_text,
const base::string16& accelerator_text); const base::string16& accelerator_text,
bool is_new_feature);
// Hides and cancels the menu. This does nothing if the menu is not open. // Hides and cancels the menu. This does nothing if the menu is not open.
void Cancel(); void Cancel();
...@@ -353,6 +354,10 @@ class VIEWS_EXPORT MenuItemView : public View { ...@@ -353,6 +354,10 @@ class VIEWS_EXPORT MenuItemView : public View {
void SetAlerted(); void SetAlerted();
bool is_alerted() const { return is_alerted_; } bool is_alerted() const { return is_alerted_; }
// Returns whether or not a "new" badge should be shown on this menu item.
// Takes into account whether the badging feature is enabled.
bool ShouldShowNewBadge() const;
protected: protected:
// Creates a MenuItemView. This is used by the various AddXXX methods. // Creates a MenuItemView. This is used by the various AddXXX methods.
MenuItemView(MenuItemView* parent, int command, Type type); MenuItemView(MenuItemView* parent, int command, Type type);
...@@ -491,10 +496,6 @@ class VIEWS_EXPORT MenuItemView : public View { ...@@ -491,10 +496,6 @@ class VIEWS_EXPORT MenuItemView : public View {
// Returns true if the menu has items with a checkbox or a radio button. // Returns true if the menu has items with a checkbox or a radio button.
bool HasChecksOrRadioButtons() const; bool HasChecksOrRadioButtons() const;
// Returns whether or not a "new" badge should be shown on this menu item.
// Takes into account whether the badging feature is enabled.
bool ShouldShowNewBadge() const;
void invalidate_dimensions() { dimensions_.height = 0; } void invalidate_dimensions() { dimensions_.height = 0; }
bool is_dimensions_valid() const { return dimensions_.height > 0; } bool is_dimensions_valid() const { return dimensions_.height > 0; }
......
...@@ -373,8 +373,9 @@ void SubmenuView::SetSelectedRow(int row) { ...@@ -373,8 +373,9 @@ void SubmenuView::SetSelectedRow(int row) {
} }
base::string16 SubmenuView::GetTextForRow(int row) { base::string16 SubmenuView::GetTextForRow(int row) {
return MenuItemView::GetAccessibleNameForMenuItem(GetMenuItemAt(row)->title(), return MenuItemView::GetAccessibleNameForMenuItem(
base::string16()); GetMenuItemAt(row)->title(), base::string16(),
GetMenuItemAt(row)->ShouldShowNewBadge());
} }
bool SubmenuView::IsShowing() const { bool SubmenuView::IsShowing() const {
......
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