Skip to content

Commit

Permalink
qs: Show toggle buttons in quick settings accessibility menu
Browse files Browse the repository at this point in the history
The quick settings revamp spec calls for the accessibility menu to have
toggle buttons in the right column. However, the entire row should be
clickable. Continue to use HoverHighlightView for each row (which
handles the click) and create a non-clickable view-only toggle button
in each row. When a setting is enterprise controlled, the enterprise
building icon is shown in the right column.

To maintain Chromevox compatibility, each entire row continues to
present itself as a checkbox, allowing the entire row to be toggled
via ChromeVox controls.

https://screenshot.googleplex.com/57PvR2CeLNEPvNH
https://screenshot.googleplex.com/6E84J3QYfk9mwMK

There are still some updates needed to match the latest mock. These
will be handled in a future CL.

Bug: b:252871844
Test: added to ash_unittests
Change-Id: I04a10113100420bf80acc73327bcb762554c08df
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4003051
Reviewed-by: Jiaming Cheng <jiamingc@chromium.org>
Commit-Queue: James Cook <jamescook@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1067344}
  • Loading branch information
James Cook authored and Chromium LUCI CQ committed Nov 4, 2022
1 parent c93dba7 commit cf8ce00
Show file tree
Hide file tree
Showing 6 changed files with 292 additions and 91 deletions.
178 changes: 132 additions & 46 deletions ash/system/accessibility/accessibility_detailed_view.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,15 @@
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/style/ash_color_provider.h"
#include "ash/style/rounded_container.h"
#include "ash/system/machine_learning/user_settings_event_logger.h"
#include "ash/system/model/system_tray_model.h"
#include "ash/system/tray/hover_highlight_view.h"
#include "ash/system/tray/tray_constants.h"
#include "ash/system/tray/tray_detailed_view.h"
#include "ash/system/tray/tray_popup_utils.h"
#include "ash/system/tray/tray_toggle_button.h"
#include "ash/system/tray/tray_utils.h"
#include "ash/system/tray/tri_view.h"
#include "base/bind.h"
Expand All @@ -33,10 +36,14 @@
#include "components/prefs/pref_service.h"
#include "components/soda/soda_installer.h"
#include "components/vector_icons/vector_icons.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/accessibility/accessibility_features.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/gfx/vector_icon_types.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/controls/separator.h"
#include "ui/views/view_utils.h"

