| Index: content/public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java
|
| diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java
|
| index ce84964decaae1e9f9d1c85508cc257abe53f7e6..d386d6d91a950a2211dfaca269718e5636415f13 100644
|
| --- a/content/public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java
|
| +++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java
|
| @@ -37,6 +37,9 @@ import java.util.Locale;
|
| public class BrowserAccessibilityManager {
|
| private static final String TAG = "BrowserAccessibilityManager";
|
|
|
| + private static final int WINDOW_CONTENT_CHANGED_DELAY_MS = 500;
|
| + private static final int ACCESSIBILITY_FOCUS_LOCATION_CHANGED_DELAY_MS = 100;
|
| +
|
| // Constants from AccessibilityNodeInfo defined in the K SDK.
|
| private static final int ACTION_COLLAPSE = 0x00080000;
|
| private static final int ACTION_EXPAND = 0x00040000;
|
| @@ -45,7 +48,6 @@ public class BrowserAccessibilityManager {
|
| private static final int ACTION_SET_TEXT = 0x200000;
|
| private static final String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE =
|
| "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE";
|
| - private static final int WINDOW_CONTENT_CHANGED_DELAY_MS = 500;
|
|
|
| // Constants from AccessibilityNodeInfo defined in the M SDK.
|
| // Source: https://developer.android.com/reference/android/R.id.html
|
| @@ -75,6 +77,7 @@ public class BrowserAccessibilityManager {
|
| private int mSelectionEndIndex;
|
| protected int mAccessibilityFocusId;
|
| private Runnable mSendWindowContentChangedRunnable;
|
| + private Runnable mAccessibilityFocusLocationChangedRunnable;
|
|
|
| /**
|
| * Create a BrowserAccessibilityManager object, which is owned by the C++
|
| @@ -237,6 +240,12 @@ public class BrowserAccessibilityManager {
|
| if (mAccessibilityFocusId == virtualViewId) {
|
| mAccessibilityFocusId = View.NO_ID;
|
| mAccessibilityFocusRect = null;
|
| + // If we had a pending callback to update the location of the previous object
|
| + // with accessibility focus, remove it.
|
| + if (mAccessibilityFocusLocationChangedRunnable != null) {
|
| + mView.removeCallbacks(mAccessibilityFocusLocationChangedRunnable);
|
| + mAccessibilityFocusLocationChangedRunnable = null;
|
| + }
|
| }
|
| return true;
|
| case AccessibilityNodeInfo.ACTION_CLICK:
|
| @@ -537,6 +546,20 @@ public class BrowserAccessibilityManager {
|
| mSelectionStartIndex = 0;
|
| mSelectionEndIndex = 0;
|
|
|
| + // If we had a pending callback to update the location of the previous object with
|
| + // accessibility focus, remove it.
|
| + if (mAccessibilityFocusLocationChangedRunnable != null) {
|
| + mView.removeCallbacks(mAccessibilityFocusLocationChangedRunnable);
|
| + mAccessibilityFocusLocationChangedRunnable = null;
|
| + }
|
| +
|
| + // Call nativeSetAccessibilityFocus. For the most part Chrome doesn't have a
|
| + // concept of accessibility focus, but we do two things: (1) auto-focus certain
|
| + // roles like links when they get accessibility focus and (2) load inline text boxes
|
| + // for nodes when they get accessibility focus since inline text boxes are expensive
|
| + // to load and on Android they're only needed for nodes that have input focus or
|
| + // accessibility focus.
|
| + //
|
| // Calling nativeSetAccessibilityFocus will asynchronously load inline text boxes for
|
| // this node and its subtree. If accessibility focus is on anything other than
|
| // the root, do it - otherwise set it to -1 so we don't load inline text boxes
|
| @@ -566,6 +589,47 @@ public class BrowserAccessibilityManager {
|
| }
|
|
|
| /**
|
| + * Work around a bug in the Android framework where if the object with accessibility
|
| + * focus moves, the accessibility focus rect is not updated - both the visual highlight,
|
| + * and the location on the screen that's clicked if you double-tap. To work around this,
|
| + * when we know the object with accessibility focus moved, move focus away and then
|
| + * move focus right back to it, which tricks Android into updating its bounds.
|
| + *
|
| + * Do this after a short delay because sometimes the change to the object with accessibility
|
| + * focus happens just before navigating somewhere else.
|
| + */
|
| + private void updateAccessibilityFocusLocationAfterDelay() {
|
| + if (mNativeObj == 0) return;
|
| +
|
| + if (mAccessibilityFocusLocationChangedRunnable != null) return;
|
| +
|
| + mAccessibilityFocusLocationChangedRunnable = new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + updateAccessibilityFocusLocation();
|
| + }
|
| + };
|
| +
|
| + mView.postDelayed(mAccessibilityFocusLocationChangedRunnable,
|
| + ACCESSIBILITY_FOCUS_LOCATION_CHANGED_DELAY_MS);
|
| + }
|
| +
|
| + /**
|
| + * See updateAccessibilityFocusLocationAfterDelay for details.
|
| + */
|
| + private void updateAccessibilityFocusLocation() {
|
| + // This can be called from a timeout, so we need to make sure we're still valid.
|
| + if (mNativeObj == 0 || mContentViewCore == null || mView == null) return;
|
| +
|
| + if (mAccessibilityFocusLocationChangedRunnable != null) {
|
| + mView.removeCallbacks(mAccessibilityFocusLocationChangedRunnable);
|
| + mAccessibilityFocusLocationChangedRunnable = null;
|
| + }
|
| +
|
| + moveAccessibilityFocusToIdAndRefocusIfNeeded(mAccessibilityFocusId);
|
| + }
|
| +
|
| + /**
|
| * Send a WINDOW_CONTENT_CHANGED event after a short delay. This helps throttle such
|
| * events from firing too quickly during animations, for example.
|
| */
|
| @@ -1001,17 +1065,14 @@ public class BrowserAccessibilityManager {
|
|
|
| node.setBoundsInScreen(rect);
|
|
|
| - // Work around a bug in the Android framework where if the object with accessibility
|
| - // focus moves, the accessibility focus rect is not updated - both the visual highlight,
|
| - // and the location on the screen that's clicked if you double-tap. To work around this,
|
| - // when we know the object with accessibility focus moved, move focus away and then
|
| - // move focus right back to it, which tricks Android into updating its bounds.
|
| + // If this is the node with accessibility focus, ensure that its location on-screen
|
| + // is up-to-date.
|
| if (virtualViewId == mAccessibilityFocusId && virtualViewId != mCurrentRootId) {
|
| if (mAccessibilityFocusRect == null) {
|
| mAccessibilityFocusRect = rect;
|
| } else if (!mAccessibilityFocusRect.equals(rect)) {
|
| mAccessibilityFocusRect = rect;
|
| - moveAccessibilityFocusToIdAndRefocusIfNeeded(virtualViewId);
|
| + updateAccessibilityFocusLocationAfterDelay();
|
| }
|
| }
|
| }
|
|
|