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
This commit is contained in:
committed by
Svetoslav Ganov
parent
bcaa315d48
commit
3a0d878ab5
@@ -364,7 +364,7 @@ public abstract class Window {
|
||||
/**
|
||||
* This hook is called whenever the window focus changes. See
|
||||
* {@link View#onWindowFocusChanged(boolean)
|
||||
* View.onWindowFocusChanged(boolean)} for more information.
|
||||
* View.onWindowFocusChangedNotLocked(boolean)} for more information.
|
||||
*
|
||||
* @param hasFocus Whether the window now has focus.
|
||||
*/
|
||||
|
||||
@@ -3314,8 +3314,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
|
||||
public int mAccessibilityFocusedWindowId = INVALID_WINDOW_ID;
|
||||
public long mAccessibilityFocusNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
|
||||
|
||||
public AccessibilityEvent mShowingFocusedWindowEvent;
|
||||
|
||||
private boolean mTouchInteractionInProgress;
|
||||
|
||||
private boolean canDispatchAccessibilityEventLocked(AccessibilityEvent event) {
|
||||
@@ -3324,19 +3322,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
|
||||
// All events that are for changes in a global window
|
||||
// state should *always* be dispatched.
|
||||
case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
|
||||
if (mWindowsForAccessibilityCallback != null) {
|
||||
// OK, this is fun. Sometimes the focused window is notified
|
||||
// it has focus before being shown. Historically this event
|
||||
// means that the window is focused and can be introspected.
|
||||
// But we still have not gotten the window state from the
|
||||
// window manager, so delay the notification until then.
|
||||
AccessibilityWindowInfo window = findWindowById(event.getWindowId());
|
||||
if (window == null) {
|
||||
mShowingFocusedWindowEvent = AccessibilityEvent.obtain(event);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// $fall-through$
|
||||
case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:
|
||||
case AccessibilityEvent.TYPE_ANNOUNCEMENT:
|
||||
// All events generated by the user touching the
|
||||
@@ -3428,18 +3413,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
|
||||
}
|
||||
|
||||
notifyWindowsChanged();
|
||||
|
||||
// If we are delaying a window state change event as the window
|
||||
// source was showing when it was fired, now is the time to send.
|
||||
if (mShowingFocusedWindowEvent != null) {
|
||||
final int windowId = mShowingFocusedWindowEvent.getWindowId();
|
||||
AccessibilityWindowInfo window = findWindowById(windowId);
|
||||
if (window != null) {
|
||||
// Sending does the recycle.
|
||||
sendAccessibilityEvent(mShowingFocusedWindowEvent, mCurrentUserId);
|
||||
}
|
||||
mShowingFocusedWindowEvent = null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean computePartialInteractiveRegionForWindowLocked(int windowId,
|
||||
|
||||
@@ -159,11 +159,15 @@ final class AccessibilityController {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ final class AccessibilityController {
|
||||
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 @@ final class AccessibilityController {
|
||||
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 @@ final class AccessibilityController {
|
||||
SparseArray<WindowState> visibleWindows = mTempWindowStates;
|
||||
populateVisibleWindowsOnScreenLocked(visibleWindows);
|
||||
|
||||
List<WindowInfo> windows = new ArrayList<WindowInfo>();
|
||||
|
||||
Set<IBinder> addedWindows = mTempBinderSet;
|
||||
addedWindows.clear();
|
||||
|
||||
@@ -1074,7 +1078,6 @@ final class AccessibilityController {
|
||||
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 @@ final class AccessibilityController {
|
||||
}
|
||||
|
||||
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 @@ final class AccessibilityController {
|
||||
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 @@ final class AccessibilityController {
|
||||
|
||||
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 @@ final class AccessibilityController {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7610,7 +7610,15 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
WindowState lastFocus;
|
||||
WindowState newFocus;
|
||||
|
||||
AccessibilityController accessibilityController = null;
|
||||
|
||||
synchronized(mWindowMap) {
|
||||
// TODO(multidisplay): Accessibility supported only of default desiplay.
|
||||
if (mAccessibilityController != null && getDefaultDisplayContentLocked()
|
||||
.getDisplayId() == Display.DEFAULT_DISPLAY) {
|
||||
accessibilityController = mAccessibilityController;
|
||||
}
|
||||
|
||||
lastFocus = mLastFocus;
|
||||
newFocus = mCurrentFocus;
|
||||
if (lastFocus == newFocus) {
|
||||
@@ -7628,6 +7636,12 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
// First notify the accessibility manager for the change so it has
|
||||
// the windows before the newly focused one starts firing eventgs.
|
||||
if (accessibilityController != null) {
|
||||
accessibilityController.onWindowFocusChangedNotLocked();
|
||||
}
|
||||
|
||||
//System.out.println("Changing focus from " + lastFocus
|
||||
// + " to " + newFocus);
|
||||
if (newFocus != null) {
|
||||
@@ -10402,12 +10416,6 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
mCurrentFocus = newFocus;
|
||||
mLosingFocus.remove(newFocus);
|
||||
|
||||
// TODO(multidisplay): Accessibilty supported only of default desiplay.
|
||||
if (mAccessibilityController != null
|
||||
&& displayContent.getDisplayId() == Display.DEFAULT_DISPLAY) {
|
||||
mAccessibilityController.onWindowFocusChangedLocked();
|
||||
}
|
||||
|
||||
int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus);
|
||||
|
||||
if (imWindowChanged && oldFocus != mInputMethodWindow) {
|
||||
|
||||
Reference in New Issue
Block a user