namespace ash {
namespace {
Expand Down Expand Up @@ -110,15 +117,37 @@ bool SodaFeatureHasUpdate(SodaFeature feature,
language_code == GetSodaFeatureLocale(feature);
}

// Updates the check mark to `checked` on `view1` and `view2` if the views
// exist.
void UpdateCheckMark(bool checked,
HoverHighlightView* view1,
HoverHighlightView* view2) {
if (view1)
TrayPopupUtils::UpdateCheckMarkVisibility(view1, checked);
if (view2)
TrayPopupUtils::UpdateCheckMarkVisibility(view2, checked);
// Updates the toggle button state and accessibility state for `item` to
// `toggled`.
void UpdateToggleState(HoverHighlightView* item, bool toggled) {
if (!item)
return;
views::View* right_view = item->right_view();
// The right view is either an enterprise icon or a tray toggle button.
if (views::IsViewClass<TrayToggleButton>(right_view)) {
TrayToggleButton* button = static_cast<TrayToggleButton*>(right_view);
button->AnimateIsOn(toggled);
}
// The entire row is treated as one element for accessibility.
item->SetAccessibilityState(
toggled ? HoverHighlightView::AccessibilityState::CHECKED_CHECKBOX
: HoverHighlightView::AccessibilityState::UNCHECKED_CHECKBOX);
}

// Updates the feature state in the UI to `enabled` on `view1` and `view2` if
// the views exist.
void UpdateFeatureState(bool enabled,
HoverHighlightView* view1,
HoverHighlightView* view2) {
if (features::IsQsRevampEnabled()) {
// QsRevamp uses toggle buttons.
UpdateToggleState(view1, enabled);
UpdateToggleState(view2, enabled);
return;
}
// Pre-QsRevamp uses check marks.
TrayPopupUtils::UpdateCheckMarkVisibility(view1, enabled);
TrayPopupUtils::UpdateCheckMarkVisibility(view2, enabled);
}

} // namespace
Expand Down Expand Up @@ -165,87 +194,90 @@ void AccessibilityDetailedView::OnAccessibilityStatusChanged() {

if (controller->IsSpokenFeedbackSettingVisibleInTray()) {
bool checked = controller->spoken_feedback().enabled();
UpdateCheckMark(checked, spoken_feedback_view_, spoken_feedback_top_view_);
UpdateFeatureState(checked, spoken_feedback_view_,
spoken_feedback_top_view_);
}

if (controller->IsSelectToSpeakSettingVisibleInTray()) {
bool checked = controller->select_to_speak().enabled();
UpdateCheckMark(checked, select_to_speak_view_, select_to_speak_top_view_);
UpdateFeatureState(checked, select_to_speak_view_,
select_to_speak_top_view_);
}

if (controller->IsDictationSettingVisibleInTray()) {
bool checked = controller->dictation().enabled();
UpdateCheckMark(checked, dictation_view_, dictation_top_view_);
UpdateFeatureState(checked, dictation_view_, dictation_top_view_);
}

if (controller->IsHighContrastSettingVisibleInTray()) {
bool checked = controller->high_contrast().enabled();
UpdateCheckMark(checked, high_contrast_view_, high_contrast_top_view_);
UpdateFeatureState(checked, high_contrast_view_, high_contrast_top_view_);
}

if (controller->IsFullScreenMagnifierSettingVisibleInTray()) {
bool checked = delegate->IsMagnifierEnabled();
UpdateCheckMark(checked, screen_magnifier_view_,
screen_magnifier_top_view_);
UpdateFeatureState(checked, screen_magnifier_view_,
screen_magnifier_top_view_);
}

if (controller->IsDockedMagnifierSettingVisibleInTray()) {
bool checked = Shell::Get()->docked_magnifier_controller()->GetEnabled();
UpdateCheckMark(checked, docked_magnifier_view_,
docked_magnifier_top_view_);
UpdateFeatureState(checked, docked_magnifier_view_,
docked_magnifier_top_view_);
}

if (controller->IsAutoclickSettingVisibleInTray()) {
bool checked = controller->autoclick().enabled();
UpdateCheckMark(checked, autoclick_view_, autoclick_top_view_);
UpdateFeatureState(checked, autoclick_view_, autoclick_top_view_);
}

if (controller->IsVirtualKeyboardSettingVisibleInTray()) {
bool checked = controller->virtual_keyboard().enabled();
UpdateCheckMark(checked, virtual_keyboard_view_,
virtual_keyboard_top_view_);
UpdateFeatureState(checked, virtual_keyboard_view_,
virtual_keyboard_top_view_);
}

if (controller->IsSwitchAccessSettingVisibleInTray()) {
bool checked = controller->switch_access().enabled();
UpdateCheckMark(checked, switch_access_view_, switch_access_top_view_);
UpdateFeatureState(checked, switch_access_view_, switch_access_top_view_);
}

if (controller->IsLiveCaptionSettingVisibleInTray()) {
bool checked = controller->live_caption().enabled();
UpdateCheckMark(checked, live_caption_view_, live_caption_top_view_);
UpdateFeatureState(checked, live_caption_view_, live_caption_top_view_);
}

if (controller->IsLargeCursorSettingVisibleInTray()) {
bool checked = controller->large_cursor().enabled();
UpdateCheckMark(checked, large_cursor_view_, large_cursor_top_view_);
UpdateFeatureState(checked, large_cursor_view_, large_cursor_top_view_);
}

if (controller->IsMonoAudioSettingVisibleInTray()) {
bool checked = controller->mono_audio().enabled();
UpdateCheckMark(checked, mono_audio_view_, mono_audio_top_view_);
UpdateFeatureState(checked, mono_audio_view_, mono_audio_top_view_);
}

if (controller->IsCaretHighlightSettingVisibleInTray()) {
bool checked = controller->caret_highlight().enabled();
UpdateCheckMark(checked, caret_highlight_view_, caret_highlight_top_view_);
UpdateFeatureState(checked, caret_highlight_view_,
caret_highlight_top_view_);
}

if (controller->IsCursorHighlightSettingVisibleInTray()) {
bool checked = controller->cursor_highlight().enabled();
UpdateCheckMark(checked, highlight_mouse_cursor_view_,
highlight_mouse_cursor_top_view_);
UpdateFeatureState(checked, highlight_mouse_cursor_view_,
highlight_mouse_cursor_top_view_);
}

if (controller->IsFocusHighlightSettingVisibleInTray()) {
bool checked = controller->focus_highlight().enabled();
UpdateCheckMark(checked, highlight_keyboard_focus_view_,
highlight_keyboard_focus_top_view_);
UpdateFeatureState(checked, highlight_keyboard_focus_view_,
highlight_keyboard_focus_top_view_);
}

if (controller->IsStickyKeysSettingVisibleInTray()) {
bool checked = controller->sticky_keys().enabled();
UpdateCheckMark(checked, sticky_keys_view_, sticky_keys_top_view_);
UpdateFeatureState(checked, sticky_keys_view_, sticky_keys_top_view_);
}
}

Expand Down Expand Up @@ -434,7 +466,7 @@ HoverHighlightView* AccessibilityDetailedView::AddSpokenFeedbackView(
views::View* container) {
auto* controller = Shell::Get()->accessibility_controller();
bool checked = controller->spoken_feedback().enabled();
return AddScrollListCheckableItem(
return AddScrollListFeatureItem(
container, kSystemMenuAccessibilityChromevoxIcon,
l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_ACCESSIBILITY_SPOKEN_FEEDBACK),
Expand All @@ -445,7 +477,7 @@ HoverHighlightView* AccessibilityDetailedView::AddSelectToSpeakView(
views::View* container) {
auto* controller = Shell::Get()->accessibility_controller();
bool checked = controller->select_to_speak().enabled();
return AddScrollListCheckableItem(
return AddScrollListFeatureItem(
container, kSystemMenuAccessibilitySelectToSpeakIcon,
l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_ACCESSIBILITY_SELECT_TO_SPEAK),
Expand All @@ -456,7 +488,7 @@ HoverHighlightView* AccessibilityDetailedView::AddDictationView(
views::View* container) {
auto* controller = Shell::Get()->accessibility_controller();
bool checked = controller->dictation().enabled();
return AddScrollListCheckableItem(
return AddScrollListFeatureItem(
container, kDictationMenuIcon,
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ACCESSIBILITY_DICTATION),
checked, controller->IsEnterpriseIconVisibleForDictation());
Expand All @@ -466,7 +498,7 @@ HoverHighlightView* AccessibilityDetailedView::AddHighContrastView(
views::View* container) {
auto* controller = Shell::Get()->accessibility_controller();
bool checked = controller->high_contrast().enabled();
return AddScrollListCheckableItem(
return AddScrollListFeatureItem(
container, kSystemMenuAccessibilityContrastIcon,
l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_ACCESSIBILITY_HIGH_CONTRAST_MODE),
Expand All @@ -477,7 +509,7 @@ HoverHighlightView* AccessibilityDetailedView::AddScreenMagnifierView(
views::View* container) {
auto* controller = Shell::Get()->accessibility_controller();
bool checked = Shell::Get()->accessibility_delegate()->IsMagnifierEnabled();
return AddScrollListCheckableItem(
return AddScrollListFeatureItem(
container, kSystemMenuAccessibilityFullscreenMagnifierIcon,
l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_ACCESSIBILITY_SCREEN_MAGNIFIER),
Expand All @@ -488,7 +520,7 @@ HoverHighlightView* AccessibilityDetailedView::AddDockedMagnifierView(
views::View* container) {
auto* controller = Shell::Get()->accessibility_controller();
bool checked = Shell::Get()->docked_magnifier_controller()->GetEnabled();
return AddScrollListCheckableItem(
return AddScrollListFeatureItem(
container, kSystemMenuAccessibilityDockedMagnifierIcon,
l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_ACCESSIBILITY_DOCKED_MAGNIFIER),
Expand All @@ -499,7 +531,7 @@ HoverHighlightView* AccessibilityDetailedView::AddAutoclickView(
views::View* container) {
auto* controller = Shell::Get()->accessibility_controller();
bool checked = controller->autoclick().enabled();
return AddScrollListCheckableItem(
return AddScrollListFeatureItem(
container, kSystemMenuAccessibilityAutoClickIcon,
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ACCESSIBILITY_AUTOCLICK),
checked, controller->IsEnterpriseIconVisibleForAutoclick());
Expand All @@ -509,7 +541,7 @@ HoverHighlightView* AccessibilityDetailedView::AddVirtualKeyboardView(
views::View* container) {
auto* controller = Shell::Get()->accessibility_controller();
bool checked = controller->virtual_keyboard().enabled();
return AddScrollListCheckableItem(
return AddScrollListFeatureItem(
container, kSystemMenuKeyboardLegacyIcon,
l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_ACCESSIBILITY_VIRTUAL_KEYBOARD),
Expand All @@ -520,7 +552,7 @@ HoverHighlightView* AccessibilityDetailedView::AddSwitchAccessView(
views::View* container) {
auto* controller = Shell::Get()->accessibility_controller();
bool checked = controller->switch_access().enabled();
return AddScrollListCheckableItem(
return AddScrollListFeatureItem(
container, kSwitchAccessIcon,
l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_ACCESSIBILITY_SWITCH_ACCESS),
Expand All @@ -531,7 +563,7 @@ HoverHighlightView* AccessibilityDetailedView::AddLiveCaptionView(
views::View* container) {
auto* controller = Shell::Get()->accessibility_controller();
bool checked = controller->live_caption().enabled();
return AddScrollListCheckableItem(
return AddScrollListFeatureItem(
container, vector_icons::kLiveCaptionOnIcon,
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_LIVE_CAPTION), checked,
controller->IsEnterpriseIconVisibleForLiveCaption());
Expand All @@ -541,7 +573,7 @@ HoverHighlightView* AccessibilityDetailedView::AddLargeCursorView(
views::View* container) {
auto* controller = Shell::Get()->accessibility_controller();
bool checked = controller->large_cursor().enabled();
return AddScrollListCheckableItem(
return AddScrollListFeatureItem(
container, gfx::kNoneIcon,
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ACCESSIBILITY_LARGE_CURSOR),
checked, controller->IsEnterpriseIconVisibleForLargeCursor());
Expand All @@ -551,7 +583,7 @@ HoverHighlightView* AccessibilityDetailedView::AddMonoAudioView(
views::View* container) {
auto* controller = Shell::Get()->accessibility_controller();
bool checked = controller->mono_audio().enabled();
return AddScrollListCheckableItem(
return AddScrollListFeatureItem(
container, gfx::kNoneIcon,
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ACCESSIBILITY_MONO_AUDIO),
checked, controller->IsEnterpriseIconVisibleForMonoAudio());
Expand All @@ -561,7 +593,7 @@ HoverHighlightView* AccessibilityDetailedView::AddCaretHighlightView(
views::View* container) {
auto* controller = Shell::Get()->accessibility_controller();
bool checked = controller->caret_highlight().enabled();
return AddScrollListCheckableItem(
return AddScrollListFeatureItem(
container, gfx::kNoneIcon,
l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_ACCESSIBILITY_CARET_HIGHLIGHT),
Expand All @@ -572,7 +604,7 @@ HoverHighlightView* AccessibilityDetailedView::AddHighlightMouseCursorView(
views::View* container) {
auto* controller = Shell::Get()->accessibility_controller();
bool checked = controller->cursor_highlight().enabled();
return AddScrollListCheckableItem(
return AddScrollListFeatureItem(
container, gfx::kNoneIcon,
l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_ACCESSIBILITY_HIGHLIGHT_MOUSE_CURSOR),
Expand All @@ -583,7 +615,7 @@ HoverHighlightView* AccessibilityDetailedView::AddHighlightKeyboardFocusView(
views::View* container) {
auto* controller = Shell::Get()->accessibility_controller();
bool checked = controller->focus_highlight().enabled();
return AddScrollListCheckableItem(
return AddScrollListFeatureItem(
container, gfx::kNoneIcon,
l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_ACCESSIBILITY_HIGHLIGHT_KEYBOARD_FOCUS),
Expand All @@ -594,12 +626,66 @@ HoverHighlightView* AccessibilityDetailedView::AddStickyKeysView(
views::View* container) {
auto* controller = Shell::Get()->accessibility_controller();
bool checked = controller->sticky_keys().enabled();
return AddScrollListCheckableItem(
return AddScrollListFeatureItem(
container, gfx::kNoneIcon,
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ACCESSIBILITY_STICKY_KEYS),
checked, controller->IsEnterpriseIconVisibleForStickyKeys());
}

HoverHighlightView* AccessibilityDetailedView::AddScrollListFeatureItem(
views::View* container,
const gfx::VectorIcon& icon,
const std::u16string& text,
bool checked,
bool enterprise_managed) {
if (features::IsQsRevampEnabled()) {
// QsRevamp uses items with a toggle button on the right.
return AddScrollListToggleItem(container, icon, text, checked,
enterprise_managed);
}
// Pre-QsRevamp uses items with check marks on the right.
return AddScrollListCheckableItem(container, icon, text, checked,
enterprise_managed);
}

HoverHighlightView* AccessibilityDetailedView::AddScrollListToggleItem(
views::View* container,
const gfx::VectorIcon& icon,
const std::u16string& text,
bool checked,
bool enterprise_managed) {
HoverHighlightView* item = AddScrollListItem(container, icon, text);
item->SetAccessibilityState(
checked ? HoverHighlightView::AccessibilityState::CHECKED_CHECKBOX
: HoverHighlightView::AccessibilityState::UNCHECKED_CHECKBOX);
if (enterprise_managed) {
// Show the enterprise "building" icon on the right.
item->SetAccessibleName(l10n_util::GetStringFUTF16(
IDS_ASH_ACCESSIBILITY_FEATURE_MANAGED, text));
// TODO(b/257315380): The color should update on theme change.
SkColor color = AshColorProvider::Get()->GetContentLayerColor(
AshColorProvider::ContentLayerType::kIconColorPrimary);
gfx::ImageSkia enterprise_managed_icon =
CreateVectorIcon(kSystemMenuBusinessIcon, kMenuIconSize, color);
item->AddRightIcon(enterprise_managed_icon,
enterprise_managed_icon.width());
} else {
// Create a non-clickable non-focusable toggle button on the right.
auto toggle = std::make_unique<TrayToggleButton>(
views::Button::PressedCallback(),
/*accessible_name_id=*/absl::nullopt);
toggle->SetIsOn(checked);
toggle->SetCanProcessEventsWithinSubtree(false);
toggle->SetFocusBehavior(views::View::FocusBehavior::NEVER);
// Ignore the toggle for accessibility.
auto& view_accessibility = toggle->GetViewAccessibility();
view_accessibility.OverrideIsLeaf(true);
view_accessibility.OverrideIsIgnored(true);
item->AddRightView(toggle.release());
}
return item;
}

void AccessibilityDetailedView::HandleViewClicked(views::View* view) {
AccessibilityDelegate* delegate = Shell::Get()->accessibility_delegate();
AccessibilityControllerImpl* controller =
Expand Down

0 comments on commit cf8ce00

Please sign in to comment.