[Auto-disable Accessibility] Disable feature for WebView and CCT embedders
This CL continues the Auto-disable Accessibility feature work. With this CL we disable the feature for CCT and WebViews. We also update the AccessibilityState to log changes to the state for convenience when debugging. AX-Relnotes: N/A Bug: 1430202, b/265493191 Change-Id: I17cc21297bfc245cb22cfec2d0a1280b82eac5dc Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4742969 Reviewed-by: Amanda Lin Dietz <aldietz@google.com> Reviewed-by: Jinsuk Kim <jinsukkim@chromium.org> Code-Coverage: Findit <findit-for-me@appspot.gserviceaccount.com> Commit-Queue: Mark Schillaci <mschillaci@google.com> Cr-Commit-Position: refs/heads/main@{#1181194}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
4915ff15bf
commit
c39c7d2fdf
chrome/android/java/src/org/chromium/chrome/browser/accessibility
content/public/android
java
src
org
chromium
content
browser
content_public
javatests
src
org
chromium
content
browser
accessibility
ui/accessibility/android/java/src/org/chromium/ui/accessibility
@@ -57,6 +57,9 @@ public class AccessibilityTabHelper extends EmptyTabObserver implements UserData
|
||||
|
||||
// Enable image descriptions feature normally, but not for Chrome Custom Tabs.
|
||||
wcax.setIsImageDescriptionsCandidate(!tab.isCustomTab());
|
||||
|
||||
// Enable Auto-disable Accessibility feature normally, but not for Chrome Custom Tabs.
|
||||
wcax.setIsAutoDisableAccessibilityCandidate(!tab.isCustomTab());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -6,6 +6,8 @@ package org.chromium.content.browser.accessibility;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
/**
|
||||
* Helper class that handles the logic and state behind the "Auto Disable" accessibility feature.
|
||||
* Clients need to cancel/reset the timer based on their implementation (e.g. on a user action).
|
||||
@@ -66,4 +68,12 @@ public class AutoDisableAccessibilityHandler {
|
||||
mClient.onDisabled();
|
||||
mHasPendingTimer = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true when there is a pending timer.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public boolean hasPendingTimer() {
|
||||
return mHasPendingTimer;
|
||||
}
|
||||
}
|
||||
|
@@ -222,6 +222,7 @@ public class WebContentsAccessibilityImpl extends AccessibilityNodeProviderCompa
|
||||
private final AutoDisableAccessibilityHandler mAutoDisableAccessibilityHandler;
|
||||
private boolean mIsCurrentlyAutoDisabled;
|
||||
private int mAutoDisableUsageCounter;
|
||||
private boolean mIsAutoDisableAccessibilityCandidate;
|
||||
|
||||
/**
|
||||
* Create a WebContentsAccessibilityImpl object.
|
||||
@@ -509,6 +510,15 @@ public class WebContentsAccessibilityImpl extends AccessibilityNodeProviderCompa
|
||||
ResettersForTesting.register(() -> mTracker = oldValue);
|
||||
}
|
||||
|
||||
public void setIsAutoDisableAccessibilityCandidateForTesting(
|
||||
boolean isAutoDisableAccessibilityCandidate) {
|
||||
mIsAutoDisableAccessibilityCandidate = isAutoDisableAccessibilityCandidate;
|
||||
}
|
||||
|
||||
public boolean hasAnyPendingTimersForTesting() {
|
||||
return mAutoDisableAccessibilityHandler.hasPendingTimer();
|
||||
}
|
||||
|
||||
public void signalEndOfTestForTesting() {
|
||||
WebContentsAccessibilityImplJni.get().signalEndOfTestForTesting(mNativeObj);
|
||||
}
|
||||
@@ -705,7 +715,8 @@ public class WebContentsAccessibilityImpl extends AccessibilityNodeProviderCompa
|
||||
// disabled then re-enabled the renderer multiple times for this instance, then we
|
||||
// will return early and keep accessibility enabled to prevent further churn.
|
||||
if (ContentFeatureMap.isEnabled(ContentFeatureList.AUTO_DISABLE_ACCESSIBILITY_V2)) {
|
||||
if (mAutoDisableUsageCounter >= AUTO_DISABLE_SINGLE_INSTANCE_TOGGLE_LIMIT) {
|
||||
if (mAutoDisableUsageCounter >= AUTO_DISABLE_SINGLE_INSTANCE_TOGGLE_LIMIT
|
||||
|| !mIsAutoDisableAccessibilityCandidate) {
|
||||
mAutoDisableAccessibilityHandler.cancelDisableTimer();
|
||||
return;
|
||||
}
|
||||
@@ -955,6 +966,12 @@ public class WebContentsAccessibilityImpl extends AccessibilityNodeProviderCompa
|
||||
mIsImageDescriptionsCandidate = isImageDescriptionsCandidate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIsAutoDisableAccessibilityCandidate(
|
||||
boolean isAutoDisableAccessibilityCandidate) {
|
||||
mIsAutoDisableAccessibilityCandidate = isAutoDisableAccessibilityCandidate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProvideVirtualStructure(
|
||||
final ViewStructure structure, final boolean ignoreScrollOffset) {
|
||||
|
@@ -85,6 +85,12 @@ public interface WebContentsAccessibility {
|
||||
*/
|
||||
void setIsImageDescriptionsCandidate(boolean isImageDescriptionsCandidate);
|
||||
|
||||
/**
|
||||
* Sets whether or not this instance is a candidate for the auto-disable accessibility feature,
|
||||
* if it is enabled. This feature is dependent on embedder behavior and accessibility state.
|
||||
*/
|
||||
void setIsAutoDisableAccessibilityCandidate(boolean isAutoDisableAccessibilityCandidate);
|
||||
|
||||
/**
|
||||
* Called when autofill popup is displayed. Used to upport navigation through the view.
|
||||
* @param autofillPopupView The displayed autofill popup view.
|
||||
|
@@ -161,6 +161,8 @@ public class WebContentsAccessibilityTest {
|
||||
private static final Map<String, Boolean> ON_DEMAND_ON_AXMODES_ON =
|
||||
Map.of(ContentFeatureList.ON_DEMAND_ACCESSIBILITY_EVENTS, true,
|
||||
ContentFeatureList.ACCESSIBILITY_PERFORMANCE_FILTERING, true);
|
||||
private static final Map<String, Boolean> AUTO_DISABLE_V2_ON =
|
||||
Map.of(ContentFeatureList.AUTO_DISABLE_ACCESSIBILITY_V2, true);
|
||||
|
||||
// Constant values for unit tests
|
||||
private static final int UNSUPPRESSED_EXPECTED_COUNT = 15;
|
||||
@@ -745,6 +747,27 @@ public class WebContentsAccessibilityTest {
|
||||
() -> createAccessibilityNodeInfo(vvid2).isAccessibilityFocused());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that Auto-disable Accessibility timers are not set for instances that are not
|
||||
* candidates for the feature (e.g. WebView, CCT).
|
||||
*/
|
||||
@Test
|
||||
@SmallTest
|
||||
public void testAutoDisableAccessibility_candidatesCheck() throws Throwable {
|
||||
setupTestWithHTML("<p>This is a test</p>");
|
||||
waitForNodeMatching(sTextMatcher, "This is a test");
|
||||
|
||||
// Enable feature, but set this instance as not a candidate.
|
||||
FeatureList.setTestFeatures(AUTO_DISABLE_V2_ON);
|
||||
mActivityTestRule.mWcax.setIsAutoDisableAccessibilityCandidateForTesting(false);
|
||||
|
||||
// Changing the accessibility state will refresh the native state.
|
||||
TestThreadUtils.runOnUiThreadBlocking(
|
||||
() -> { AccessibilityState.setIsTextShowPasswordEnabledForTesting(true); });
|
||||
|
||||
Assert.assertFalse(mActivityTestRule.mWcax.hasAnyPendingTimersForTesting());
|
||||
}
|
||||
|
||||
// ------------------ Tests of AccessibilityNodeInfo caching mechanism ------------------ //
|
||||
|
||||
/**
|
||||
|
@@ -25,6 +25,7 @@ import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
import android.view.autofill.AutofillManager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.chromium.base.ActivityState;
|
||||
@@ -128,6 +129,20 @@ public class AccessibilityState {
|
||||
this.isTextShowPasswordEnabled = isTextShowPasswordEnabled;
|
||||
this.isOnlyPasswordManagersEnabled = isOnlyPasswordManagersEnabled;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "State{"
|
||||
+ "isScreenReaderEnabled=" + isScreenReaderEnabled
|
||||
+ ", isTouchExplorationEnabled=" + isTouchExplorationEnabled
|
||||
+ ", isPerformGesturesEnabled=" + isPerformGesturesEnabled
|
||||
+ ", isAnyAccessibilityServiceEnabled=" + isAnyAccessibilityServiceEnabled
|
||||
+ ", isAccessibilityToolPresent=" + isAccessibilityToolPresent
|
||||
+ ", isSpokenFeedbackServicePresent=" + isSpokenFeedbackServicePresent
|
||||
+ ", isTextShowPasswordEnabled=" + isTextShowPasswordEnabled
|
||||
+ ", isOnlyPasswordManagersEnabled=" + isOnlyPasswordManagersEnabled + '}';
|
||||
}
|
||||
}
|
||||
|
||||
// Analysis of the most popular accessibility services on Android suggests
|
||||
@@ -543,6 +558,7 @@ public class AccessibilityState {
|
||||
State oldState = sState;
|
||||
sState = newState;
|
||||
|
||||
Log.v(TAG, "New AccessibilityState: " + sState.toString());
|
||||
for (Listener listener : sListeners) {
|
||||
listener.onAccessibilityStateChanged(oldState, newState);
|
||||
}
|
||||
|
Reference in New Issue
Block a user