Ensure all events from a showing window are dispatched.
Accessibility services may opt-in to introspect the interactive
windows on the screen. If window introspection is enabled there
is a case where some events from a showing window are received
before the updated window state from the window manager. Now the
window manager sends over the windows before notifying the app
for the focus change.
bug:18625996
Change-Id: Ic481e01efbe12dc92f090f799feeb236672fc7b3
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 0cbf03a..08754f9 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -159,11 +159,15 @@
}
}
- public void onWindowFocusChangedLocked() {
+ public void onWindowFocusChangedNotLocked() {
// Not relevant for the display magnifier.
- if (mWindowsForAccessibilityObserver != null) {
- mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
+ WindowsForAccessibilityObserver observer = null;
+ synchronized (mWindowManagerService) {
+ observer = mWindowsForAccessibilityObserver;
+ }
+ if (observer != null) {
+ observer.performComputeChangedWindowsNotLocked();
}
}
@@ -937,14 +941,13 @@
computeChangedWindows();
}
+ public void performComputeChangedWindowsNotLocked() {
+ mHandler.removeMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS);
+ computeChangedWindows();
+ }
+
public void scheduleComputeChangedWindowsLocked() {
- // If focus changed, compute changed windows immediately as the focused window
- // is used by the accessibility manager service to determine the active window.
- if (mWindowManagerService.mCurrentFocus != null
- && mWindowManagerService.mCurrentFocus != mWindowManagerService.mLastFocus) {
- mHandler.removeMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS);
- computeChangedWindows();
- } else if (!mHandler.hasMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS)) {
+ if (!mHandler.hasMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS)) {
mHandler.sendEmptyMessageDelayed(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS,
mRecurringAccessibilityEventsIntervalMillis);
}
@@ -955,6 +958,9 @@
Slog.i(LOG_TAG, "computeChangedWindows()");
}
+ boolean windowsChanged = false;
+ List<WindowInfo> windows = new ArrayList<WindowInfo>();
+
synchronized (mWindowManagerService.mWindowMap) {
// Do not send the windows if there is no current focus as
// the window manager is still looking for where to put it.
@@ -975,8 +981,6 @@
SparseArray<WindowState> visibleWindows = mTempWindowStates;
populateVisibleWindowsOnScreenLocked(visibleWindows);
- List<WindowInfo> windows = new ArrayList<WindowInfo>();
-
Set<IBinder> addedWindows = mTempBinderSet;
addedWindows.clear();
@@ -1074,7 +1078,6 @@
addedWindows.clear();
// We computed the windows and if they changed notify the client.
- boolean windowsChanged = false;
if (mOldWindows.size() != windows.size()) {
// Different size means something changed.
windowsChanged = true;
@@ -1096,22 +1099,24 @@
}
if (windowsChanged) {
- if (DEBUG) {
- Log.i(LOG_TAG, "Windows changed:" + windows);
- }
- // Remember the old windows to detect changes.
cacheWindows(windows);
- // Announce the change.
- mHandler.obtainMessage(MyHandler.MESSAGE_NOTIFY_WINDOWS_CHANGED,
- windows).sendToTarget();
- } else {
- if (DEBUG) {
- Log.i(LOG_TAG, "No windows changed.");
- }
- // Recycle the nodes as we do not need them.
- clearAndRecycleWindows(windows);
}
}
+
+ // Now we do not hold the lock, so send the windows over.
+ if (windowsChanged) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "Windows changed:" + windows);
+ }
+ mCallback.onWindowsForAccessibilityChanged(windows);
+ } else {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "No windows changed.");
+ }
+ }
+
+ // Recycle the windows as we do not need them.
+ clearAndRecycleWindows(windows);
}
private void computeWindowBoundsInScreen(WindowState windowState, Rect outBounds) {
@@ -1217,7 +1222,7 @@
return false;
}
- private void clearAndRecycleWindows(List<WindowInfo> windows) {
+ private static void clearAndRecycleWindows(List<WindowInfo> windows) {
final int windowCount = windows.size();
for (int i = windowCount - 1; i >= 0; i--) {
windows.remove(i).recycle();
@@ -1254,7 +1259,6 @@
private class MyHandler extends Handler {
public static final int MESSAGE_COMPUTE_CHANGED_WINDOWS = 1;
- public static final int MESSAGE_NOTIFY_WINDOWS_CHANGED = 2;
public MyHandler(Looper looper) {
super(looper, null, false);
@@ -1267,12 +1271,6 @@
case MESSAGE_COMPUTE_CHANGED_WINDOWS: {
computeChangedWindows();
} break;
-
- case MESSAGE_NOTIFY_WINDOWS_CHANGED: {
- List<WindowInfo> windows = (List<WindowInfo>) message.obj;
- mCallback.onWindowsForAccessibilityChanged(windows);
- clearAndRecycleWindows(windows);
- } break;
}
}
}