Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8fe39f4a authored by Jackal Guo's avatar Jackal Guo Committed by Android (Google) Code Review
Browse files

Merge "Move pre-check in A11yController to the new A11yWindowManager"

parents b24a3b1b 28dce105
Loading
Loading
Loading
Loading
+116 −6
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Slog;
import android.util.SparseArray;
import android.view.IWindow;
@@ -83,6 +84,7 @@ public class AccessibilityWindowManager
            mInteractionConnections = new SparseArray<>();
    private final SparseArray<SparseArray<IBinder>> mWindowTokens = new SparseArray<>();

    private final List<WindowInfo> mCachedWindowInfos = new ArrayList<>();
    private List<AccessibilityWindowInfo> mWindows;

    private RemoteAccessibilityConnection mPictureInPictureActionReplacingConnection;
@@ -173,24 +175,132 @@ public class AccessibilityWindowManager
    }

    /**
     * Callbacks from from window manager when there's an accessibility change in windows.
     * Callbacks from window manager when there's an accessibility change in windows.
     *
     * @param forceSend Send the windows for accessibility even if they haven't changed.
     * @param windows The windows of current display for accessibility.
     */
    @Override
    public void onWindowsForAccessibilityChanged(@NonNull List<WindowInfo> windows) {
    public void onWindowsForAccessibilityChanged(boolean forceSend,
            @NonNull List<WindowInfo> windows) {
        synchronized (mLock) {
            if (DEBUG) {
                Slog.i(LOG_TAG, "Windows changed: " + windows);
            }

            if (shouldUpdateWindowsLocked(forceSend, windows)) {
                cacheWindows(windows);
                // Let the policy update the focused and active windows.
                updateWindowsLocked(mAccessibilityUserManager.getCurrentUserIdLocked(), windows);

                // Someone may be waiting for the windows - advertise it.
                mLock.notifyAll();
            }
        }
    }

    private boolean shouldUpdateWindowsLocked(boolean forceSend,
            @NonNull List<WindowInfo> windows) {
        if (forceSend) {
            return true;
        }

        final int windowCount = windows.size();
        // We computed the windows and if they changed notify the client.
        if (mCachedWindowInfos.size() != windowCount) {
            // Different size means something changed.
            return true;
        } else if (!mCachedWindowInfos.isEmpty() || !windows.isEmpty()) {
            // Since we always traverse windows from high to low layer
            // the old and new windows at the same index should be the
            // same, otherwise something changed.
            for (int i = 0; i < windowCount; i++) {
                WindowInfo oldWindow = mCachedWindowInfos.get(i);
                WindowInfo newWindow = windows.get(i);
                // We do not care for layer changes given the window
                // order does not change. This brings no new information
                // to the clients.
                if (windowChangedNoLayer(oldWindow, newWindow)) {
                    return true;
                }
            }
        }

        return false;
    }

    private void cacheWindows(List<WindowInfo> windows) {
        final int oldWindowCount = mCachedWindowInfos.size();
        for (int i = oldWindowCount - 1; i >= 0; i--) {
            mCachedWindowInfos.remove(i).recycle();
        }
        final int newWindowCount = windows.size();
        for (int i = 0; i < newWindowCount; i++) {
            WindowInfo newWindow = windows.get(i);
            mCachedWindowInfos.add(WindowInfo.obtain(newWindow));
        }
    }

    private boolean windowChangedNoLayer(WindowInfo oldWindow, WindowInfo newWindow) {
        if (oldWindow == newWindow) {
            return false;
        }
        if (oldWindow == null) {
            return true;
        }
        if (newWindow == null) {
            return true;
        }
        if (oldWindow.type != newWindow.type) {
            return true;
        }
        if (oldWindow.focused != newWindow.focused) {
            return true;
        }
        if (oldWindow.token == null) {
            if (newWindow.token != null) {
                return true;
            }
        } else if (!oldWindow.token.equals(newWindow.token)) {
            return true;
        }
        if (oldWindow.parentToken == null) {
            if (newWindow.parentToken != null) {
                return true;
            }
        } else if (!oldWindow.parentToken.equals(newWindow.parentToken)) {
            return true;
        }
        if (oldWindow.activityToken == null) {
            if (newWindow.activityToken != null) {
                return true;
            }
        } else if (!oldWindow.activityToken.equals(newWindow.activityToken)) {
            return true;
        }
        if (!oldWindow.boundsInScreen.equals(newWindow.boundsInScreen)) {
            return true;
        }
        if (oldWindow.childTokens != null && newWindow.childTokens != null
                && !oldWindow.childTokens.equals(newWindow.childTokens)) {
            return true;
        }
        if (!TextUtils.equals(oldWindow.title, newWindow.title)) {
            return true;
        }
        if (oldWindow.accessibilityIdOfAnchor != newWindow.accessibilityIdOfAnchor) {
            return true;
        }
        if (oldWindow.inPictureInPicture != newWindow.inPictureInPicture) {
            return true;
        }
        if (oldWindow.hasFlagWatchOutsideTouch != newWindow.hasFlagWatchOutsideTouch) {
            return true;
        }
        if (oldWindow.displayId != newWindow.displayId) {
            return true;
        }
        return false;
    }

    /**
     * Start tracking windows changes from window manager.
+4 −108
Original line number Diff line number Diff line
@@ -43,9 +43,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TypedValue;
@@ -1036,12 +1034,9 @@ final class AccessibilityController {

        private static final boolean DEBUG = false;

        private final SparseArray<WindowState> mTempWindowStates =
                new SparseArray<WindowState>();
        private final SparseArray<WindowState> mTempWindowStates = new SparseArray<>();

        private final List<WindowInfo> mOldWindows = new ArrayList<WindowInfo>();

        private final Set<IBinder> mTempBinderSet = new ArraySet<IBinder>();
        private final Set<IBinder> mTempBinderSet = new ArraySet<>();

        private final RectF mTempRectF = new RectF();

@@ -1098,8 +1093,7 @@ final class AccessibilityController {
                Slog.i(LOG_TAG, "computeChangedWindows()");
            }

            boolean windowsChanged = false;
            List<WindowInfo> windows = new ArrayList<WindowInfo>();
            List<WindowInfo> windows = new ArrayList<>();

            synchronized (mService.mGlobalLock) {
                // Do not send the windows if there is no current focus as
@@ -1169,46 +1163,9 @@ final class AccessibilityController {

                visibleWindows.clear();
                addedWindows.clear();

                if (!forceSend) {
                    // We computed the windows and if they changed notify the client.
                    if (mOldWindows.size() != windows.size()) {
                        // Different size means something changed.
                        windowsChanged = true;
                    } else if (!mOldWindows.isEmpty() || !windows.isEmpty()) {
                        // Since we always traverse windows from high to low layer
                        // the old and new windows at the same index should be the
                        // same, otherwise something changed.
                        for (int i = 0; i < windowCount; i++) {
                            WindowInfo oldWindow = mOldWindows.get(i);
                            WindowInfo newWindow = windows.get(i);
                            // We do not care for layer changes given the window
                            // order does not change. This brings no new information
                            // to the clients.
                            if (windowChangedNoLayer(oldWindow, newWindow)) {
                                windowsChanged = true;
                                break;
                            }
                        }
                    }
            }

                if (forceSend || windowsChanged) {
                    cacheWindows(windows);
                }
            }

            // Now we do not hold the lock, so send the windows over.
            if (forceSend || windowsChanged) {
                if (DEBUG) {
                    Log.i(LOG_TAG, "Windows changed or force sending:" + windows);
                }
                mCallback.onWindowsForAccessibilityChanged(windows);
            } else {
                if (DEBUG) {
                    Log.i(LOG_TAG, "No windows changed.");
                }
            }
            mCallback.onWindowsForAccessibilityChanged(forceSend, windows);

            // Recycle the windows as we do not need them.
            clearAndRecycleWindows(windows);
@@ -1313,67 +1270,6 @@ final class AccessibilityController {
            tokenOut.add(window.token);
        }

        private void cacheWindows(List<WindowInfo> windows) {
            final int oldWindowCount = mOldWindows.size();
            for (int i = oldWindowCount - 1; i >= 0; i--) {
                mOldWindows.remove(i).recycle();
            }
            final int newWindowCount = windows.size();
            for (int i = 0; i < newWindowCount; i++) {
                WindowInfo newWindow = windows.get(i);
                mOldWindows.add(WindowInfo.obtain(newWindow));
            }
        }

        private boolean windowChangedNoLayer(WindowInfo oldWindow, WindowInfo newWindow) {
            if (oldWindow == newWindow) {
                return false;
            }
            if (oldWindow == null) {
                return true;
            }
            if (newWindow == null) {
                return true;
            }
            if (oldWindow.type != newWindow.type) {
                return true;
            }
            if (oldWindow.focused != newWindow.focused) {
                return true;
            }
            if (oldWindow.token == null) {
                if (newWindow.token != null) {
                    return true;
                }
            } else if (!oldWindow.token.equals(newWindow.token)) {
                return true;
            }
            if (oldWindow.parentToken == null) {
                if (newWindow.parentToken != null) {
                    return true;
                }
            } else if (!oldWindow.parentToken.equals(newWindow.parentToken)) {
                return true;
            }
            if (!oldWindow.boundsInScreen.equals(newWindow.boundsInScreen)) {
                return true;
            }
            if (oldWindow.childTokens != null && newWindow.childTokens != null
                    && !oldWindow.childTokens.equals(newWindow.childTokens)) {
                return true;
            }
            if (!TextUtils.equals(oldWindow.title, newWindow.title)) {
                return true;
            }
            if (oldWindow.accessibilityIdOfAnchor != newWindow.accessibilityIdOfAnchor) {
                return true;
            }
            if (oldWindow.displayId != newWindow.displayId) {
                return true;
            }
            return false;
        }

        private static void clearAndRecycleWindows(List<WindowInfo> windows) {
            final int windowCount = windows.size();
            for (int i = windowCount - 1; i >= 0; i--) {
+2 −1
Original line number Diff line number Diff line
@@ -51,9 +51,10 @@ public abstract class WindowManagerInternal {
        /**
         * Called when the windows for accessibility changed.
         *
         * @param forceSend Send the windows for accessibility even if they haven't changed.
         * @param windows The windows for accessibility.
         */
        public void onWindowsForAccessibilityChanged(List<WindowInfo> windows);
        void onWindowsForAccessibilityChanged(boolean forceSend, List<WindowInfo> windows);
    }

    /**
+60 −12
Original line number Diff line number Diff line
@@ -70,6 +70,8 @@ import java.util.List;
 */
