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

Commit cb93f26f authored by Jacky Kao's avatar Jacky Kao Committed by Automerger Merge Worker
Browse files

Improve the windows register and unregister mechanism am: 31eaf452

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14637424

Change-Id: If7b01817b2d76d2b7e4512278f853ba5875d3c4d
parents 14e79511 31eaf452
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -373,6 +373,20 @@ public class AccessibilityWindowManager {
            }
        }

        /**
         * Called when the display is reparented and becomes an embedded
         * display.
         *
         * @param embeddedDisplayId The embedded display Id.
         */
        @Override
        public void onDisplayReparented(int embeddedDisplayId) {
            // Removes the un-used window observer for the embedded display.
            synchronized (mLock) {
                mDisplayWindowsObservers.remove(embeddedDisplayId);
            }
        }

        private boolean shouldUpdateWindowsLocked(boolean forceSend,
                @NonNull List<WindowInfo> windows) {
            if (forceSend) {
+46 −29
Original line number Diff line number Diff line
@@ -90,6 +90,7 @@ import android.view.animation.Interpolator;
import com.android.internal.R;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.TraceBuffer;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.wm.WindowManagerInternal.AccessibilityControllerInternal;
@@ -172,11 +173,15 @@ final class AccessibilityController {

    /**
     * Sets a callback for observing which windows are touchable for the purposes
     * of accessibility on specified display.
     * of accessibility on specified display. When a display is reparented and becomes
     * an embedded one, the {@link WindowsForAccessibilityCallback#onDisplayReparented(int)}
     * will notify the accessibility framework to remove the un-used window observer of
     * this embedded display.
     *
     * @param displayId The logical display id.
     * @param callback The callback.
     * @return {@code false} if display id is not valid or an embedded display.
     * @return {@code false} if display id is not valid or an embedded display when the callback
     * isn't null.
     */
    boolean setWindowsForAccessibilityCallback(int displayId,
            WindowsForAccessibilityCallback callback) {
@@ -185,12 +190,13 @@ final class AccessibilityController {
                    TAG + ".setWindowsForAccessibilityCallback",
                    "displayId=" + displayId + "; callback={" + callback + "}");
        }

        if (callback != null) {
            final DisplayContent dc = mService.mRoot.getDisplayContentOrCreate(displayId);
            if (dc == null) {
                return false;
            }

        if (callback != null) {
            WindowsForAccessibilityObserver observer =
                    mWindowsForAccessibilityObserver.get(displayId);
            if (isEmbeddedDisplay(dc)) {
@@ -209,21 +215,13 @@ final class AccessibilityController {
                if (Build.IS_DEBUGGABLE) {
                    throw new IllegalStateException(errorMessage);
                }
                removeObserverOfEmbeddedDisplay(observer);
                removeObserversForEmbeddedChildDisplays(observer);
                mWindowsForAccessibilityObserver.remove(displayId);
            }
            observer = new WindowsForAccessibilityObserver(mService, displayId, callback);
            mWindowsForAccessibilityObserver.put(displayId, observer);
            mAllObserversInitialized &= observer.mInitialized;
        } else {
            if (isEmbeddedDisplay(dc)) {
                // If this display is an embedded one, its window observer should be removed along
                // with the window observer of its parent display removed because the window
                // observer of the embedded display and its parent display is the same, and would
                // be removed together when stopping the window tracking of its parent display. So
                // here don't need to do removing window observer of the embedded display again.
                return true;
            }
            final WindowsForAccessibilityObserver windowsForA11yObserver =
                    mWindowsForAccessibilityObserver.get(displayId);
            if (windowsForA11yObserver == null) {
@@ -234,7 +232,7 @@ final class AccessibilityController {
                    throw new IllegalStateException(errorMessage);
                }
            }
            removeObserverOfEmbeddedDisplay(windowsForA11yObserver);
            removeObserversForEmbeddedChildDisplays(windowsForA11yObserver);
            mWindowsForAccessibilityObserver.remove(displayId);
        }
        return true;
@@ -507,24 +505,36 @@ final class AccessibilityController {
        if (embeddedDisplayId == Display.DEFAULT_DISPLAY || parentWindow == null) {
            return;
        }
        mService.mH.sendMessage(PooledLambda.obtainMessage(
                AccessibilityController::updateWindowObserverOfEmbeddedDisplay,
                this, embeddedDisplayId, parentWindow));
    }

    private void updateWindowObserverOfEmbeddedDisplay(int embeddedDisplayId,
            WindowState parentWindow) {
        final WindowsForAccessibilityObserver windowsForA11yObserver;

        synchronized (mService.mGlobalLock) {
            // Finds the parent display of this embedded display
        final int parentDisplayId;
            WindowState candidate = parentWindow;
            while (candidate != null) {
                parentWindow = candidate;
                candidate = parentWindow.getDisplayContent().getParentWindow();
            }
        parentDisplayId = parentWindow.getDisplayId();
            final int parentDisplayId = parentWindow.getDisplayId();
            // Uses the observer of parent display
        final WindowsForAccessibilityObserver windowsForA11yObserver =
                mWindowsForAccessibilityObserver.get(parentDisplayId);
            windowsForA11yObserver = mWindowsForAccessibilityObserver.get(parentDisplayId);
        }

        if (windowsForA11yObserver != null) {
            windowsForA11yObserver.notifyDisplayReparented(embeddedDisplayId);
            windowsForA11yObserver.addEmbeddedDisplay(embeddedDisplayId);
            synchronized (mService.mGlobalLock) {
                // Replaces the observer of embedded display to the one of parent display
                mWindowsForAccessibilityObserver.put(embeddedDisplayId, windowsForA11yObserver);
            }
        }
    }

    void onImeSurfaceShownChanged(WindowState windowState, boolean shown) {
        if (mAccessibilityTracing.isEnabled()) {
@@ -555,7 +565,7 @@ final class AccessibilityController {
                + "mWindowsForAccessibilityObserver=" + mWindowsForAccessibilityObserver);
    }

    private void removeObserverOfEmbeddedDisplay(WindowsForAccessibilityObserver
    private void removeObserversForEmbeddedChildDisplays(WindowsForAccessibilityObserver
            observerOfParentDisplay) {
        final IntArray embeddedDisplayIdList =
                observerOfParentDisplay.getAndClearEmbeddedDisplayIdList();
@@ -1541,6 +1551,13 @@ final class AccessibilityController {
            mEmbeddedDisplayIdList.add(displayId);
        }

        void notifyDisplayReparented(int embeddedDisplayId) {
            // Notifies the A11y framework the display is reparented and
            // becomes an embedded display for removing the un-used
            // displayWindowObserver of this embedded one.
            mCallback.onDisplayReparented(embeddedDisplayId);
        }

        /**
         * Check if windows have changed, and send them to the accessibility subsystem if they have.
         *
+10 −0
Original line number Diff line number Diff line
@@ -115,6 +115,16 @@ public abstract class WindowManagerInternal {
         */
        void onWindowsForAccessibilityChanged(boolean forceSend, int topFocusedDisplayId,
                IBinder topFocusedWindowToken, @NonNull List<WindowInfo> windows);

        /**
         * Called when the display is reparented and becomes an embedded
         * display. The {@link WindowsForAccessibilityCallback} with the given embedded
         * display will be replaced by the {@link WindowsForAccessibilityCallback}
         * associated with its parent display at the same time.
         *
         * @param embeddedDisplayId The embedded display Id.
         */
        void onDisplayReparented(int embeddedDisplayId);
    }

    /**
+13 −0
Original line number Diff line number Diff line
@@ -834,6 +834,19 @@ public class AccessibilityWindowManagerTest {
        assertNull(token);
    }

    @Test
    public void onDisplayReparented_shouldRemoveObserver() throws RemoteException {
        // Starts tracking window of second display.
        startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
        assertTrue(mA11yWindowManager.isTrackingWindowsLocked(SECONDARY_DISPLAY_ID));
        // Notifies the second display is an embedded one of the default display.
        final WindowsForAccessibilityCallback callbacks =
                mCallbackOfWindows.get(Display.DEFAULT_DISPLAY);
        callbacks.onDisplayReparented(SECONDARY_DISPLAY_ID);
        // Makes sure the observer of the second display is removed.
        assertFalse(mA11yWindowManager.isTrackingWindowsLocked(SECONDARY_DISPLAY_ID));
    }

    private void registerLeashedTokenAndWindowId() {
        mA11yWindowManager.registerIdLocked(mMockHostToken, HOST_WINDOW_ID);
        mA11yWindowManager.registerIdLocked(mMockEmbeddedToken, EMBEDDED_WINDOW_ID);