Update Accessibility Feature Tile behavior
This CL adds a toggled state for the accessibility feature tile. Whenever an accessibility feature is enabled the tile is now toggled and a sub label is displayed to signify the first enabled feature along with a count to show how many features are enabled. This CL also adds a `name_resource_id` field for the AccessibilityControllerImpl::Feature class so that we can fetch a feature's name instead of hard coding it. Screenshot: https://screenshot.googleplex.com/B7FvV87PXwtYWFu Bug: b:280853527 Change-Id: I1a71e173ddedbe24c32568d0979cecafaa58cc2f Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4704936 Reviewed-by: Jiaming Cheng <jiamingc@chromium.org> Reviewed-by: Katie Dektar <katie@chromium.org> Commit-Queue: Ahmed Mehfooz <amehfooz@chromium.org> Cr-Commit-Position: refs/heads/main@{#1183251}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
60af84dfdc
commit
d2722b695e
ash
@ -92,6 +92,8 @@ struct FeatureData {
|
||||
// This field is not a raw_ptr<> because it was filtered by the rewriter
|
||||
// for: #global-scope
|
||||
RAW_PTR_EXCLUSION const gfx::VectorIcon* icon;
|
||||
const int name_resource_id;
|
||||
bool toggleable_in_quicksettings = true;
|
||||
FeatureType conflicting_feature = FeatureType::kNoConflictingFeature;
|
||||
};
|
||||
|
||||
@ -106,43 +108,56 @@ struct FeatureDialogData {
|
||||
// A static array describing each feature.
|
||||
const FeatureData kFeatures[] = {
|
||||
{FeatureType::kAutoclick, prefs::kAccessibilityAutoclickEnabled,
|
||||
&kSystemMenuAccessibilityAutoClickIcon},
|
||||
&kSystemMenuAccessibilityAutoClickIcon,
|
||||
IDS_ASH_STATUS_TRAY_ACCESSIBILITY_AUTOCLICK},
|
||||
{FeatureType::kCaretHighlight, prefs::kAccessibilityCaretHighlightEnabled,
|
||||
nullptr},
|
||||
nullptr, IDS_ASH_STATUS_TRAY_ACCESSIBILITY_CARET_HIGHLIGHT},
|
||||
{FeatureType::kCursorHighlight, prefs::kAccessibilityCursorHighlightEnabled,
|
||||
nullptr},
|
||||
nullptr, IDS_ASH_STATUS_TRAY_ACCESSIBILITY_HIGHLIGHT_MOUSE_CURSOR},
|
||||
{FeatureType::kCursorColor, prefs::kAccessibilityCursorColorEnabled,
|
||||
nullptr},
|
||||
nullptr, 0, /*toggleable_in_quicksettings*/ false},
|
||||
{FeatureType::kDictation, prefs::kAccessibilityDictationEnabled,
|
||||
&kDictationMenuIcon},
|
||||
&kDictationMenuIcon, IDS_ASH_STATUS_TRAY_ACCESSIBILITY_DICTATION},
|
||||
{FeatureType::kColorCorrection, prefs::kAccessibilityColorCorrectionEnabled,
|
||||
&kColorCorrectionIcon},
|
||||
&kColorCorrectionIcon, IDS_ASH_STATUS_TRAY_ACCESSIBILITY_COLOR_CORRECTION},
|
||||
{FeatureType::kFocusHighlight, prefs::kAccessibilityFocusHighlightEnabled,
|
||||
nullptr, /* conflicting_feature= */ FeatureType::kSpokenFeedback},
|
||||
nullptr, IDS_ASH_STATUS_TRAY_ACCESSIBILITY_HIGHLIGHT_KEYBOARD_FOCUS,
|
||||
/*toggleable_in_quicksettings*/ true,
|
||||
/* conflicting_feature= */ FeatureType::kSpokenFeedback},
|
||||
{FeatureType::kFloatingMenu, prefs::kAccessibilityFloatingMenuEnabled,
|
||||
nullptr},
|
||||
nullptr, IDS_ASH_FLOATING_ACCESSIBILITY_MAIN_MENU,
|
||||
/*toggleable_in_quicksettings=*/false},
|
||||
{FeatureType::kFullscreenMagnifier,
|
||||
prefs::kAccessibilityScreenMagnifierEnabled,
|
||||
&kSystemMenuAccessibilityFullscreenMagnifierIcon},
|
||||
&kSystemMenuAccessibilityFullscreenMagnifierIcon,
|
||||
IDS_ASH_STATUS_TRAY_ACCESSIBILITY_SCREEN_MAGNIFIER},
|
||||
{FeatureType::kDockedMagnifier, prefs::kDockedMagnifierEnabled,
|
||||
&kSystemMenuAccessibilityDockedMagnifierIcon},
|
||||
&kSystemMenuAccessibilityDockedMagnifierIcon,
|
||||
IDS_ASH_STATUS_TRAY_ACCESSIBILITY_DOCKED_MAGNIFIER},
|
||||
{FeatureType::kHighContrast, prefs::kAccessibilityHighContrastEnabled,
|
||||
&kSystemMenuAccessibilityContrastIcon},
|
||||
&kSystemMenuAccessibilityContrastIcon,
|
||||
IDS_ASH_STATUS_TRAY_ACCESSIBILITY_HIGH_CONTRAST_MODE},
|
||||
{FeatureType::kLargeCursor, prefs::kAccessibilityLargeCursorEnabled,
|
||||
nullptr},
|
||||
nullptr, IDS_ASH_STATUS_TRAY_ACCESSIBILITY_LARGE_CURSOR},
|
||||
{FeatureType::kLiveCaption, ::prefs::kLiveCaptionEnabled,
|
||||
&vector_icons::kLiveCaptionOnIcon},
|
||||
{FeatureType::kMonoAudio, prefs::kAccessibilityMonoAudioEnabled, nullptr},
|
||||
&vector_icons::kLiveCaptionOnIcon, IDS_ASH_STATUS_TRAY_LIVE_CAPTION},
|
||||
{FeatureType::kMonoAudio, prefs::kAccessibilityMonoAudioEnabled, nullptr,
|
||||
IDS_ASH_STATUS_TRAY_ACCESSIBILITY_MONO_AUDIO},
|
||||
{FeatureType::kSpokenFeedback, prefs::kAccessibilitySpokenFeedbackEnabled,
|
||||
&kSystemMenuAccessibilityChromevoxIcon},
|
||||
&kSystemMenuAccessibilityChromevoxIcon,
|
||||
IDS_ASH_STATUS_TRAY_ACCESSIBILITY_SPOKEN_FEEDBACK},
|
||||
{FeatureType::kSelectToSpeak, prefs::kAccessibilitySelectToSpeakEnabled,
|
||||
&kSystemMenuAccessibilitySelectToSpeakIcon},
|
||||
&kSystemMenuAccessibilitySelectToSpeakIcon,
|
||||
IDS_ASH_STATUS_TRAY_ACCESSIBILITY_SELECT_TO_SPEAK},
|
||||
{FeatureType::kStickyKeys, prefs::kAccessibilityStickyKeysEnabled, nullptr,
|
||||
IDS_ASH_STATUS_TRAY_ACCESSIBILITY_STICKY_KEYS,
|
||||
/*toggleable_in_quicksettings=*/true,
|
||||
/*conflicting_feature=*/FeatureType::kSpokenFeedback},
|
||||
{FeatureType::kSwitchAccess, prefs::kAccessibilitySwitchAccessEnabled,
|
||||
&kSwitchAccessIcon},
|
||||
&kSwitchAccessIcon, IDS_ASH_STATUS_TRAY_ACCESSIBILITY_SWITCH_ACCESS},
|
||||
{FeatureType::kVirtualKeyboard, prefs::kAccessibilityVirtualKeyboardEnabled,
|
||||
&kSystemMenuKeyboardLegacyIcon}};
|
||||
&kSystemMenuKeyboardLegacyIcon,
|
||||
IDS_ASH_STATUS_TRAY_ACCESSIBILITY_VIRTUAL_KEYBOARD}};
|
||||
|
||||
// An array describing the confirmation dialogs for the features which have
|
||||
// them.
|
||||
@ -782,8 +797,21 @@ AccessibilityControllerImpl::Feature::Feature(
|
||||
FeatureType type,
|
||||
const std::string& pref_name,
|
||||
const gfx::VectorIcon* icon,
|
||||
const int name_resource_id,
|
||||
const bool toggleable_in_quicksettings,
|
||||
AccessibilityControllerImpl* controller)
|
||||
: type_(type), pref_name_(pref_name), icon_(icon), owner_(controller) {}
|
||||
: type_(type),
|
||||
pref_name_(pref_name),
|
||||
icon_(icon),
|
||||
name_resource_id_(name_resource_id),
|
||||
toggleable_in_quicksettings_(toggleable_in_quicksettings),
|
||||
owner_(controller) {
|
||||
// If a feature is toggleable in quicksettings it must have a
|
||||
// `name_resource_id` so it's name can be looked up.
|
||||
if (toggleable_in_quicksettings_) {
|
||||
CHECK(name_resource_id);
|
||||
}
|
||||
}
|
||||
|
||||
AccessibilityControllerImpl::Feature::~Feature() = default;
|
||||
|
||||
@ -866,9 +894,16 @@ AccessibilityControllerImpl::FeatureWithDialog::FeatureWithDialog(
|
||||
FeatureType type,
|
||||
const std::string& pref_name,
|
||||
const gfx::VectorIcon* icon,
|
||||
const int name_resource_id,
|
||||
const bool toggleable_in_quicksettings,
|
||||
const Dialog& dialog,
|
||||
AccessibilityControllerImpl* controller)
|
||||
: AccessibilityControllerImpl::Feature(type, pref_name, icon, controller),
|
||||
: AccessibilityControllerImpl::Feature(type,
|
||||
pref_name,
|
||||
icon,
|
||||
name_resource_id,
|
||||
toggleable_in_quicksettings,
|
||||
controller),
|
||||
dialog_(dialog) {}
|
||||
AccessibilityControllerImpl::FeatureWithDialog::~FeatureWithDialog() = default;
|
||||
|
||||
@ -954,11 +989,14 @@ void AccessibilityControllerImpl::CreateAccessibilityFeatures() {
|
||||
auto it = dialogs.find(feature_data.type);
|
||||
if (it == dialogs.end()) {
|
||||
features_[feature_index] = std::make_unique<Feature>(
|
||||
feature_data.type, feature_data.pref, feature_data.icon, this);
|
||||
feature_data.type, feature_data.pref, feature_data.icon,
|
||||
feature_data.name_resource_id,
|
||||
feature_data.toggleable_in_quicksettings, this);
|
||||
} else {
|
||||
features_[feature_index] = std::make_unique<FeatureWithDialog>(
|
||||
feature_data.type, feature_data.pref, feature_data.icon, it->second,
|
||||
this);
|
||||
feature_data.type, feature_data.pref, feature_data.icon,
|
||||
feature_data.name_resource_id,
|
||||
feature_data.toggleable_in_quicksettings, it->second, this);
|
||||
}
|
||||
if (feature_data.conflicting_feature !=
|
||||
FeatureType::kNoConflictingFeature) {
|
||||
@ -1282,6 +1320,18 @@ AccessibilityControllerImpl::Feature& AccessibilityControllerImpl::GetFeature(
|
||||
return *features_[feature_index].get();
|
||||
}
|
||||
|
||||
std::vector<AccessibilityControllerImpl::Feature*>
|
||||
AccessibilityControllerImpl::GetEnabledFeaturesInQuickSettings() const {
|
||||
std::vector<Feature*> enabled_features;
|
||||
|
||||
for (auto& feature : features_) {
|
||||
if (feature->enabled() && feature->toggleable_in_quicksettings()) {
|
||||
enabled_features.push_back(feature.get());
|
||||
}
|
||||
}
|
||||
return enabled_features;
|
||||
}
|
||||
|
||||
base::WeakPtr<AccessibilityControllerImpl>
|
||||
AccessibilityControllerImpl::GetWeakPtr() {
|
||||
return weak_ptr_factory_.GetWeakPtr();
|
||||
|
@ -97,6 +97,8 @@ class ASH_EXPORT AccessibilityControllerImpl : public AccessibilityController,
|
||||
Feature(A11yFeatureType type,
|
||||
const std::string& pref_name,
|
||||
const gfx::VectorIcon* icon,
|
||||
const int name_resource_id,
|
||||
const bool toggleable_in_quicksettings,
|
||||
AccessibilityControllerImpl* controller);
|
||||
Feature(const Feature&) = delete;
|
||||
Feature& operator=(Feature const&) = delete;
|
||||
@ -113,6 +115,10 @@ class ASH_EXPORT AccessibilityControllerImpl : public AccessibilityController,
|
||||
bool IsEnterpriseIconVisible() const;
|
||||
const std::string& pref_name() const { return pref_name_; }
|
||||
const gfx::VectorIcon& icon() const;
|
||||
int name_resource_id() const { return name_resource_id_; }
|
||||
bool toggleable_in_quicksettings() const {
|
||||
return toggleable_in_quicksettings_;
|
||||
}
|
||||
A11yFeatureType conflicting_feature() const { return conflicting_feature_; }
|
||||
|
||||
void UpdateFromPref();
|
||||
@ -133,6 +139,15 @@ class ASH_EXPORT AccessibilityControllerImpl : public AccessibilityController,
|
||||
bool enabled_ = false;
|
||||
const std::string pref_name_;
|
||||
raw_ptr<const gfx::VectorIcon, ExperimentalAsh> icon_;
|
||||
|
||||
// The resource id used to fetch the string with this feature's name. Used
|
||||
// in quicksettings.
|
||||
const int name_resource_id_;
|
||||
|
||||
// Specifies if this feature can be toggled from the accessibility options
|
||||
// available in the quicksettings menu.
|
||||
const bool toggleable_in_quicksettings_;
|
||||
|
||||
const raw_ptr<AccessibilityControllerImpl, ExperimentalAsh> owner_;
|
||||
};
|
||||
|
||||
@ -155,6 +170,8 @@ class ASH_EXPORT AccessibilityControllerImpl : public AccessibilityController,
|
||||
FeatureWithDialog(A11yFeatureType type,
|
||||
const std::string& pref_name,
|
||||
const gfx::VectorIcon* icon,
|
||||
const int name_resource_id,
|
||||
const bool toggleable_in_quicksettings,
|
||||
const Dialog& dialog,
|
||||
AccessibilityControllerImpl* controller);
|
||||
~FeatureWithDialog() override;
|
||||
@ -203,6 +220,10 @@ class ASH_EXPORT AccessibilityControllerImpl : public AccessibilityController,
|
||||
|
||||
Feature& GetFeature(A11yFeatureType feature) const;
|
||||
|
||||
// Returns all `Feature`s that are toggleable in quicksettings and currently
|
||||
// enabled.
|
||||
std::vector<Feature*> GetEnabledFeaturesInQuickSettings() const;
|
||||
|
||||
base::WeakPtr<AccessibilityControllerImpl> GetWeakPtr();
|
||||
|
||||
// Getters for the corresponding features.
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "ash/accessibility/a11y_feature_type.h"
|
||||
#include "ash/accessibility/accessibility_observer.h"
|
||||
#include "ash/accessibility/magnifier/docked_magnifier_controller.h"
|
||||
#include "ash/accessibility/sticky_keys/sticky_keys_controller.h"
|
||||
@ -31,6 +32,7 @@
|
||||
#include "media/base/media_switches.h"
|
||||
#include "ui/accessibility/accessibility_features.h"
|
||||
#include "ui/accessibility/aura/aura_window_properties.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
#include "ui/message_center/message_center.h"
|
||||
|
||||
using message_center::MessageCenter;
|
||||
@ -1360,6 +1362,24 @@ TEST_F(AccessibilityControllerTest,
|
||||
(*notifications.begin())->system_notification_warning_level());
|
||||
}
|
||||
|
||||
// Test to ensure all features that are toggleable in the quicksettings menu
|
||||
// have a valid `name_resource_id`.
|
||||
TEST_F(AccessibilityControllerTest, AllAccessibilityFeaturesHaveValidNames) {
|
||||
auto* accessibility_controller = Shell::Get()->accessibility_controller();
|
||||
for (int type = 0; type != static_cast<int>(A11yFeatureType::kFeatureCount);
|
||||
type++) {
|
||||
auto& feature = accessibility_controller->GetFeature(
|
||||
static_cast<A11yFeatureType>(type));
|
||||
if (!feature.toggleable_in_quicksettings()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::u16string feature_name =
|
||||
l10n_util::GetStringUTF16(feature.name_resource_id());
|
||||
EXPECT_GT(feature_name.length(), 0u);
|
||||
}
|
||||
}
|
||||
|
||||
// Verifies the behavior of EnableOrToggleDictation without the keyboard
|
||||
// improvements feature (current behavior).
|
||||
TEST_F(AccessibilityControllerTest, EnableOrToggleDictation) {
|
||||
@ -1550,11 +1570,11 @@ TEST_P(AccessibilityControllerSigninTest, EnableOnLoginScreenAndLogin) {
|
||||
EXPECT_FALSE(accessibility->autoclick().enabled());
|
||||
EXPECT_FALSE(accessibility->mono_audio().enabled());
|
||||
EXPECT_FALSE(docked_magnifier->GetEnabled());
|
||||
using prefs::kAccessibilityLargeCursorEnabled;
|
||||
using prefs::kAccessibilitySpokenFeedbackEnabled;
|
||||
using prefs::kAccessibilityHighContrastEnabled;
|
||||
using prefs::kAccessibilityAutoclickEnabled;
|
||||
using prefs::kAccessibilityHighContrastEnabled;
|
||||
using prefs::kAccessibilityLargeCursorEnabled;
|
||||
using prefs::kAccessibilityMonoAudioEnabled;
|
||||
using prefs::kAccessibilitySpokenFeedbackEnabled;
|
||||
using prefs::kDockedMagnifierEnabled;
|
||||
PrefService* signin_prefs = session->GetSigninScreenPrefService();
|
||||
EXPECT_FALSE(signin_prefs->GetBoolean(kAccessibilityLargeCursorEnabled));
|
||||
|
@ -1074,9 +1074,16 @@ Style notes:
|
||||
<message name="IDS_ASH_STATUS_TRAY_ACCESSIBILITY" desc="The label used in the tray menu to show the accessibility option menu. [CHAR_LIMIT=14]">
|
||||
Accessibility
|
||||
</message>
|
||||
<message name="IDS_ASH_STATUS_TRAY_ACCESSIBILITY_ENABLED_FEATURES_SEPARATOR" desc="The characters used to separate the first feature's
|
||||
name from the counter in the label displayed when accessibility features are enabled in the quicksettings menu. Example: Select to Speak, +2">
|
||||
, +
|
||||
</message>
|
||||
<message name="IDS_ASH_STATUS_TRAY_ACCESSIBILITY_TOOLTIP" desc="The tooltip text in the tray menu to show the accessibility option menu.">
|
||||
Show accessibility settings
|
||||
</message>
|
||||
<message name="IDS_ASH_STATUS_TRAY_ACCESSIBILITY_TOGGLED_TOOLTIP" desc="The tooltip text in the tray menu to show the accessibility option menu.">
|
||||
Show accessibility settings, "<ph name="ENABLED_FEATURES">$1<ex>Dictation</ex></ph>" enabled.
|
||||
</message>
|
||||
<message name="IDS_ASH_STATUS_TRAY_ACCESSIBILITY_TITLE" desc="The label used in the title of the accessibility option menu. [CHAR_LIMIT=18]">
|
||||
Accessibility
|
||||
</message>
|
||||
|
1
ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_ACCESSIBILITY_ENABLED_FEATURES_SEPARATOR.png.sha1
Normal file
1
ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_ACCESSIBILITY_ENABLED_FEATURES_SEPARATOR.png.sha1
Normal file
@ -0,0 +1 @@
|
||||
4583db2a273ca22e2b2afac7c84de83553210b64
|
@ -0,0 +1 @@
|
||||
4583db2a273ca22e2b2afac7c84de83553210b64
|
@ -2,8 +2,11 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "ash/system/accessibility/accessibility_feature_pod_controller.h"
|
||||
|
||||
#include "ash/accessibility/accessibility_controller_impl.h"
|
||||
#include "ash/accessibility/accessibility_delegate.h"
|
||||
#include "ash/constants/quick_settings_catalogs.h"
|
||||
#include "ash/public/cpp/ash_view_ids.h"
|
||||
@ -15,16 +18,87 @@
|
||||
#include "ash/system/unified/feature_tile.h"
|
||||
#include "ash/system/unified/quick_settings_metrics_util.h"
|
||||
#include "ash/system/unified/unified_system_tray_controller.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
#include "ui/gfx/font_list.h"
|
||||
#include "ui/gfx/text_constants.h"
|
||||
#include "ui/gfx/text_elider.h"
|
||||
#include "ui/gfx/text_utils.h"
|
||||
#include "ui/views/controls/label.h"
|
||||
|
||||
namespace ash {
|
||||
|
||||
namespace {
|
||||
|
||||
std::u16string GenerateSublabelText(
|
||||
std::vector<AccessibilityControllerImpl::Feature*> enabled_features,
|
||||
int max_width,
|
||||
gfx::FontList font_list) {
|
||||
CHECK(!enabled_features.empty());
|
||||
std::u16string feature_name =
|
||||
l10n_util::GetStringUTF16(enabled_features.front()->name_resource_id());
|
||||
|
||||
if (enabled_features.size() == 1) {
|
||||
return feature_name;
|
||||
}
|
||||
std::u16string separator = l10n_util::GetStringUTF16(
|
||||
IDS_ASH_STATUS_TRAY_ACCESSIBILITY_ENABLED_FEATURES_SEPARATOR);
|
||||
std::u16string count_label =
|
||||
base::NumberToString16(enabled_features.size() - 1);
|
||||
|
||||
int available_width_for_feature_name =
|
||||
max_width - gfx::GetStringWidth(std::u16string(gfx::kEllipsisUTF16) +
|
||||
separator + count_label,
|
||||
font_list);
|
||||
// Elide the first enabled feature's name if necessary and then append the
|
||||
// number of other enabled features. This is to ensure the number is
|
||||
// always visible.
|
||||
std::u16string label = gfx::ElideText(feature_name, gfx::FontList(),
|
||||
available_width_for_feature_name,
|
||||
gfx::ElideBehavior::ELIDE_TAIL);
|
||||
|
||||
return base::JoinString({label, count_label}, separator);
|
||||
}
|
||||
|
||||
std::u16string GenerateTooltipText(
|
||||
std::vector<AccessibilityControllerImpl::Feature*> enabled_features) {
|
||||
if (enabled_features.empty()) {
|
||||
return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ACCESSIBILITY_TOOLTIP);
|
||||
}
|
||||
|
||||
std::u16string first_feature_name =
|
||||
l10n_util::GetStringUTF16(enabled_features.front()->name_resource_id());
|
||||
std::u16string separator = l10n_util::GetStringUTF16(
|
||||
IDS_ASH_STATUS_TRAY_ACCESSIBILITY_ENABLED_FEATURES_SEPARATOR);
|
||||
std::u16string enabled_features_string =
|
||||
enabled_features.size() == 1
|
||||
? first_feature_name
|
||||
: base::JoinString(
|
||||
{first_feature_name,
|
||||
base::NumberToString16(enabled_features.size() - 1)},
|
||||
separator);
|
||||
|
||||
return l10n_util::GetStringFUTF16(
|
||||
IDS_ASH_STATUS_TRAY_ACCESSIBILITY_TOGGLED_TOOLTIP,
|
||||
enabled_features_string);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
AccessibilityFeaturePodController::AccessibilityFeaturePodController(
|
||||
UnifiedSystemTrayController* tray_controller)
|
||||
: tray_controller_(tray_controller) {}
|
||||
: tray_controller_(tray_controller) {
|
||||
Shell::Get()->accessibility_controller()->AddObserver(this);
|
||||
}
|
||||
|
||||
AccessibilityFeaturePodController::~AccessibilityFeaturePodController() =
|
||||
default;
|
||||
AccessibilityFeaturePodController::~AccessibilityFeaturePodController() {
|
||||
Shell::Get()->accessibility_controller()->RemoveObserver(this);
|
||||
}
|
||||
|
||||
void AccessibilityFeaturePodController::OnAccessibilityStatusChanged() {
|
||||
UpdateTileStateIfExists();
|
||||
}
|
||||
|
||||
FeaturePodButton* AccessibilityFeaturePodController::CreateButton() {
|
||||
auto* button = new FeaturePodButton(this, /*is_togglable=*/false);
|
||||
@ -55,15 +129,12 @@ std::unique_ptr<FeatureTile> AccessibilityFeaturePodController::CreateTile(
|
||||
DCHECK(features::IsQsRevampEnabled());
|
||||
auto feature_tile = std::make_unique<FeatureTile>(
|
||||
base::BindRepeating(&FeaturePodControllerBase::OnIconPressed,
|
||||
weak_ptr_factory_.GetWeakPtr()),
|
||||
/*is_togglable=*/false);
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
feature_tile->SetID(VIEW_ID_ACCESSIBILITY_FEATURE_TILE);
|
||||
feature_tile->SetVectorIcon(kUnifiedMenuAccessibilityIcon);
|
||||
feature_tile->SetLabel(
|
||||
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ACCESSIBILITY));
|
||||
feature_tile->SetSubLabelVisibility(false);
|
||||
feature_tile->SetTooltipText(
|
||||
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ACCESSIBILITY_TOOLTIP));
|
||||
feature_tile->CreateDecorativeDrillInArrow();
|
||||
|
||||
AccessibilityDelegate* delegate = Shell::Get()->accessibility_delegate();
|
||||
@ -76,6 +147,8 @@ std::unique_ptr<FeatureTile> AccessibilityFeaturePodController::CreateTile(
|
||||
TrackVisibilityUMA();
|
||||
}
|
||||
|
||||
tile_ = feature_tile.get();
|
||||
UpdateTileStateIfExists();
|
||||
return feature_tile;
|
||||
}
|
||||
|
||||
@ -88,4 +161,28 @@ void AccessibilityFeaturePodController::OnIconPressed() {
|
||||
tray_controller_->ShowAccessibilityDetailedView();
|
||||
}
|
||||
|
||||
void AccessibilityFeaturePodController::UpdateTileStateIfExists() {
|
||||
if (!tile_) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto enabled_features = Shell::Get()
|
||||
->accessibility_controller()
|
||||
->GetEnabledFeaturesInQuickSettings();
|
||||
|
||||
bool toggled = !enabled_features.empty();
|
||||
tile_->SetToggled(toggled);
|
||||
tile_->SetTooltipText(GenerateTooltipText(enabled_features));
|
||||
|
||||
tile_->SetSubLabelVisibility(toggled);
|
||||
if (toggled) {
|
||||
tile_->SetSubLabel(GenerateSublabelText(enabled_features,
|
||||
tile_->GetSubLabelMaxWidth(),
|
||||
tile_->sub_label()->font_list()));
|
||||
tile_->sub_label()->SetElideBehavior(enabled_features.size() == 1
|
||||
? gfx::ElideBehavior::ELIDE_TAIL
|
||||
: gfx::ElideBehavior::NO_ELIDE);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ash
|
||||
|
@ -7,9 +7,11 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "ash/accessibility/accessibility_observer.h"
|
||||
#include "ash/ash_export.h"
|
||||
#include "ash/constants/quick_settings_catalogs.h"
|
||||
#include "ash/system/unified/feature_pod_controller_base.h"
|
||||
#include "base/allocator/partition_allocator/pointers/raw_ptr.h"
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
|
||||
@ -20,9 +22,10 @@ class UnifiedSystemTrayController;
|
||||
|
||||
// Controller of accessibility feature pod button.
|
||||
class ASH_EXPORT AccessibilityFeaturePodController
|
||||
: public FeaturePodControllerBase {
|
||||
: public FeaturePodControllerBase,
|
||||
public AccessibilityObserver {
|
||||
public:
|
||||
AccessibilityFeaturePodController(
|
||||
explicit AccessibilityFeaturePodController(
|
||||
UnifiedSystemTrayController* tray_controller);
|
||||
|
||||
AccessibilityFeaturePodController(const AccessibilityFeaturePodController&) =
|
||||
@ -32,6 +35,9 @@ class ASH_EXPORT AccessibilityFeaturePodController
|
||||
|
||||
~AccessibilityFeaturePodController() override;
|
||||
|
||||
// AccessibilityObserver:
|
||||
void OnAccessibilityStatusChanged() override;
|
||||
|
||||
// FeaturePodControllerBase:
|
||||
FeaturePodButton* CreateButton() override;
|
||||
std::unique_ptr<FeatureTile> CreateTile(bool compact = false) override;
|
||||
@ -39,9 +45,17 @@ class ASH_EXPORT AccessibilityFeaturePodController
|
||||
void OnIconPressed() override;
|
||||
|
||||
private:
|
||||
// Updates `tile_` state to reflect the current accessibility features state.
|
||||
// The `tile_` is toggled if any features are enabled and a sublabel is
|
||||
// displayed with details for the enabled features.
|
||||
void UpdateTileStateIfExists();
|
||||
|
||||
// Unowned.
|
||||
const raw_ptr<UnifiedSystemTrayController, ExperimentalAsh> tray_controller_;
|
||||
|
||||
// Owned by views hierarchy.
|
||||
raw_ptr<FeatureTile, ExperimentalAsh> tile_ = nullptr;
|
||||
|
||||
base::WeakPtrFactory<AccessibilityFeaturePodController> weak_ptr_factory_{
|
||||
this};
|
||||
};
|
||||
|
@ -4,14 +4,18 @@
|
||||
|
||||
#include "ash/system/accessibility/accessibility_feature_pod_controller.h"
|
||||
|
||||
#include "ash/accessibility/a11y_feature_type.h"
|
||||
#include "ash/accessibility/accessibility_controller_impl.h"
|
||||
#include "ash/constants/ash_features.h"
|
||||
#include "ash/constants/quick_settings_catalogs.h"
|
||||
#include "ash/shell.h"
|
||||
#include "ash/system/unified/feature_pod_button.h"
|
||||
#include "ash/system/unified/feature_tile.h"
|
||||
#include "ash/system/unified/unified_system_tray.h"
|
||||
#include "ash/system/unified/unified_system_tray_bubble.h"
|
||||
#include "ash/system/unified/unified_system_tray_controller.h"
|
||||
#include "ash/test/ash_test_base.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/test/metrics/histogram_tester.h"
|
||||
#include "base/test/scoped_feature_list.h"
|
||||
#include "ui/views/view.h"
|
||||
@ -62,6 +66,11 @@ class AccessibilityFeaturePodControllerTest
|
||||
}
|
||||
}
|
||||
|
||||
AccessibilityControllerImpl* GetAccessibilityController() {
|
||||
return Shell::Get()->accessibility_controller();
|
||||
}
|
||||
|
||||
FeatureTile* GetFeatureTile() { return tile_.get(); }
|
||||
UnifiedSystemTrayController* tray_controller() {
|
||||
return GetPrimaryUnifiedSystemTray()
|
||||
->bubble()
|
||||
@ -164,4 +173,100 @@ TEST_P(AccessibilityFeaturePodControllerTest, LabelUMATracking) {
|
||||
/*expected_count=*/1);
|
||||
}
|
||||
|
||||
TEST_P(AccessibilityFeaturePodControllerTest, FeatureTileBasicToggleBehavior) {
|
||||
if (!IsQsRevampEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
SetUpButton();
|
||||
|
||||
EXPECT_FALSE(GetFeatureTile()->IsToggled());
|
||||
|
||||
// Enable an accessibility feature and expect the feature tile to be toggled
|
||||
// and the sublabel to be visible.
|
||||
GetAccessibilityController()
|
||||
->GetFeature(A11yFeatureType::kHighContrast)
|
||||
.SetEnabled(true);
|
||||
EXPECT_TRUE(GetFeatureTile()->IsToggled());
|
||||
EXPECT_TRUE(GetFeatureTile()->sub_label()->GetVisible());
|
||||
|
||||
// Disable an accessibility feature and expect the feature tile to be
|
||||
// untoggled and the sublabel to be invisible.
|
||||
GetAccessibilityController()
|
||||
->GetFeature(A11yFeatureType::kHighContrast)
|
||||
.SetEnabled(false);
|
||||
EXPECT_FALSE(GetFeatureTile()->IsToggled());
|
||||
EXPECT_FALSE(GetFeatureTile()->sub_label()->GetVisible());
|
||||
}
|
||||
|
||||
// Toggle all accessibility features one by one and make sure the feature tile
|
||||
// is updated appropriately.
|
||||
TEST_P(AccessibilityFeaturePodControllerTest, FeatureTileAllFeaturesToggled) {
|
||||
if (!IsQsRevampEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
SetUpButton();
|
||||
|
||||
for (int type = 0; type != static_cast<int>(A11yFeatureType::kFeatureCount);
|
||||
type++) {
|
||||
auto& feature = GetAccessibilityController()->GetFeature(
|
||||
static_cast<A11yFeatureType>(type));
|
||||
feature.SetEnabled(true);
|
||||
if (!feature.enabled()) {
|
||||
continue;
|
||||
}
|
||||
if (feature.toggleable_in_quicksettings()) {
|
||||
EXPECT_TRUE(GetFeatureTile()->IsToggled());
|
||||
} else {
|
||||
EXPECT_FALSE(GetFeatureTile()->IsToggled());
|
||||
}
|
||||
|
||||
feature.SetEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Enable accessibility features one by one until we have double digits in the
|
||||
// count shown in the `sub_label`.
|
||||
TEST_P(AccessibilityFeaturePodControllerTest,
|
||||
FeatureTileSubLabelCounterBehavior) {
|
||||
if (!IsQsRevampEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
SetUpButton();
|
||||
|
||||
GetAccessibilityController()
|
||||
->GetFeature(A11yFeatureType::kLargeCursor)
|
||||
.SetEnabled(true);
|
||||
int expected_count = 0;
|
||||
auto feature_types = {
|
||||
A11yFeatureType::kCaretHighlight, A11yFeatureType::kCursorHighlight,
|
||||
A11yFeatureType::kDictation, A11yFeatureType::kFocusHighlight,
|
||||
A11yFeatureType::kHighContrast, A11yFeatureType::kMonoAudio,
|
||||
A11yFeatureType::kLiveCaption, A11yFeatureType::kFullscreenMagnifier,
|
||||
A11yFeatureType::kStickyKeys, A11yFeatureType::kSwitchAccess};
|
||||
for (A11yFeatureType type : feature_types) {
|
||||
auto& feature = GetAccessibilityController()->GetFeature(
|
||||
static_cast<A11yFeatureType>(type));
|
||||
|
||||
feature.SetEnabled(true);
|
||||
expected_count++;
|
||||
|
||||
EXPECT_TRUE(base::EndsWith(GetFeatureTile()->sub_label()->GetText(),
|
||||
base::NumberToString16(expected_count)));
|
||||
}
|
||||
|
||||
for (A11yFeatureType type : feature_types) {
|
||||
EXPECT_TRUE(base::EndsWith(GetFeatureTile()->sub_label()->GetText(),
|
||||
base::NumberToString16(expected_count)));
|
||||
|
||||
auto& feature = GetAccessibilityController()->GetFeature(
|
||||
static_cast<A11yFeatureType>(type));
|
||||
expected_count--;
|
||||
|
||||
feature.SetEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ash
|
||||
|
@ -267,8 +267,9 @@ void FeatureTile::UpdateColors() {
|
||||
}
|
||||
|
||||
void FeatureTile::SetToggled(bool toggled) {
|
||||
if (!is_togglable_ || toggled_ == toggled)
|
||||
if (!is_togglable_ || toggled_ == toggled) {
|
||||
return;
|
||||
}
|
||||
|
||||
toggled_ = toggled;
|
||||
UpdateColors();
|
||||
@ -302,6 +303,10 @@ void FeatureTile::SetLabel(const std::u16string& label) {
|
||||
label_->SetText(label);
|
||||
}
|
||||
|
||||
int FeatureTile::GetSubLabelMaxWidth() const {
|
||||
return kTitlesContainerSize.width();
|
||||
}
|
||||
|
||||
void FeatureTile::SetSubLabel(const std::u16string& sub_label) {
|
||||
sub_label_->SetText(sub_label);
|
||||
}
|
||||
|
@ -110,6 +110,9 @@ class ASH_EXPORT FeatureTile : public views::Button {
|
||||
// Sets the text of `label_`.
|
||||
void SetLabel(const std::u16string& label);
|
||||
|
||||
// Returns the maximum width for `sub_label_`.
|
||||
int GetSubLabelMaxWidth() const;
|
||||
|
||||
// Sets the text of the `sub_label_`.
|
||||
void SetSubLabel(const std::u16string& sub_label);
|
||||
|
||||
|
Reference in New Issue
Block a user