diff options
3 files changed, 32 insertions, 13 deletions
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index b0aa5c3a77e0..7e5109637855 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -8877,7 +8877,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @hide */ public void clearAccessibilityFocus() { - clearAccessibilityFocusNoCallbacks(); + clearAccessibilityFocusNoCallbacks(0); // Clear the global reference of accessibility focus if this view or // any of its descendants had accessibility focus. This will NOT send @@ -8920,14 +8920,27 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * Clears accessibility focus without calling any callback methods * normally invoked in {@link #clearAccessibilityFocus()}. This method - * is used for clearing accessibility focus when giving this focus to - * another view. + * is used separately from that one for clearing accessibility focus when + * giving this focus to another view. + * + * @param action The action, if any, that led to focus being cleared. Set to + * AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS to specify that focus is moving within + * the window. */ - void clearAccessibilityFocusNoCallbacks() { + void clearAccessibilityFocusNoCallbacks(int action) { if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0) { mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_FOCUSED; invalidate(); - sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); + if (AccessibilityManager.getInstance(mContext).isEnabled()) { + AccessibilityEvent event = AccessibilityEvent.obtain( + AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); + event.setAction(action); + if (mAccessibilityDelegate != null) { + mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); + } else { + sendAccessibilityEventUnchecked(event); + } + } } } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 5b2877faef02..a324767ac4ed 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -3071,7 +3071,8 @@ public final class ViewRootImpl implements ViewParent, // Clear accessibility focus on the host after clearing state since // this method may be reentrant. - focusHost.clearAccessibilityFocusNoCallbacks(); + focusHost.clearAccessibilityFocusNoCallbacks( + AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); AccessibilityNodeProvider provider = focusHost.getAccessibilityNodeProvider(); if (provider != null) { @@ -3088,7 +3089,8 @@ public final class ViewRootImpl implements ViewParent, } if (mAccessibilityFocusedHost != null) { // Clear accessibility focus in the view. - mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks(); + mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks( + AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); } // Set the new focus host and node. @@ -6623,7 +6625,7 @@ public final class ViewRootImpl implements ViewParent, // Error state: virtual view with no provider. Clear focus. mAccessibilityFocusedHost = null; mAccessibilityFocusedVirtualView = null; - focusedHost.clearAccessibilityFocusNoCallbacks(); + focusedHost.clearAccessibilityFocusNoCallbacks(0); return; } @@ -6673,7 +6675,7 @@ public final class ViewRootImpl implements ViewParent, if (mAccessibilityFocusedVirtualView == null) { // Error state: The node no longer exists. Clear focus. mAccessibilityFocusedHost = null; - focusedHost.clearAccessibilityFocusNoCallbacks(); + focusedHost.clearAccessibilityFocusNoCallbacks(0); // This will probably fail, but try to keep the provider's internal // state consistent by clearing focus. diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 27417332f7d1..adf44d40de5c 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -439,7 +439,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } if (mSecurityPolicy.canDispatchAccessibilityEventLocked(event)) { mSecurityPolicy.updateActiveAndAccessibilityFocusedWindowLocked(event.getWindowId(), - event.getSourceNodeId(), event.getEventType()); + event.getSourceNodeId(), event.getEventType(), event.getAction()); mSecurityPolicy.updateEventSourceLocked(event); notifyAccessibilityServicesDelayedLocked(event, false); notifyAccessibilityServicesDelayedLocked(event, true); @@ -3829,7 +3829,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } public void updateActiveAndAccessibilityFocusedWindowLocked(int windowId, long nodeId, - int eventType) { + int eventType, int eventAction) { // The active window is either the window that has input focus or // the window that the user is currently touching. If the user is // touching a window that does not have input focus as soon as the @@ -3882,8 +3882,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { if (mAccessibilityFocusNodeId == nodeId) { mAccessibilityFocusNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID; } - if (mAccessibilityFocusNodeId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID - && mAccessibilityFocusedWindowId == windowId) { + // Clear the window with focus if it no longer has focus and we aren't + // just moving focus from one view to the other in the same window + if ((mAccessibilityFocusNodeId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID) + && (mAccessibilityFocusedWindowId == windowId) + && (eventAction != AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS) + ) { mAccessibilityFocusedWindowId = INVALID_WINDOW_ID; } } |