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

Commit 07bcab78 authored by Wale Ogunwale's avatar Wale Ogunwale
Browse files

Add windows to window tokens in expected z-order

Decouple the logic for adding window to a position in the parent
window token from the position we are adding the window to in the
window list. The window token now adds the windows in order based
on the rules the rest of the system is using which makes the code
a little more straightforward to follow.

Test: bit FrameworksServicesTests:com.android.server.wm.AppWindowTokenTests
Change-Id: Ic9b724fba02279a0c4e92508d39e5e35171b6d8d
parent 71a7b9ad
Loading
Loading
Loading
Loading
+28 −0
Original line number Diff line number Diff line
@@ -676,6 +676,34 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
        mPendingRelaunchCount = 0;
    }

    /**
     * Returns true if the new child window we are adding to this token is considered greater than
     * the existing child window in this token in terms of z-order.
     */
    @Override
    protected boolean isFirstChildWindowGreaterThanSecond(WindowState newWindow,
            WindowState existingWindow) {
        final int type1 = newWindow.mAttrs.type;
        final int type2 = existingWindow.mAttrs.type;

        // Base application windows should be z-ordered BELOW all other windows in the app token.
        if (type1 == TYPE_BASE_APPLICATION && type2 != TYPE_BASE_APPLICATION) {
            return false;
        } else if (type1 != TYPE_BASE_APPLICATION && type2 == TYPE_BASE_APPLICATION) {
            return true;
        }

        // Starting windows should be z-ordered ABOVE all other windows in the app token.
        if (type1 == TYPE_APPLICATION_STARTING && type2 != TYPE_APPLICATION_STARTING) {
            return true;
        } else if (type1 != TYPE_APPLICATION_STARTING && type2 == TYPE_APPLICATION_STARTING) {
            return false;
        }

        // Otherwise the new window is greater than the existing window.
        return true;
    }

    @Override
    void addWindow(WindowState w) {
        super.addWindow(w);
+6 −16
Original line number Diff line number Diff line
@@ -1085,12 +1085,13 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
        return null;
    }

    int addAppWindowToWindowList(final WindowState win) {
    void addAppWindowToWindowList(final WindowState win) {
        final IWindow client = win.mClient;

        WindowList tokenWindowList = getTokenWindowsOnDisplay(win.mToken);
        if (!tokenWindowList.isEmpty()) {
            return addAppWindowExisting(win, tokenWindowList);
            addAppWindowExisting(win, tokenWindowList);
            return;
        }

        // No windows from this token on this display
@@ -1128,7 +1129,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
                }
            }
            addWindowToListBefore(win, pos);
            return 0;
            return;
        }

        // Continue looking down until we find the first token that has windows on this display.
@@ -1154,7 +1155,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
                }
            }
            addWindowToListAfter(win, pos);
            return 0;
            return;
        }

        // Just search for the start of this layer.
@@ -1175,7 +1176,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
                + mWindows.size());
        mWindows.add(i + 1, win);
        mService.mWindowsChanged = true;
        return 0;
    }

    /** Adds this non-app window to the window list. */
@@ -1778,23 +1778,20 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
        return mLayoutNeeded;
    }

    private int addAppWindowExisting(WindowState win, WindowList tokenWindowList) {
    private void addAppWindowExisting(WindowState win, WindowList tokenWindowList) {

        int tokenWindowsPos;
        // If this application has existing windows, we simply place the new window on top of
        // them... but keep the starting window on top.
        if (win.mAttrs.type == TYPE_BASE_APPLICATION) {
            // Base windows go behind everything else.
            final WindowState lowestWindow = tokenWindowList.get(0);
            addWindowToListBefore(win, lowestWindow);
            tokenWindowsPos = win.mToken.getWindowIndex(lowestWindow);
        } else {
            final AppWindowToken atoken = win.mAppToken;
            final int windowListPos = tokenWindowList.size();
            final WindowState lastWindow = tokenWindowList.get(windowListPos - 1);
            if (atoken != null && lastWindow == atoken.startingWindow) {
                addWindowToListBefore(win, lastWindow);
                tokenWindowsPos = win.mToken.getWindowIndex(lastWindow);
            } else {
                int newIdx = findIdxBasedOnAppTokens(win);
                // There is a window above this one associated with the same apptoken note that the
@@ -1804,16 +1801,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
                        "not Base app: Adding window " + win + " at " + (newIdx + 1) + " of "
                                + mWindows.size());
                mWindows.add(newIdx + 1, win);
                if (newIdx < 0) {
                    // No window from token found on win's display.
                    tokenWindowsPos = 0;
                } else {
                    tokenWindowsPos = win.mToken.getWindowIndex(mWindows.get(newIdx)) + 1;
                }
                mService.mWindowsChanged = true;
            }
        }
        return tokenWindowsPos;
    }

    /** Places the first input window after the second input window in the window list. */
+37 −4
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.util.Slog;
import android.view.DisplayInfo;

import java.io.PrintWriter;
import java.util.Comparator;

