0

Revert "Reland "[A11yPerformance] Clean up BrowserAccessibilityState""

This reverts commit 717eefc40c.

Reason for revert: broke deactivation when VoiceOver is stopped

Original change's description:
> Reland "[A11yPerformance] Clean up BrowserAccessibilityState"
>
> Problem and fix:
> The test NewTabPageAppA11yTest.Click failed as mentioned in
> crbug.com/404576872 failed because there were
> two call sites setting the process accessibility mode directly,
> basically competing with each other. This only happens after
> the CL landed where we are removing outdated
> OnScreenReaderDetected/Stopped methods and replacing them
> with close equivalents. However, these two methods were not
> symmetrical in the old code. One enabled accessibility, and one
> potentially disabled accessibility after a short delay.
>
> The modern way to set an accessibility mode, which fixes this issue,
> is to use ScopedAccessibilityMode. When it goes out of scope it
> doesn't destroy the a11y mode set by any other piece of code.
> A follow-up is to move all code setting a process accessibility mode
> to ScopedAccessibilityMode.
>
> Original change's description:
> > Revert "[A11yPerformance] Clean up BrowserAccessibilityState"
> >
> > This reverts commit 8c794f38d3.
> >
> > Reason for revert: breaks test on multiple Mac bots crbug.com/404576872
> >
> > Original change's description:
> > > [A11yPerformance] Clean up BrowserAccessibilityState
> > >
> > > 1. Clarify which methods/variables are related to Auto Disable as
> > >    opposed to just Disable (manually disabling of a11y), so that
> > >    it's no longer confusing what belongs to what intention.
> > >
> > > 2. Rename some methods to accurately reflect what they do,
> > >   and add comments:
> > > * IsRendererAccessibilityEnabled() -> IsAccessibilityAllowed().
> > >   This was not specific to renderers, or whether a11y was enabled.
> > >   It returned true if a11y was not disallowed via the command line.
> > > * EnableAccessibility() -> EnableCompleteAccessibility().
> > >   This turns on kAXModeComplete.
> > >
> > > 3. Remove some poorly named and redundant methods that are not
> > >    actually needed:
> > > * ResetAccessibilityMode() -- the same as DisableAccessibility().
> > > * OnScreenReaderDetected() -- did not actually reflect screen
> > >   reader detection and was just a way to EnableAccessibility(), so
> > >   is redundant with that. Any remaining methods and modes with
> > >   "screen reader" in the name will now make sense.
> > > * OnScreenReaderStopped() -- did not actually reflect the stoppage
> > >   of a screen reader and callers are better off using
> > >   DisableAccessibility().
> > >
> > > 4. The new UMA Accessibility.EngineUse.TimeUntilStart that was just
> > >    added was not working on all platforms, because some platforms
> > >    use AddAccessibilityModeFlags() and others use
> > >    EnableAccessibility(). Move the UMA code to
> > >    OnAccessibilityAPIUsage() where it will always be hit.
> > >
> > > This relates to a11y performance because it helps build the
> > > foundation for the auto disable refresh by clarifying what
> > > different pieces do and cleaning up code paths.
> > >
> > > Follow-ups:
> > > - Audit calls to OnAccessibilityAPIUsed(), such as from
> > > AXPlatformNodeDelegate::GetRole(). If we don't change that, we'll
> > > always think that there's new API usage every time we Unserialize
> > > from a renderer, which breaks the auto-disable heuristic.
> > > - Use ScopedAccessibilityMode for chrome/browser/apps/app_shim/app_shim_host_mac.cc.
> > >
> > > Bug: 401232343
> > > Change-Id: Id386c378812484aae01e2a93dac90336c0aa7ae3
> > > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6333854
> > > Commit-Queue: Aaron Leventhal <aleventhal@chromium.org>
> > > Reviewed-by: Greg Thompson <grt@chromium.org>
> > > Reviewed-by: Benjamin Beaudry <benjamin.beaudry@microsoft.com>
> > > Reviewed-by: Nasko Oskov <nasko@chromium.org>
> > > Cr-Commit-Position: refs/heads/main@{#1434483}
> >
> > Bug: 401232343,404576872
> > No-Presubmit: true
> > No-Tree-Checks: true
> > No-Try: true
> > Change-Id: I6d43b0fa9d36b7ee0adeaf38b2b04e2b044eea60
> > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6367795
> > Reviewed-by: Aaron Leventhal <aleventhal@chromium.org>
> > Reviewed-by: Takuto Ikuta <tikuta@chromium.org>
> > Commit-Queue: Ming-Ying Chung <mych@chromium.org>
> > Owners-Override: Ming-Ying Chung <mych@chromium.org>
> > Cr-Commit-Position: refs/heads/main@{#1434613}
>
> Bug: 401232343,404576872,404576872
> Change-Id: I1192fe2310402a84f47e4c89114bba8d30ee733f
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6373060
> Reviewed-by: Mark Mentovai <mark@chromium.org>
> Auto-Submit: Aaron Leventhal <aleventhal@chromium.org>
> Commit-Queue: Aaron Leventhal <aleventhal@chromium.org>
> Reviewed-by: Greg Thompson <grt@chromium.org>
> Reviewed-by: Benjamin Beaudry <benjamin.beaudry@microsoft.com>
> Cr-Commit-Position: refs/heads/main@{#1435606}

Bug: 401232343,404576872,404576872
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Change-Id: I565a21249c59a07cecec635a6249a369b6529ccb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6380873
Reviewed-by: Ming-Ying Chung <mych@chromium.org>
Reviewed-by: Jiacheng Guo <gjc@google.com>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Commit-Queue: Peter Pakkenberg <pbirk@chromium.org>
Auto-Submit: Greg Thompson <grt@chromium.org>
Owners-Override: Peter Pakkenberg <pbirk@chromium.org>
Reviewed-by: Greg Thompson <grt@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1435995}
This commit is contained in:
Greg Thompson
2025-03-21 06:14:55 -07:00
committed by Chromium LUCI CQ
parent 8a753c2377
commit eed80c8f6a
14 changed files with 228 additions and 91 deletions

@ -948,11 +948,9 @@ AccessibilityPrivateSetNativeAccessibilityEnabledFunction::Run() {
EXTENSION_FUNCTION_VALIDATE(args()[0].is_bool());
bool enabled = args()[0].GetBool();
if (enabled) {
content::BrowserAccessibilityState::GetInstance()
->EnableProcessAccessibility();
content::BrowserAccessibilityState::GetInstance()->EnableAccessibility();
} else {
content::BrowserAccessibilityState::GetInstance()
->DisableProcessAccessibility();
content::BrowserAccessibilityState::GetInstance()->DisableAccessibility();
}
return RespondNow(NoArguments());
}

@ -265,13 +265,14 @@ void AppShimHost::EnableAccessibilitySupport(
content::BrowserAccessibilityState::GetInstance();
switch (mode) {
case chrome::mojom::AppShimScreenReaderSupportMode::kComplete: {
process_accessibility_mode_ =
accessibility_state->CreateScopedModeForProcess(ui::kAXModeComplete);
accessibility_state->OnScreenReaderDetected();
break;
}
case chrome::mojom::AppShimScreenReaderSupportMode::kPartial: {
process_accessibility_mode_ =
accessibility_state->CreateScopedModeForProcess(ui::kAXModeBasic);
if (!accessibility_state->GetAccessibilityMode().has_mode(
ui::kAXModeBasic.flags())) {
accessibility_state->AddAccessibilityModeFlags(ui::kAXModeBasic);
}
break;
}
}

@ -17,7 +17,6 @@
#include "chrome/browser/web_applications/os_integration/mac/app_shim_launch.h"
#include "chrome/common/mac/app_shim.mojom.h"
#include "components/metrics/histogram_child_process.h"
#include "content/public/browser/scoped_accessibility_mode.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
@ -206,10 +205,6 @@ class AppShimHost : public chrome::mojom::AppShimHost,
// This class is only ever to be used on the UI thread.
THREAD_CHECKER(thread_checker_);
// Will be created if accessibility APIs are needed, e.g. if the VoiceOver
// screen reader is enabled.
std::unique_ptr<content::ScopedAccessibilityMode> process_accessibility_mode_;
// This weak factory is used for launch callbacks only.
base::WeakPtrFactory<AppShimHost> launch_weak_factory_;
};

@ -23,9 +23,7 @@
#include "content/public/browser/browser_accessibility_state.h"
#include "content/public/browser/native_event_processor_mac.h"
#include "content/public/browser/native_event_processor_observer_mac.h"
#include "content/public/browser/scoped_accessibility_mode.h"
#include "content/public/common/content_features.h"
#include "ui/accessibility/ax_mode.h"
#include "ui/base/cocoa/accessibility_focus_overrider.h"
namespace chrome_browser_application_mac {
@ -147,7 +145,6 @@ std::string DescriptionForNSEvent(NSEvent* event) {
base::ObserverList<content::NativeEventProcessorObserver>::Unchecked
_observers;
BOOL _handlingSendEvent;
std::unique_ptr<content::ScopedAccessibilityMode> _scoped_accessibility_mode;
}
+ (void)initialize {
@ -459,14 +456,13 @@ std::string DescriptionForNSEvent(NSEvent* event) {
// Accessibility Support
- (void)enableScreenReaderCompleteMode:(BOOL)enable {
content::BrowserAccessibilityState* accessibility_state =
content::BrowserAccessibilityState::GetInstance();
if (enable) {
if (!_scoped_accessibility_mode) {
_scoped_accessibility_mode =
content::BrowserAccessibilityState::GetInstance()
->CreateScopedModeForProcess(ui::kAXModeComplete);
}
accessibility_state->OnScreenReaderDetected();
} else {
_scoped_accessibility_mode.reset();
accessibility_state->OnScreenReaderStopped();
}
}

@ -195,8 +195,8 @@ void HandleAccessibilityRequestCallback(
PrefService* pref = Profile::FromBrowserContext(current_context)->GetPrefs();
ui::AXMode mode =
content::BrowserAccessibilityState::GetInstance()->GetAccessibilityMode();
bool is_a11y_allowed = content::BrowserAccessibilityState::GetInstance()
->IsAccessibilityAllowed();
bool is_native_enabled = content::BrowserAccessibilityState::GetInstance()
->IsRendererAccessibilityEnabled();
bool native = mode.has_mode(ui::AXMode::kNativeAPIs);
bool web = mode.has_mode(ui::AXMode::kWebContents);
bool text = mode.has_mode(ui::AXMode::kInlineTextBoxes);
@ -206,12 +206,12 @@ void HandleAccessibilityRequestCallback(
// The "native" and "web" flags are disabled if
// --disable-renderer-accessibility is set.
data.Set(kNative, is_a11y_allowed ? (native ? kOn : kOff) : kDisabled);
data.Set(kWeb, is_a11y_allowed ? (web ? kOn : kOff) : kDisabled);
data.Set(kNative, is_native_enabled ? (native ? kOn : kOff) : kDisabled);
data.Set(kWeb, is_native_enabled ? (web ? kOn : kOff) : kDisabled);
// The "text", "extendedProperties" and "html" flags are only
// meaningful if "web" is enabled.
bool is_web_enabled = is_a11y_allowed && web;
bool is_web_enabled = is_native_enabled && web;
data.Set(kText, is_web_enabled ? (text ? kOn : kOff) : kDisabled);
data.Set(kExtendedProperties,
is_web_enabled ? (extendedProperties ? kOn : kOff) : kDisabled);
@ -280,7 +280,7 @@ void HandleAccessibilityRequestCallback(
}
base::Value::Dict descriptor = BuildTargetDescriptor(rvh);
descriptor.Set(kNative, is_a11y_allowed);
descriptor.Set(kNative, is_native_enabled);
descriptor.Set(kExtendedProperties, is_web_enabled && extendedProperties);
descriptor.Set(kWeb, is_web_enabled);
page_list.Append(std::move(descriptor));

@ -335,7 +335,7 @@ IN_PROC_BROWSER_TEST_F(AccessibilityModeTest, ReEnablingDoesNotAlterUniqueIds) {
int32_t unique_id_2 = button_2->GetAXPlatformNode()->GetUniqueId();
// Turn accessibility off again.
BrowserAccessibilityState::GetInstance()->DisableProcessAccessibility();
BrowserAccessibilityState::GetInstance()->ResetAccessibilityMode();
accessibility_mode = web_contents()->GetAccessibilityMode();
ASSERT_TRUE(accessibility_mode.is_mode_off());
EXPECT_EQ(nullptr, GetManager());

@ -2342,8 +2342,7 @@ IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
EXPECT_TRUE(found);
// Remove all accessibility modes.
content::BrowserAccessibilityState::GetInstance()
->DisableProcessAccessibility();
content::BrowserAccessibilityState::GetInstance()->ResetAccessibilityMode();
// Ensure accessibility is not enabled before we begin the test.
EXPECT_TRUE(content::BrowserAccessibilityStateImpl::GetInstance()
@ -6556,7 +6555,7 @@ IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
WebContentsImpl* web_contents =
static_cast<WebContentsImpl*>(shell()->web_contents());
BrowserAccessibilityState::GetInstance()->DisableProcessAccessibility();
BrowserAccessibilityState::GetInstance()->ResetAccessibilityMode();
auto accessibility_mode = web_contents->GetAccessibilityMode();
ASSERT_TRUE(accessibility_mode.is_mode_off());
EXPECT_EQ(nullptr, GetManager());
@ -6584,7 +6583,7 @@ IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
int32_t unique_id_2 = button_2->GetAXPlatformNode()->GetUniqueId();
// Turn accessibility off again.
BrowserAccessibilityState::GetInstance()->DisableProcessAccessibility();
BrowserAccessibilityState::GetInstance()->ResetAccessibilityMode();
accessibility_mode = web_contents->GetAccessibilityMode();
ASSERT_TRUE(accessibility_mode.is_mode_off());
EXPECT_EQ(nullptr, GetManager());

@ -50,6 +50,13 @@ constexpr int kAutoDisableAccessibilityEventCount = 3;
// good for perf. Instead, delay the update task.
constexpr int kOnAccessibilityUsageUpdateDelaySecs = 5;
// How long to wait after `OnScreenReaderStopped` was called before actually
// disabling accessibility support. The main use case is when a screen reader
// or other client is toggled off and on in rapid succession. We don't want to
// destroy the full accessibility tree only to immediately recreate it because
// doing so is bad for performance.
constexpr int kDisableAccessibilitySupportDelaySecs = 2;
// Used for validating the 'basic' bundle parameter for
// --force-renderer-accessibility.
const char kAXModeBundleBasic[] = "basic";
@ -267,6 +274,32 @@ BrowserAccessibilityStateImpl::~BrowserAccessibilityStateImpl() {
g_instance = nullptr;
}
void BrowserAccessibilityStateImpl::OnScreenReaderDetected() {
// Clear any previous, now obsolete, request to disable support.
disable_accessibility_request_time_ = base::TimeTicks();
if (!allow_ax_mode_changes_) {
return;
}
EnableAccessibility();
}
void BrowserAccessibilityStateImpl::OnScreenReaderStopped() {
disable_accessibility_request_time_ = ui::EventTimeForNow();
// If a screen reader or other client using accessibility API is toggled off
// and on in short succession, we risk destroying and recreating large
// accessibility trees unnecessarily which is bad for performance. So we post
// a delayed task here, and only reset accessibility mode if nothing has
// requested accessibility support be re-enabled after that delay has passed.
GetUIThreadTaskRunner({})->PostDelayedTask(
FROM_HERE,
base::BindOnce(
&BrowserAccessibilityStateImpl::MaybeResetAccessibilityMode,
weak_factory_.GetWeakPtr()),
base::Seconds(kDisableAccessibilitySupportDelaySecs));
}
void BrowserAccessibilityStateImpl::OnAssistiveTechFound(
ui::AssistiveTech assistive_tech) {
ax_platform_.NotifyAssistiveTechChanged(assistive_tech);
@ -281,16 +314,66 @@ ui::AssistiveTech BrowserAccessibilityStateImpl::ActiveAssistiveTech() const {
return ui::AXPlatform::GetInstance().active_assistive_tech();
}
void BrowserAccessibilityStateImpl::EnableProcessAccessibility() {
SetProcessMode(ui::kAXModeComplete);
void BrowserAccessibilityStateImpl::EnableAccessibility() {
if (!allow_ax_mode_changes_) {
return;
}
// Track the time since start-up before the kWebContents mode was enabled,
// ensuring we record this value only one time.
if (!has_enabled_accessibility_in_session_ &&
GetAccessibilityMode().has_mode(ui::AXMode::kWebContents)) {
has_enabled_accessibility_in_session_ = true;
UMA_HISTOGRAM_LONG_TIMES_100("Accessibility.EngineUse.TimeUntilStart",
timer_.Elapsed());
}
// Enabling accessibility is generally the result of an accessibility API
// call, so we should also reset the auto-disable accessibility code. The only
// exception is in tests or when a user manually toggles accessibility flags
// in chrome://accessibility.
OnAccessibilityApiUsage();
const ui::AXMode previous_mode = process_accessibility_mode_->mode();
// First disable any non-additive modes that restrict or filter the
// information available in the tree.
const ui::AXMode new_mode =
(previous_mode & ~ui::kAXModeFormControls) | ui::kAXModeComplete;
process_accessibility_mode_ = CreateScopedModeForProcess(new_mode);
}
bool BrowserAccessibilityStateImpl::IsAccessibilityAllowed() {
void BrowserAccessibilityStateImpl::DisableAccessibility() {
ResetAccessibilityMode();
}
bool BrowserAccessibilityStateImpl::IsRendererAccessibilityEnabled() {
return !base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableRendererAccessibility);
}
void BrowserAccessibilityStateImpl::DisableProcessAccessibility() {
void BrowserAccessibilityStateImpl::MaybeResetAccessibilityMode() {
// `OnScreenReaderStopped` sets `disable_accessibility_request_time_`, and
// `OnScreenReaderDetected` clears it. If we no longer have a request time
// to disable accessibility, this delayed task is obsolete.
if (disable_accessibility_request_time_.is_null()) {
return;
}
// `OnScreenReaderStopped` could be called multiple times prior to the delay
// expiring. The value of `disable_accessibility_request_time_` is updated
// for every call. If we're running this task prior to the delay expiring,
// this request time to disable accessibility is obsolete.
if ((base::TimeTicks::Now() - disable_accessibility_request_time_) <
base::Seconds(kDisableAccessibilitySupportDelaySecs)) {
return;
}
ResetAccessibilityMode();
}
void BrowserAccessibilityStateImpl::ResetAccessibilityMode() {
SetProcessMode(ui::AXMode());
}
@ -322,6 +405,10 @@ void BrowserAccessibilityStateImpl::UpdateHistogramsOnUIThread() {
}
ui_thread_histogram_callbacks_.clear();
UMA_HISTOGRAM_BOOLEAN(
"Accessibility.ManuallyEnabled",
!GetAccessibilityMode().is_mode_off() && !allow_ax_mode_changes_);
ui_thread_done_ = true;
if (background_thread_done_callback_) {
std::move(background_thread_done_callback_).Run();
@ -434,7 +521,7 @@ void BrowserAccessibilityStateImpl::OnUserInputEvent() {
now - accessibility_enabled_time_);
accessibility_disabled_time_ = now;
DisableProcessAccessibility();
DisableAccessibility();
}
}
}
@ -456,6 +543,16 @@ void BrowserAccessibilityStateImpl::NotifyWebContentsPreferencesChanged()
}
void BrowserAccessibilityStateImpl::AddAccessibilityModeFlags(ui::AXMode mode) {
if (!allow_ax_mode_changes_) {
return;
}
// Adding an accessibility mode flag is generally the result of an
// accessibility API call, so we should also reset the auto-disable
// accessibility code. The only exception is in tests or when a user manually
// toggles accessibility flags in chrome://accessibility.
OnAccessibilityApiUsage();
// Update process_accessibility_mode_ via SetProcessMode so that the remainder
// of processing is identical to when AXPlatformNode::NotifyAddAXModeFlags()
// is called -- it will defer to AXPlatform::SetMode() to update the global
@ -469,7 +566,15 @@ void BrowserAccessibilityStateImpl::AddAccessibilityModeFlags(ui::AXMode mode) {
void BrowserAccessibilityStateImpl::RemoveAccessibilityModeFlags(
ui::AXMode mode) {
SetProcessMode(process_accessibility_mode_->mode() & ~mode);
// Turning off accessibility or changing the mode will not be allowed if the
// --force-renderer-accessibility or --disable-renderer-accessibility command
// line flags are present, or during testing
if (!allow_ax_mode_changes_) {
return;
}
process_accessibility_mode_ =
CreateScopedModeForProcess(process_accessibility_mode_->mode() & ~mode);
}
base::CallbackListSubscription
@ -491,13 +596,6 @@ void BrowserAccessibilityStateImpl::SetProcessMode(ui::AXMode new_mode) {
return;
}
if (!new_mode.is_mode_off()) {
// Unless the mode is being turned off, setting accessibility flags is
// generally caused by accessibility API call, so we should also reset the
// auto-disable accessibility code.
OnAccessibilityApiUsage();
}
const ui::AXMode previous_mode = GetAccessibilityMode();
if (new_mode == previous_mode) {
return;
@ -527,15 +625,6 @@ void BrowserAccessibilityStateImpl::OnAccessibilityApiUsage() {
base::Unretained(this)),
base::Seconds(kOnAccessibilityUsageUpdateDelaySecs));
}
// Track the time since start-up before the kWebContents mode was enabled,
// ensuring we record this value only one time.
if (!has_enabled_accessibility_in_session_ &&
GetAccessibilityMode().has_mode(ui::AXMode::kWebContents)) {
has_enabled_accessibility_in_session_ = true;
UMA_HISTOGRAM_LONG_TIMES_100("Accessibility.EngineUse.TimeUntilStart",
timer_.Elapsed());
}
}
void BrowserAccessibilityStateImpl::OnInputEvent(

@ -68,15 +68,22 @@ class CONTENT_EXPORT BrowserAccessibilityStateImpl
virtual void InitBackgroundTasks();
// BrowserAccessibilityState implementation.
void EnableProcessAccessibility() override;
void DisableProcessAccessibility() override;
bool IsAccessibilityAllowed() override;
void EnableAccessibility() override;
void DisableAccessibility() override;
bool IsRendererAccessibilityEnabled() override;
ui::AXMode GetAccessibilityMode() override;
ui::AXMode GetAccessibilityModeForBrowserContext(
BrowserContext* browser_context) override;
// TODO(aleventhal): Rename this to Add/RemoveProcessAccessibilityFlags()
void AddAccessibilityModeFlags(ui::AXMode mode) override;
void RemoveAccessibilityModeFlags(ui::AXMode mode) override;
void ResetAccessibilityMode() override;
// These methods indicate the presence of AXMode::kAllProperties, which is
// a misnomer because it is used by many clients, and not just screen readers.
// Methods with "AssistiveTech" in the name deal with actual
// screen reader usage.
// TODO(accessibility) Rename these methods to fix the misnomer.
void OnScreenReaderDetected() override;
void OnScreenReaderStopped() override;
// Some platforms have a strong signal indicating the presence of a
// screen reader and can call in to let us know when one has
// been enabled/disabled.
@ -244,6 +251,8 @@ class CONTENT_EXPORT BrowserAccessibilityStateImpl
// ResetAccessibilityMode(); and applies them to all WebContentses in the
// process. Guaranteed to hold at least an instance with no mode flags set.
std::unique_ptr<ScopedAccessibilityMode> process_accessibility_mode_;
base::WeakPtrFactory<BrowserAccessibilityStateImpl> weak_factory_{this};
};
} // namespace content

@ -42,7 +42,7 @@ class BrowserAccessibilityStateImplTest : public ::testing::Test {
void TearDown() override {
// Disable accessibility so that it does not impact subsequent tests.
state_->DisableProcessAccessibility();
state_->DisableAccessibility();
}
base::test::ScopedFeatureList scoped_feature_list_;
@ -63,7 +63,7 @@ TEST_F(BrowserAccessibilityStateImplTest,
EXPECT_EQ(ui::AXPlatform::GetInstance().GetMode(), ui::AXMode());
// Enable accessibility based on usage of accessibility APIs.
state_->EnableProcessAccessibility();
state_->EnableAccessibility();
// Indicate that an actual screen reader is not running (a screen reader
// will prevent auto-disable from taking place).
state_->SetScreenReaderAppActive(false);
@ -98,7 +98,7 @@ TEST_F(BrowserAccessibilityStateImplTest,
EXPECT_EQ(ui::AXPlatform::GetInstance().GetMode(), ui::AXMode());
// Enable accessibility based on usage of accessibility APIs.
state_->EnableProcessAccessibility();
state_->OnScreenReaderDetected();
// Indicate that an actual screen reader is not running (a screen reader
// will prevent auto-disable from taking place).
state_->SetScreenReaderAppActive(false);
@ -144,10 +144,7 @@ TEST_F(BrowserAccessibilityStateImplTest,
EXPECT_EQ(ui::AXPlatform::GetInstance().GetMode(), ui::AXMode());
// Enable accessibility.
state_->EnableProcessAccessibility();
// Indicate that an actual screen reader is not running (a screen reader
// will prevent auto-disable from taking place).
state_->SetScreenReaderAppActive(false);
state_->OnScreenReaderDetected();
EXPECT_TRUE(state_->IsAccessibleBrowser());
EXPECT_EQ(ui::AXPlatform::GetInstance().GetMode(), ui::kAXModeComplete);
@ -193,7 +190,7 @@ TEST_F(BrowserAccessibilityStateImplTest,
EXPECT_EQ(ui::AXPlatform::GetInstance().GetMode(), ui::AXMode());
// Enable accessibility.
state_->EnableProcessAccessibility();
state_->OnScreenReaderDetected();
EXPECT_TRUE(state_->IsAccessibleBrowser());
EXPECT_EQ(ui::AXPlatform::GetInstance().GetMode(), ui::kAXModeComplete);
@ -210,6 +207,55 @@ TEST_F(BrowserAccessibilityStateImplTest,
EXPECT_EQ(ui::AXPlatform::GetInstance().GetMode(), ui::kAXModeComplete);
}
TEST_F(BrowserAccessibilityStateImplTest, DisableAccessibilityHasADelay) {
// Initially accessibility should be disabled.
EXPECT_FALSE(state_->IsAccessibleBrowser());
// Enable accessibility.
state_->OnScreenReaderDetected();
EXPECT_TRUE(state_->IsAccessibleBrowser());
// After 10 seconds, disable accessibility in response to client being quit.
task_environment_.FastForwardBy(base::Seconds(10));
state_->OnScreenReaderStopped();
// After one second, accessibility support should still be enabled. This is
// because we delay disabling accessibility support in response to the client
// being quit just in case it is about to be toggled back on.
task_environment_.FastForwardBy(base::Seconds(1));
EXPECT_TRUE(state_->IsAccessibleBrowser());
// After the delay has passed without support being re-enabled, accessibility
// should now be disabled.
task_environment_.FastForwardBy(base::Seconds(10));
EXPECT_FALSE(state_->IsAccessibleBrowser());
}
TEST_F(BrowserAccessibilityStateImplTest,
EnableImmediatelyAfterDisablePreventsDisable) {
// Initially accessibility should be disabled.
EXPECT_FALSE(state_->IsAccessibleBrowser());
// Enable accessibility.
state_->OnScreenReaderDetected();
EXPECT_TRUE(state_->IsAccessibleBrowser());
// After 10 seconds, disable accessibility in response to client being quit.
// Then re-enable it immediately. Accessibility support should never get
// disabled because it was re-enabled before the delay to disable support
// had passed.
task_environment_.FastForwardBy(base::Seconds(10));
state_->OnScreenReaderStopped();
EXPECT_TRUE(state_->IsAccessibleBrowser());
task_environment_.FastForwardBy(base::Milliseconds(10));
state_->OnScreenReaderDetected();
for (int i = 0; i < 10; i++) {
task_environment_.FastForwardBy(base::Seconds(i));
EXPECT_TRUE(state_->IsAccessibleBrowser());
}
}
namespace {
using ::testing::_;
@ -232,11 +278,11 @@ TEST_F(BrowserAccessibilityStateImplTest,
// Enable accessibility.
EXPECT_CALL(mock_observer, OnAXModeAdded(ui::kAXModeComplete));
state_->EnableProcessAccessibility();
state_->OnScreenReaderDetected();
::testing::Mock::VerifyAndClearExpectations(&mock_observer);
// A second call should be a no-op.
state_->EnableProcessAccessibility();
state_->OnScreenReaderDetected();
::testing::Mock::VerifyAndClearExpectations(&mock_observer);
}

@ -481,7 +481,7 @@ void DumpAccessibilityTestBase::RunTestForPlatform(
// Start with no AXMode, so that in case the test was run with
// --force-renderer-accessibility, we can still set the correct mode for the
// test, e.g. form controls mode.
BrowserAccessibilityState::GetInstance()->DisableProcessAccessibility();
BrowserAccessibilityState::GetInstance()->DisableAccessibility();
if (enable_accessibility_after_navigating_ &&
web_contents->GetAccessibilityMode().is_mode_off()) {

@ -586,7 +586,7 @@ void WebContentsAccessibilityAndroid::DisableRendererAccessibility(
// Turn off accessibility on the renderer side by resetting the AXMode.
BrowserAccessibilityStateImpl* accessibility_state =
BrowserAccessibilityStateImpl::GetInstance();
accessibility_state->DisableProcessAccessibility();
accessibility_state->ResetAccessibilityMode();
}
void WebContentsAccessibilityAndroid::ReEnableRendererAccessibility(
@ -2209,7 +2209,7 @@ void JNI_WebContentsAccessibilityImpl_SetBrowserAXMode(
// When the browser is not yet accessible, then set the AXMode to
// |ui::kAXModeComplete| for all web contents.
if (!accessibility_state->IsAccessibleBrowser()) {
accessibility_state->EnableProcessAccessibility();
accessibility_state->OnScreenReaderDetected();
}
return;
}

@ -32,24 +32,15 @@ class CONTENT_EXPORT BrowserAccessibilityState {
static BrowserAccessibilityState* GetInstance();
// Enables accessibility for all running tabs.
// Called when an accessibility client is detected.
// It is often preferable to use ScopedAccessibilityMode.
// The process AXMode is the default used for new WebContents and pages.
// When no mode argument is passed, ui::kAXModeComplete is assumed.
virtual void EnableProcessAccessibility() = 0;
virtual void EnableAccessibility() = 0;
// Disables accessibility for all running tabs. (Only if accessibility is not
// required by a command line flag or by a platform requirement.)
// Called when all AXModes should be turned off.
// By default, new WebContents and pages will not have accessibility on.
virtual void DisableProcessAccessibility() = 0;
virtual void DisableAccessibility() = 0;
// Returns true if accessibility is not disallowed via
// Returns true if renderer accessibility is not disabled via
// --disable-renderer-accessibility on the process's command line.
// Note: the command line flag --disable-renderer-accessibility is a misnomer
// because it also disables accessibility in non-renderer contexts, such as
// UI.
virtual bool IsAccessibilityAllowed() = 0;
virtual bool IsRendererAccessibilityEnabled() = 0;
// Returns the effective accessibility mode for the process. Individual
// WebContentses may have an effective mode that is a superset of this as a
@ -91,6 +82,22 @@ class CONTENT_EXPORT BrowserAccessibilityState {
// accessibility mode bitmap.
virtual void RemoveAccessibilityModeFlags(ui::AXMode mode) = 0;
// DEPRECATED. Resets accessibility to the platform default for all running
// tabs. This is probably off, but may be on, if
// --force_renderer_accessibility is passed, or EditableTextOnly if this is
// Win7.
virtual void ResetAccessibilityMode() = 0;
// Called when an accessibility client is detected, using a heuristic.
// These methods indicate the presence of AXMode::kExtendedProperties.
// The current method name is a misnomer because it is used by many clients,
// and not just screen readers.
// TODO(accessibility) Remove this method.
virtual void OnScreenReaderDetected() = 0;
// Called when kExtendedProperties mode should be turned off.
virtual void OnScreenReaderStopped() = 0;
// Some platforms have a strong signal indicating the presence of a
// screen reader and can call in to let us know when one has
// been enabled/disabled. This should be called for screen readers only.

@ -237,8 +237,7 @@ static const char kAllTracingCategories[] = "*";
// Enable Accessibility if VoiceOver is already running.
if (UIAccessibilityIsVoiceOverRunning()) {
content::BrowserAccessibilityState::GetInstance()
->EnableProcessAccessibility();
content::BrowserAccessibilityState::GetInstance()->OnScreenReaderDetected();
}
// Register for VoiceOver notifications.
@ -422,11 +421,9 @@ static const char kAllTracingCategories[] = "*";
content::BrowserAccessibilityState* accessibility_state =
content::BrowserAccessibilityState::GetInstance();
if (UIAccessibilityIsVoiceOverRunning()) {
accessibility_state->EnableProcessAccessibility();
accessibility_state->SetScreenReaderAppActive(true);
accessibility_state->OnScreenReaderDetected();
} else {
accessibility_state->DisableProcessAccessibility();
accessibility_state->SetScreenReaderAppActive(false);
accessibility_state->OnScreenReaderStopped();
}
}
@end