public class AccessibilityWindowManagerTest {
    private static final String PACKAGE_NAME = "com.android.server.accessibility";
    private static final boolean FORCE_SEND = true;
    private static final boolean SEND_ON_WINDOW_CHANGES = false;
    private static final int USER_SYSTEM_ID = UserHandle.USER_SYSTEM;
    private static final int NUM_GLOBAL_WINDOWS = 4;
    private static final int NUM_APP_WINDOWS = 4;
@@ -122,7 +124,7 @@ public class AccessibilityWindowManagerTest {
        mWindowInfos.get(DEFAULT_FOCUSED_INDEX).focused = true;
        // Turn on windows tracking, and update window info
        mA11yWindowManager.startTrackingWindows();
        mA11yWindowManager.onWindowsForAccessibilityChanged(mWindowInfos);
        mA11yWindowManager.onWindowsForAccessibilityChanged(FORCE_SEND, mWindowInfos);
        assertEquals(mA11yWindowManager.getWindowListLocked().size(),
                mWindowInfos.size());

@@ -169,16 +171,16 @@ public class AccessibilityWindowManagerTest {
    @Test
    public void onWindowsChanged_duringTouchInteractAndFocusChange_shouldChangeActiveWindow() {
        final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
        WindowInfo focuedWindowInfo = mWindowInfos.get(DEFAULT_FOCUSED_INDEX);
        WindowInfo focusedWindowInfo = mWindowInfos.get(DEFAULT_FOCUSED_INDEX);
        assertEquals(activeWindowId, mA11yWindowManager.findWindowIdLocked(
                USER_SYSTEM_ID, focuedWindowInfo.token));
                USER_SYSTEM_ID, focusedWindowInfo.token));

        focuedWindowInfo.focused = false;
        focuedWindowInfo = mWindowInfos.get(DEFAULT_FOCUSED_INDEX + 1);
        focuedWindowInfo.focused = true;
        focusedWindowInfo.focused = false;
        focusedWindowInfo = mWindowInfos.get(DEFAULT_FOCUSED_INDEX + 1);
        focusedWindowInfo.focused = true;

        mA11yWindowManager.onTouchInteractionStart();
        mA11yWindowManager.onWindowsForAccessibilityChanged(mWindowInfos);
        mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
        assertNotEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID));
    }

