diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 4f1f5698eea9b..e2608cd9d96ed 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -227,6 +227,7 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.OptionalInt; import java.util.Queue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; @@ -10865,6 +10866,12 @@ public final class ViewRootImpl implements ViewParent, public View mSource; public long mLastEventTimeMillis; + /** + * Keep track of action that caused the event. + * This is empty if there's no performing actions for pending events. + * This is zero if there're multiple events performed for pending events. + */ + @NonNull public OptionalInt mAction = OptionalInt.empty(); /** * Override for {@link AccessibilityEvent#originStackTrace} to provide the stack trace * of the original {@link #runOrPost} call instead of one for sending the delayed event @@ -10888,6 +10895,7 @@ public final class ViewRootImpl implements ViewParent, AccessibilityEvent event = AccessibilityEvent.obtain(); event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); event.setContentChangeTypes(mChangeTypes); + if (mAction.isPresent()) event.setAction(mAction.getAsInt()); if (AccessibilityEvent.DEBUG_ORIGIN) event.originStackTrace = mOrigin; source.sendAccessibilityEventUnchecked(event); } else { @@ -10896,6 +10904,7 @@ public final class ViewRootImpl implements ViewParent, // In any case reset to initial state. source.resetSubtreeAccessibilityStateChanged(); mChangeTypes = 0; + mAction = OptionalInt.empty(); if (AccessibilityEvent.DEBUG_ORIGIN) mOrigin = null; } @@ -10925,10 +10934,27 @@ public final class ViewRootImpl implements ViewParent, } mSource = (predecessor != null) ? predecessor : source; mChangeTypes |= changeType; + + final int performingAction = mAccessibilityManager.getPerformingAction(); + if (performingAction != 0) { + if (mAction.isEmpty()) { + mAction = OptionalInt.of(performingAction); + } else if (mAction.getAsInt() != performingAction) { + // Multiple actions are performed for pending events. We cannot decide one + // action here. + // We're doing best effort to set action value, and it's fine to set + // no action this case. + mAction = OptionalInt.of(0); + } + } + return; } mSource = source; mChangeTypes = changeType; + if (mAccessibilityManager.getPerformingAction() != 0) { + mAction = OptionalInt.of(mAccessibilityManager.getPerformingAction()); + } if (AccessibilityEvent.DEBUG_ORIGIN) { mOrigin = Thread.currentThread().getStackTrace(); } diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java index 9abbba923a669..8e335e8837ef3 100644 --- a/core/java/android/view/accessibility/AccessibilityManager.java +++ b/core/java/android/view/accessibility/AccessibilityManager.java @@ -1274,6 +1274,15 @@ public final class AccessibilityManager { mPerformingAction = actionId; } + /** + * Get the id of {@link AccessibilityNodeInfo.AccessibilityAction} currently being performed. + * + * @hide + */ + public int getPerformingAction() { + return mPerformingAction; + } + /** * Registers a {@link HighTextContrastChangeListener} for changes in * the global high text contrast state of the system.