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

Commit 90be6f3d authored by chaviw's avatar chaviw
Browse files

Accessibility fix for ShellRoot

Ensure ShellRoot layers are ordered correctly with other windows in the
system. This means placing the Shell Root layers z ordered based on the
window type

Bug: 177864415
Test: adb shell dumpsys accessibility
Change-Id: Iee982e9f17b496d413d4733f0a99997f81cee527
parent 126b5dcb
Loading
Loading
Loading
Loading
+59 −10
Original line number Diff line number Diff line
@@ -1586,6 +1586,52 @@ final class AccessibilityController {
            mCallback.onDisplayReparented(embeddedDisplayId);
        }

        boolean shellRootIsAbove(WindowState windowState, ShellRoot shellRoot) {
            int wsLayer = mService.mPolicy.getWindowLayerLw(windowState);
            int shellLayer = mService.mPolicy.getWindowLayerFromTypeLw(shellRoot.getWindowType(),
                    true);
            return shellLayer >= wsLayer;
        }

        int addShellRootsIfAbove(WindowState windowState, ArrayList<ShellRoot> shellRoots,
                int shellRootIndex, List<WindowInfo> windows, Set<IBinder> addedWindows,
                Region unaccountedSpace, boolean focusedWindowAdded) {
            while (shellRootIndex < shellRoots.size()
                    && shellRootIsAbove(windowState, shellRoots.get(shellRootIndex))) {
                ShellRoot shellRoot = shellRoots.get(shellRootIndex);
                shellRootIndex++;
                final WindowInfo info = shellRoot.getWindowInfo();
                if (info == null) {
                    continue;
                }

                info.layer = addedWindows.size();
                windows.add(info);
                addedWindows.add(info.token);
                unaccountedSpace.op(info.regionInScreen, unaccountedSpace,
                        Region.Op.REVERSE_DIFFERENCE);
                if (unaccountedSpace.isEmpty() && focusedWindowAdded) {
                    break;
                }
            }
            return shellRootIndex;
        }

        private ArrayList<ShellRoot> getSortedShellRoots(
                SparseArray<ShellRoot> originalShellRoots) {
            ArrayList<ShellRoot> sortedShellRoots = new ArrayList<>(originalShellRoots.size());
            for (int i = originalShellRoots.size() - 1; i >= 0; --i) {
                sortedShellRoots.add(originalShellRoots.valueAt(i));
            }

            sortedShellRoots.sort((left, right) ->
                    mService.mPolicy.getWindowLayerFromTypeLw(right.getWindowType(), true)
                            - mService.mPolicy.getWindowLayerFromTypeLw(left.getWindowType(),
                            true));

            return sortedShellRoots;
        }

        /**
         * Check if windows have changed, and send them to the accessibility subsystem if they have.
         *
@@ -1645,9 +1691,22 @@ final class AccessibilityController {
                final int visibleWindowCount = visibleWindows.size();
                HashSet<Integer> skipRemainingWindowsForTasks = new HashSet<>();

                ArrayList<ShellRoot> shellRoots = getSortedShellRoots(dc.mShellRoots);

                // Iterate until we figure out what is touchable for the entire screen.
                int shellRootIndex = 0;
                for (int i = visibleWindowCount - 1; i >= 0; i--) {
                    final WindowState windowState = visibleWindows.valueAt(i);
                    int prevShellRootIndex = shellRootIndex;
                    shellRootIndex = addShellRootsIfAbove(windowState, shellRoots, shellRootIndex,
                            windows, addedWindows, unaccountedSpace, focusedWindowAdded);

                    // If a Shell Root was added, it could have accounted for all the space already.
                    if (shellRootIndex > prevShellRootIndex && unaccountedSpace.isEmpty()
                            && focusedWindowAdded) {
                        break;
                    }

                    final Region regionInScreen = new Region();
                    computeWindowRegionInScreen(windowState, regionInScreen);

@@ -1671,16 +1730,6 @@ final class AccessibilityController {
                    }
                }

                for (int i = dc.mShellRoots.size() - 1; i >= 0; --i) {
                    final WindowInfo info = dc.mShellRoots.valueAt(i).getWindowInfo();
                    if (info == null) {
                        continue;
                    }
                    info.layer = addedWindows.size();
                    windows.add(info);
                    addedWindows.add(info.token);
                }

                // Remove child/parent references to windows that were not added.
                final int windowCount = windows.size();
                for (int i = 0; i < windowCount; i++) {
+8 −4
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ public class ShellRoot {
    private SurfaceControl mSurfaceControl = null;
    private IWindow mAccessibilityWindow;
    private IBinder.DeathRecipient mAccessibilityWindowDeath;
    private int mWindowType;

    ShellRoot(@NonNull IWindow client, @NonNull DisplayContent dc,
            @WindowManager.ShellRootLayer final int shellRootLayer) {
@@ -64,19 +65,18 @@ public class ShellRoot {
            return;
        }
        mClient = client;
        int windowType;
        switch (shellRootLayer) {
            case SHELL_ROOT_LAYER_DIVIDER:
                windowType = TYPE_DOCK_DIVIDER;
                mWindowType = TYPE_DOCK_DIVIDER;
                break;
            case SHELL_ROOT_LAYER_PIP:
                windowType = TYPE_APPLICATION_OVERLAY;
                mWindowType = TYPE_APPLICATION_OVERLAY;
                break;
            default:
                throw new IllegalArgumentException(shellRootLayer
                        + " is not an acceptable shell root layer.");
        }
        mToken = new WindowToken.Builder(dc.mWmService, client.asBinder(), windowType)
        mToken = new WindowToken.Builder(dc.mWmService, client.asBinder(), mWindowType)
                .setDisplayContent(dc)
                .setPersistOnEmpty(true)
                .setOwnerCanManageAppTokens(true)
@@ -89,6 +89,10 @@ public class ShellRoot {
        mToken.getPendingTransaction().show(mSurfaceControl);
    }

    int getWindowType() {
        return mWindowType;
    }

    void clear() {
        if (mClient != null) {
            mClient.asBinder().unlinkToDeath(mDeathRecipient, 0);