Starting window tests, yay!

Test: bit FrameworksServicesTests:com.android.server.wm.AppWindowContainerControllerTests
Fixes: 34364463
Fixes: 34361417
Change-Id: Ie1b8debc894e5cad8fe517912a1991a38661dfaa
This commit is contained in:
Jorim Jaggi
2017-01-19 17:28:30 +01:00
parent 2cff9319e8
commit 9bafc7150e
5 changed files with 137 additions and 25 deletions

View File

@@ -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());

View File

@@ -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() {

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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