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

Commit 9bafc715 authored by Jorim Jaggi's avatar Jorim Jaggi
Browse files

Starting window tests, yay!

Test: bit FrameworksServicesTests:com.android.server.wm.AppWindowContainerControllerTests
Fixes: 34364463
Fixes: 34361417
Change-Id: Ie1b8debc894e5cad8fe517912a1991a38661dfaa
parent 2cff9319
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -56,7 +56,7 @@ public class AppWindowContainerController
    private static final int STARTING_WINDOW_TYPE_SPLASH_SCREEN = 2;

    private final IApplicationToken mToken;
    private final Handler mHandler = new Handler(Looper.getMainLooper());
    private final Handler mHandler;

    private final Runnable mOnWindowsDrawn = () -> {
        if (mListener == null) {
@@ -186,6 +186,7 @@ public class AppWindowContainerController
            int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos,
            WindowManagerService service) {
        super(listener, service);
        mHandler = new Handler(service.mH.getLooper());
        mToken = token;
        synchronized(mWindowMap) {
            AppWindowToken atoken = mRoot.getAppWindowToken(mToken.asBinder());
+62 −3
Original line number Diff line number Diff line
@@ -18,12 +18,10 @@ package com.android.server.wm;

import org.junit.Test;

import android.os.Binder;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.view.IApplicationToken;

import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -74,6 +72,67 @@ public class AppWindowContainerControllerTests extends WindowTestsBase {
        controller.removeContainer(sDisplayContent.getDisplayId());
        // Assert orientation is unspecified to after container is removed.
        assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, controller.getOrientation());

        // Reset display frozen state
        sWm.mDisplayFrozen = false;
    }

    private void assertHasStartingWindow(AppWindowToken atoken) {
        assertNotNull(atoken.startingSurface);
        assertNotNull(atoken.startingData);
        assertNotNull(atoken.startingWindow);
    }

    private void assertNoStartingWindow(AppWindowToken atoken) {
        assertNull(atoken.startingSurface);
        assertNull(atoken.startingWindow);
        assertNull(atoken.startingData);
    }

    @Test
    public void testCreateRemoveStartingWindow() throws Exception {
        final TestAppWindowContainerController controller = createAppWindowController();
        controller.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
                android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false);
        waitUntilHandlerIdle();
        final AppWindowToken atoken = controller.getAppWindowToken();
        assertHasStartingWindow(atoken);
        controller.removeStartingWindow();
        waitUntilHandlerIdle();
        assertNoStartingWindow(atoken);
    }

    @Test
    public void testTransferStartingWindow() throws Exception {
        final TestAppWindowContainerController controller1 = createAppWindowController();
        final TestAppWindowContainerController controller2 = createAppWindowController();
        controller1.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
                android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false);
        waitUntilHandlerIdle();
        controller2.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
                android.R.style.Theme, null, "Test", 0, 0, 0, 0, controller1.mToken.asBinder(),
                true, true, false);
        waitUntilHandlerIdle();
        assertNoStartingWindow(controller1.getAppWindowToken());
        assertHasStartingWindow(controller2.getAppWindowToken());
    }

    @Test
    public void testTransferStartingWindowWhileCreating() throws Exception {
        final TestAppWindowContainerController controller1 = createAppWindowController();
        final TestAppWindowContainerController controller2 = createAppWindowController();
        sPolicy.setRunnableWhenAddingSplashScreen(() -> {

            // Surprise, ...! Transfer window in the middle of the creation flow.
            controller2.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
                    android.R.style.Theme, null, "Test", 0, 0, 0, 0, controller1.mToken.asBinder(),
                    true, true, false);
        });
        controller1.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
                android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false);
        waitUntilHandlerIdle();
        assertNoStartingWindow(controller1.getAppWindowToken());
        assertHasStartingWindow(controller2.getAppWindowToken());
    }

    private TestAppWindowContainerController createAppWindowController() {
+31 −2
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
import static android.view.WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY;
@@ -74,6 +75,7 @@ import android.view.Display;
import android.view.IWindowManager;
import android.view.KeyEvent;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.WindowManagerPolicy;
import android.view.animation.Animation;
import android.os.PowerManagerInternal;
@@ -92,6 +94,8 @@ class TestWindowManagerPolicy implements WindowManagerPolicy {

    int rotationToReport = 0;

    private Runnable mRunnableWhenAddingSplashScreen;

    static synchronized WindowManagerService getWindowManagerService(Context context) {
        if (sWm == null) {
            // We only want to do this once for the test process as we don't want WM to try to
@@ -318,11 +322,36 @@ class TestWindowManagerPolicy implements WindowManagerPolicy {
        return false;
    }

    /**
     * Sets a runnable to run when adding a splash screen which gets executed after the window has
     * been added but before returning the surface.
     */
    void setRunnableWhenAddingSplashScreen(Runnable r) {
        mRunnableWhenAddingSplashScreen = r;
    }

    @Override
    public StartingSurface addSplashScreen(IBinder appToken, String packageName, int theme,
            CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon,
            int logo, int windowFlags, Configuration overrideConfig, int displayId) {
        return null;
        final com.android.server.wm.WindowState window;
        final AppWindowToken atoken;
        synchronized (sWm.mWindowMap) {
            atoken = WindowTestsBase.sDisplayContent.getAppWindowToken(appToken);
            window = WindowTestsBase.createWindow(null, TYPE_APPLICATION_STARTING, atoken,
                    "Starting window");
            atoken.startingWindow = window;
        }
        if (mRunnableWhenAddingSplashScreen != null) {
            mRunnableWhenAddingSplashScreen.run();
            mRunnableWhenAddingSplashScreen = null;
        }
        return () -> {
            synchronized (sWm.mWindowMap) {
                atoken.removeChild(window);
                atoken.startingWindow = null;
            }
        };
    }

    @Override
@@ -482,7 +511,7 @@ class TestWindowManagerPolicy implements WindowManagerPolicy {

    @Override
    public boolean isScreenOn() {
        return false;
        return true;
    }

    @Override
+3 −5
Original line number Diff line number Diff line
@@ -45,20 +45,18 @@ import org.mockito.invocation.InvocationOnMock;
@SmallTest
@Presubmit
@RunWith(AndroidJUnit4.class)
public class UnknownAppVisibilityControllerTest {
public class UnknownAppVisibilityControllerTest extends WindowTestsBase {

    private WindowManagerService mWm;
    private @Mock ActivityManagerInternal mAm;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        super.setUp();
        final Context context = InstrumentationRegistry.getTargetContext();
        LocalServices.addService(ActivityManagerInternal.class, mAm);
        doAnswer((InvocationOnMock invocationOnMock) -> {
            invocationOnMock.getArgumentAt(0, Runnable.class).run();
            return null;
        }).when(mAm).notifyKeyguardFlagsChanged(any());
        }).when(sMockAm).notifyKeyguardFlagsChanged(any());
        mWm = TestWindowManagerPolicy.getWindowManagerService(context);
    }

+39 −14
Original line number Diff line number Diff line
@@ -16,15 +16,17 @@

package com.android.server.wm;

import android.app.ActivityManagerInternal;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Binder;
import android.view.IApplicationToken;
import org.junit.Assert;
import org.junit.Before;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

import android.app.ActivityManager;
import android.app.ActivityManager.TaskSnapshot;
import android.content.Context;
import android.os.IBinder;
import android.support.test.InstrumentationRegistry;
@@ -50,13 +52,17 @@ import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static org.mockito.Mockito.mock;

import com.android.server.AttributeCache;
import com.android.server.LocalServices;

/**
 * Common base class for window manager unit test classes.
 */
class WindowTestsBase {
    static WindowManagerService sWm = null;
    private final IWindow mIWindow = new TestIWindow();
    private final Session mMockSession = mock(Session.class);
    static TestWindowManagerPolicy sPolicy = null;
    private final static IWindow sIWindow = new TestIWindow();
    private final static Session sMockSession = mock(Session.class);
    static int sNextStackId = FIRST_DYNAMIC_STACK_ID;
    private static int sNextTaskId = 0;

@@ -72,19 +78,27 @@ class WindowTestsBase {
    static WindowState sAppWindow;
    static WindowState sChildAppWindowAbove;
    static WindowState sChildAppWindowBelow;
    static @Mock ActivityManagerInternal sMockAm;

    @Before
    public void setUp() throws Exception {
        if (sOneTimeSetupDone) {
            Mockito.reset(sMockAm);
            return;
        }
        sOneTimeSetupDone = true;
        MockitoAnnotations.initMocks(this);
        final Context context = InstrumentationRegistry.getTargetContext();
        LocalServices.addService(ActivityManagerInternal.class, sMockAm);
        AttributeCache.init(context);
        sWm = TestWindowManagerPolicy.getWindowManagerService(context);
        sPolicy = (TestWindowManagerPolicy) sWm.mPolicy;
        sLayersController = new WindowLayersController(sWm);
        sDisplayContent = new DisplayContent(context.getDisplay(), sWm, sLayersController,
                new WallpaperController(sWm));
        sWm.mRoot.addChild(sDisplayContent, 0);
        sWm.mDisplayEnabled = true;
        sWm.mDisplayReady = true;

        // Set-up some common windows.
        sWallpaperWindow = createWindow(null, TYPE_WALLPAPER, sDisplayContent, "wallpaperWindow");
@@ -108,7 +122,14 @@ class WindowTestsBase {
        Assert.assertTrue("Excepted " + first + " to be greater than " + second, first > second);
    }

    private WindowToken createWindowToken(DisplayContent dc, int type) {
    /**
     * Waits until the main handler for WM has processed all messages.
     */
    void waitUntilHandlerIdle() {
        sWm.mH.runWithScissors(() -> { }, 0);
    }

    private static WindowToken createWindowToken(DisplayContent dc, int type) {
        if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) {
            return new TestWindowToken(type, dc);
        }
@@ -120,7 +141,7 @@ class WindowTestsBase {
        return token;
    }

    WindowState createWindow(WindowState parent, int type, String name) {
    static WindowState createWindow(WindowState parent, int type, String name) {
        return (parent == null)
                ? createWindow(parent, type, sDisplayContent, name)
                : createWindow(parent, type, parent.mToken, name);
@@ -132,16 +153,16 @@ class WindowTestsBase {
        return createWindow(null, type, token, name);
    }

    WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name) {
    static WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name) {
        final WindowToken token = createWindowToken(dc, type);
        return createWindow(parent, type, token, name);
    }

    WindowState createWindow(WindowState parent, int type, WindowToken token, String name) {
    static WindowState createWindow(WindowState parent, int type, WindowToken token, String name) {
        final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
        attrs.setTitle(name);

        final WindowState w = new WindowState(sWm, mMockSession, mIWindow, token, parent, OP_NONE,
        final WindowState w = new WindowState(sWm, sMockSession, sIWindow, token, parent, OP_NONE,
                0, attrs, 0, 0);
        // TODO: Probably better to make this call in the WindowState ctor to avoid errors with
        // adding it to the token...
@@ -150,14 +171,14 @@ class WindowTestsBase {
    }

    /** Creates a {@link TaskStack} and adds it to the specified {@link DisplayContent}. */
    TaskStack createTaskStackOnDisplay(DisplayContent dc) {
    static TaskStack createTaskStackOnDisplay(DisplayContent dc) {
        final int stackId = sNextStackId++;
        dc.addStackToDisplay(stackId, true);
        return sWm.mStackIdToStack.get(stackId);
    }

    /**Creates a {@link Task} and adds it to the specified {@link TaskStack}. */
    Task createTaskInStack(TaskStack stack, int userId) {
    static Task createTaskInStack(TaskStack stack, int userId) {
        final Task newTask = new Task(sNextTaskId++, stack, userId, sWm, null, EMPTY, false, 0,
                false, null);
        stack.addTask(newTask, POSITION_TOP);
@@ -165,7 +186,7 @@ class WindowTestsBase {
    }

    /* Used so we can gain access to some protected members of the {@link WindowToken} class */
    class TestWindowToken extends WindowToken {
    static class TestWindowToken extends WindowToken {

        TestWindowToken(int type, DisplayContent dc) {
            this(type, dc, false /* persistOnEmpty */);
@@ -185,7 +206,7 @@ class WindowTestsBase {
    }

    /** Used so we can gain access to some protected members of the {@link AppWindowToken} class. */
    class TestAppWindowToken extends AppWindowToken {
    static class TestAppWindowToken extends AppWindowToken {

        TestAppWindowToken(DisplayContent dc) {
            super(sWm, null, false, dc);
@@ -279,6 +300,10 @@ class WindowTestsBase {
                    0 /* inputDispatchingTimeoutNanos */, sWm);
            mToken = token;
        }

        AppWindowToken getAppWindowToken() {
            return (AppWindowToken) sDisplayContent.getWindowToken(mToken.asBinder());
        }
    }

    class TestIApplicationToken implements IApplicationToken {
@@ -295,7 +320,7 @@ class WindowTestsBase {
        boolean resizeReported;

        TestWindowState(WindowManager.LayoutParams attrs, WindowToken token) {
            super(sWm, mMockSession, mIWindow, token, null, OP_NONE, 0, attrs, 0, 0);
            super(sWm, sMockSession, sIWindow, token, null, OP_NONE, 0, attrs, 0, 0);
        }

        @Override