summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java94
1 files changed, 91 insertions, 3 deletions
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index cbeb01a68778..4806514a0e13 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -187,6 +187,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
// their capabilities are ready.
private static final int WAIT_MOTION_INJECTOR_TIMEOUT_MILLIS = 1000;
+
+ // This postpones state changes events when a window doesn't exist with the expectation that
+ // a race condition will resolve. It is determined by observing elapsed time of the
+ // corresponding window added.
+ //TODO(b/230810909) : Fix it with a better idea.
+ private static final int POSTPONE_WINDOW_STATE_CHANGED_EVENT_TIMEOUT_MILLIS = 500;
+
private static final String FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE =
"registerUiTestAutomationService";
@@ -272,6 +279,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
private final AccessibilityTraceManager mTraceManager;
private final CaptioningManagerImpl mCaptioningManagerImpl;
+ private final List<SendWindowStateChangedEventRunnable> mSendWindowStateChangedEventRunnables =
+ new ArrayList<>();
+
private int mCurrentUserId = UserHandle.USER_SYSTEM;
//TODO: Remove this hack
@@ -930,11 +940,15 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
final WindowManagerInternal wm = LocalServices.getService(
WindowManagerInternal.class);
wm.computeWindowsForAccessibility(displayId);
+ // The App side sends a event to notify that the window visible or focused,
+ // but the window information in framework is not updated yet, so we postpone it.
+ if (postponeWindowStateEvent(event)) {
+ return;
+ }
}
+
synchronized (mLock) {
- notifyAccessibilityServicesDelayedLocked(event, false);
- notifyAccessibilityServicesDelayedLocked(event, true);
- mUiAutomationManager.sendAccessibilityEventLocked(event);
+ dispatchAccessibilityEventLocked(event);
}
}
@@ -943,6 +957,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
}
+ private void dispatchAccessibilityEventLocked(AccessibilityEvent event) {
+ notifyAccessibilityServicesDelayedLocked(event, false);
+ notifyAccessibilityServicesDelayedLocked(event, true);
+ mUiAutomationManager.sendAccessibilityEventLocked(event);
+ }
+
private void sendAccessibilityEventToInputFilter(AccessibilityEvent event) {
synchronized (mLock) {
if (mHasInputFilter && mInputFilter != null) {
@@ -3339,6 +3359,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
@Override
public void sendAccessibilityEventForCurrentUserLocked(AccessibilityEvent event) {
+ if (event.getWindowChanges() == AccessibilityEvent.WINDOWS_CHANGE_ADDED) {
+ // We need to ensure the window is available before sending pending
+ // window_state_changed events.
+ sendPendingWindowStateChangedEventsForAvailableWindowLocked(event.getWindowId());
+ }
sendAccessibilityEventLocked(event, mCurrentUserId);
}
@@ -4505,4 +4530,67 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
}
}
+
+ private final class SendWindowStateChangedEventRunnable implements Runnable {
+
+ private final AccessibilityEvent mPendingEvent;
+ private final int mWindowId;
+
+ SendWindowStateChangedEventRunnable(@NonNull AccessibilityEvent event) {
+ mPendingEvent = event;
+ mWindowId = event.getWindowId();
+ }
+
+ @Override
+ public void run() {
+ synchronized (mLock) {
+ Slog.w(LOG_TAG, " wait for adding window timeout: " + mWindowId);
+ sendPendingEventLocked();
+ }
+ }
+
+ private void sendPendingEventLocked() {
+ mSendWindowStateChangedEventRunnables.remove(this);
+ dispatchAccessibilityEventLocked(mPendingEvent);
+ }
+
+ private int getWindowId() {
+ return mWindowId;
+ }
+ }
+
+ void sendPendingWindowStateChangedEventsForAvailableWindowLocked(int windowId) {
+ final int eventSize = mSendWindowStateChangedEventRunnables.size();
+ for (int i = eventSize - 1; i >= 0; i--) {
+ final SendWindowStateChangedEventRunnable runnable =
+ mSendWindowStateChangedEventRunnables.get(i);
+ if (runnable.getWindowId() == windowId) {
+ mMainHandler.removeCallbacks(runnable);
+ runnable.sendPendingEventLocked();
+ }
+ }
+ }
+
+ /**
+ * Postpones the {@link AccessibilityEvent} with
+ * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED}
+ * which doesn't have the corresponding window until the window is added or timeout.
+ *
+ * @return {@code true} if the event is postponed.
+ */
+ private boolean postponeWindowStateEvent(AccessibilityEvent event) {
+ synchronized (mLock) {
+ final int resolvedWindowId = mA11yWindowManager.resolveParentWindowIdLocked(
+ event.getWindowId());
+ if (mA11yWindowManager.findWindowInfoByIdLocked(resolvedWindowId) != null) {
+ return false;
+ }
+ final SendWindowStateChangedEventRunnable pendingRunnable =
+ new SendWindowStateChangedEventRunnable(new AccessibilityEvent(event));
+ mMainHandler.postDelayed(pendingRunnable,
+ POSTPONE_WINDOW_STATE_CHANGED_EVENT_TIMEOUT_MILLIS);
+ mSendWindowStateChangedEventRunnables.add(pendingRunnable);
+ return true;
+ }
+ }
}