import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
@@ -82,6 +83,26 @@ class WindowToken extends WindowContainer<WindowState> {
    // The display this token is on.
    private DisplayContent mDisplayContent;

    /**
     * Compares two child window of this token and returns -1 if the first is lesser than the
     * second in terms of z-order and 1 otherwise.
     */
    private final Comparator<WindowState> mWindowComparator =
            (WindowState newWindow, WindowState existingWindow) -> {
        final WindowToken token = WindowToken.this;
        if (newWindow.mToken != token) {
            throw new IllegalArgumentException("newWindow=" + newWindow
                    + " is not a child of token=" + token);
        }

        if (existingWindow.mToken != token) {
            throw new IllegalArgumentException("existingWindow=" + existingWindow
                    + " is not a child of token=" + token);
        }

        return isFirstChildWindowGreaterThanSecond(newWindow, existingWindow) ? 1 : -1;
    };

    WindowToken(WindowManagerService service, IBinder _token, int type, boolean _explicit,
            DisplayContent dc) {
        mService = service;
@@ -168,19 +189,31 @@ class WindowToken extends WindowContainer<WindowState> {
        return -1;
    }

    /**
     * Returns true if the new window is considered greater than the existing window in terms of
     * z-order.
     */
    protected boolean isFirstChildWindowGreaterThanSecond(WindowState newWindow,
            WindowState existingWindow) {
        // By default the first window isn't greater than the second to preserve existing logic of
        // how new windows are added to the token
        return false;
    }

    void addWindow(final WindowState win) {
        if (DEBUG_FOCUS) Slog.d(TAG_WM, "addWindow: win=" + win + " Callers=" + Debug.getCallers(5));
        if (DEBUG_FOCUS) Slog.d(TAG_WM,
                "addWindow: win=" + win + " Callers=" + Debug.getCallers(5));

        if (!win.isChildWindow()) {
            int tokenWindowsPos = 0;
            if (asAppWindowToken() != null) {
                tokenWindowsPos = mDisplayContent.addAppWindowToWindowList(win);
                mDisplayContent.addAppWindowToWindowList(win);
            } else {
                mDisplayContent.addNonAppWindowToWindowList(win);
            }

            if (!mChildren.contains(win)) {
                if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "Adding " + win + " to " + this);
                addChild(win, tokenWindowsPos);
                addChild(win, mWindowComparator);
            }
        } else {
            mDisplayContent.addChildWindowToWindowList(win);
+43 −3
Original line number Diff line number Diff line
@@ -29,17 +29,19 @@ import android.view.IWindow;
import android.view.WindowManager;

import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

/**
 * Tests for the {@link WindowState} class.
 *
 * Build: mmma -j32 frameworks/base/services/tests/servicestests
 * Install: adb install -r out/target/product/$TARGET_PRODUCT/data/app/FrameworksServicesTests/FrameworksServicesTests.apk
 * Run: adb shell am instrument -w -e class com.android.server.wm.AppWindowTokenTests com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
 * Build/Install/Run:
 *  bit FrameworksServicesTests:com.android.server.wm.AppWindowTokenTests
 */
@SmallTest
@Presubmit
@@ -55,6 +57,36 @@ public class AppWindowTokenTests {
        sWm = TestWindowManagerPolicy.getWindowManagerService(context);
    }

    @Test
    public void testAddWindow_Order() throws Exception {
        final TestAppWindowToken token = new TestAppWindowToken();

        assertEquals(0, token.getWindowsCount());

        final WindowState win1 = createWindow(null, TYPE_APPLICATION, token);
        final WindowState startingWin = createWindow(null, TYPE_APPLICATION_STARTING, token);
        final WindowState baseWin = createWindow(null, TYPE_BASE_APPLICATION, token);
        final WindowState win4 = createWindow(null, TYPE_APPLICATION, token);

        token.addWindow(win1);
        token.addWindow(startingWin);
        token.addWindow(baseWin);
        token.addWindow(win4);

        // Should not contain the windows that were added above.
        assertEquals(4, token.getWindowsCount());
        assertTrue(token.hasWindow(win1));
        assertTrue(token.hasWindow(startingWin));
        assertTrue(token.hasWindow(baseWin));
        assertTrue(token.hasWindow(win4));

        // The starting window should be on-top of all other windows.
        assertEquals(startingWin, token.getLastChild());

        // The base application window should be below all other windows.
        assertEquals(baseWin, token.getFirstChild());
    }

    @Test
    public void testFindMainWindow() throws Exception {
        final TestAppWindowToken token = new TestAppWindowToken();
@@ -93,5 +125,13 @@ public class AppWindowTokenTests {
        boolean hasWindow(WindowState w) {
            return mChildren.contains(w);
        }

        WindowState getFirstChild() {
            return mChildren.getFirst();
        }

        WindowState getLastChild() {
            return mChildren.getLast();
        }
    }
}
+2 −3
Original line number Diff line number Diff line
@@ -41,9 +41,8 @@ import static org.mockito.Mockito.mock;
/**
 * Tests for the {@link WindowState} class.
 *
 * Build: mmma -j32 frameworks/base/services/tests/servicestests
 * Install: adb install -r out/target/product/$TARGET_PRODUCT/data/app/FrameworksServicesTests/FrameworksServicesTests.apk
 * Run: adb shell am instrument -w -e class com.android.server.wm.WindowTokenTests com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
 * Build/Install/Run:
 *  bit FrameworksServicesTests:com.android.server.wm.WindowTokenTests
 */
@SmallTest
@Presubmit