@@ -207,6 +209,52 @@ public class AccessibilityWindowManagerTest {
        }
    }

    @Test
    public void onWindowsChangedAndForceSend_shouldUpdateWindows() {
        final WindowInfo windowInfo = mWindowInfos.get(0);
        final int correctLayer = mA11yWindowManager.getWindowListLocked().get(0).getLayer();
        windowInfo.layer += 1;

        mA11yWindowManager.onWindowsForAccessibilityChanged(FORCE_SEND, mWindowInfos);
        assertNotEquals(correctLayer, mA11yWindowManager.getWindowListLocked().get(0).getLayer());
    }

    @Test
    public void onWindowsChangedNoForceSend_layerChanged_shouldNotUpdateWindows() {
        final WindowInfo windowInfo = mWindowInfos.get(0);
        final int correctLayer = mA11yWindowManager.getWindowListLocked().get(0).getLayer();
        windowInfo.layer += 1;

        mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
        assertEquals(correctLayer, mA11yWindowManager.getWindowListLocked().get(0).getLayer());
    }

    @Test
    public void onWindowsChangedNoForceSend_windowChanged_shouldUpdateWindows()
            throws RemoteException {
        final AccessibilityWindowInfo oldWindow = mA11yWindowManager.getWindowListLocked().get(0);
        final IWindow token = addAccessibilityInteractionConnection(true);
        final WindowInfo windowInfo = WindowInfo.obtain();
        windowInfo.type = AccessibilityWindowInfo.TYPE_APPLICATION;
        windowInfo.token = token.asBinder();
        windowInfo.layer = 0;
        windowInfo.boundsInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
        mWindowInfos.set(0, windowInfo);

        mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
        assertNotEquals(oldWindow, mA11yWindowManager.getWindowListLocked().get(0));
    }

    @Test
    public void onWindowsChangedNoForceSend_focusChanged_shouldUpdateWindows() {
        final WindowInfo focusedWindowInfo = mWindowInfos.get(DEFAULT_FOCUSED_INDEX);
        final WindowInfo windowInfo = mWindowInfos.get(0);
        focusedWindowInfo.focused = false;
        windowInfo.focused = true;
        mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
        assertTrue(mA11yWindowManager.getWindowListLocked().get(0).isFocused());
    }

    @Test
    public void removeAccessibilityInteractionConnection_byWindowToken_shouldRemoved() {
        for (int i = 0; i < NUM_OF_WINDOWS; i++) {
@@ -264,7 +312,7 @@ public class AccessibilityWindowManagerTest {
        windowInfo = mWindowInfos.get(1);
        windowInfo.boundsInScreen.set(0, SCREEN_HEIGHT / 2,
                SCREEN_WIDTH, SCREEN_HEIGHT);
        mA11yWindowManager.onWindowsForAccessibilityChanged(mWindowInfos);
        mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);

        final List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked();
        final Region outBounds = new Region();
@@ -291,7 +339,7 @@ public class AccessibilityWindowManagerTest {
        windowInfo = mWindowInfos.get(1);
        windowInfo.boundsInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);

        mA11yWindowManager.onWindowsForAccessibilityChanged(mWindowInfos);
        mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);
        final List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked();
        final Region outBounds = new Region();
        int windowId = a11yWindows.get(1).getId();
@@ -309,7 +357,7 @@ public class AccessibilityWindowManagerTest {
        windowInfo.boundsInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
        windowInfo = mWindowInfos.get(1);
        windowInfo.boundsInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
        mA11yWindowManager.onWindowsForAccessibilityChanged(mWindowInfos);
        mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);

        final List<AccessibilityWindowInfo> a11yWindows = mA11yWindowManager.getWindowListLocked();
        final Region outBounds = new Region();
@@ -498,7 +546,7 @@ public class AccessibilityWindowManagerTest {
    public void getPictureInPictureWindow_shouldNotNull() {
        assertNull(mA11yWindowManager.getPictureInPictureWindow());
        mWindowInfos.get(1).inPictureInPicture = true;
        mA11yWindowManager.onWindowsForAccessibilityChanged(mWindowInfos);
        mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);

        assertNotNull(mA11yWindowManager.getPictureInPictureWindow());
    }
@@ -511,7 +559,7 @@ public class AccessibilityWindowManagerTest {
                mA11yWindowManager.getConnectionLocked(
                        USER_SYSTEM_ID, outsideWindowId).getRemote();
        mWindowInfos.get(0).hasFlagWatchOutsideTouch = true;
        mA11yWindowManager.onWindowsForAccessibilityChanged(mWindowInfos);
        mA11yWindowManager.onWindowsForAccessibilityChanged(SEND_ON_WINDOW_CHANGES, mWindowInfos);

        mA11yWindowManager.notifyOutsideTouch(USER_SYSTEM_ID, targetWindowId);
        verify(mockRemoteConnection).notifyOutsideTouch();