Loading services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +12 −14 Original line number Diff line number Diff line Loading @@ -74,7 +74,6 @@ import com.android.server.uri.UriGrantsManagerInternal; import com.android.server.wm.utils.MockTracker; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; Loading @@ -89,8 +88,6 @@ import java.util.List; class ActivityTestsBase { private static int sNextDisplayId = DEFAULT_DISPLAY + 1; private static MockTracker sMockTracker; @Rule public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule = new DexmakerShareClassLoaderRule(); Loading @@ -102,6 +99,8 @@ class ActivityTestsBase { RootActivityContainer mRootActivityContainer; ActivityStackSupervisor mSupervisor; private MockTracker mMockTracker; // Default package name static final String DEFAULT_COMPONENT_PACKAGE_NAME = "com.foo"; Loading @@ -110,19 +109,13 @@ class ActivityTestsBase { @BeforeClass public static void setUpOnceBase() { sMockTracker = new MockTracker(); AttributeCache.init(getInstrumentation().getTargetContext()); } @AfterClass public static void tearDownOnceBase() { sMockTracker.close(); sMockTracker = null; } @Before public void setUpBase() { mMockTracker = new MockTracker(); mTestInjector.setUp(); mService = new TestActivityTaskManagerService(mContext); Loading @@ -137,6 +130,9 @@ class ActivityTestsBase { mService.setWindowManager(null); mService = null; } mMockTracker.close(); mMockTracker = null; } /** Creates a {@link TestActivityDisplay}. */ Loading Loading @@ -651,7 +647,10 @@ class ActivityTestsBase { @Override protected DisplayContent createDisplayContent() { return WindowTestUtils.createTestDisplayContent(); final DisplayContent displayContent = mock(DisplayContent.class); DockedStackDividerController divider = mock(DockedStackDividerController.class); doReturn(divider).when(displayContent).getDockedDividerController(); return displayContent; } void removeAllTasks() { Loading Loading @@ -732,14 +731,13 @@ class ActivityTestsBase { @Override protected void createTaskStack(int displayId, boolean onTop, Rect outBounds) { mTaskStack = WindowTestUtils.createMockTaskStack(); mTaskStack = mock(TaskStack.class); // Primary pinned stacks require a non-empty out bounds to be set or else all tasks // will be moved to the full screen stack. if (getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { outBounds.set(0, 0, 100, 100); } } @Override Loading services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java +6 −30 Original line number Diff line number Diff line Loading @@ -24,14 +24,13 @@ import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE; import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY; import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE; import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; Loading @@ -39,9 +38,7 @@ import android.view.Display; import androidx.test.filters.SmallTest; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; /** Loading @@ -54,33 +51,12 @@ import org.junit.Test; @Presubmit public class AppTransitionTests extends WindowTestsBase { private static RootWindowContainer sOriginalRootWindowContainer; private DisplayContent mDc; @BeforeClass public static void setUpRootWindowContainerMock() { final WindowManagerService wm = TestSystemServices.getWindowManagerService(); // For unit test, we don't need to test performSurfacePlacement to prevent some abnormal // interaction with surfaceflinger native side. sOriginalRootWindowContainer = wm.mRoot; // Creating spied mock of RootWindowContainer shouldn't be done in @Before, since it will // create unnecessary nested spied objects chain, because WindowManagerService object under // test is a single instance shared among all tests that extend WindowTestsBase class. // Instead it should be done once before running all tests in this test class. wm.mRoot = spy(wm.mRoot); doNothing().when(wm.mRoot).performSurfacePlacement(anyBoolean()); } @AfterClass public static void tearDownRootWindowContainerMock() { final WindowManagerService wm = TestSystemServices.getWindowManagerService(); wm.mRoot = sOriginalRootWindowContainer; sOriginalRootWindowContainer = null; } @Before public void setUp() throws Exception { spyOn(mWm.mRoot); doNothing().when(mWm.mRoot).performSurfacePlacement(anyBoolean()); mDc = mWm.getDefaultDisplayContentLocked(); } Loading services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java +6 −7 Original line number Diff line number Diff line Loading @@ -26,11 +26,11 @@ import static android.view.Surface.ROTATION_180; import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; import static com.android.server.wm.utils.CoordinateTransforms.transformPhysicalToLogicalCoordinates; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.content.Context; import android.content.ContextWrapper; Loading Loading @@ -65,8 +65,7 @@ public class DisplayPolicyTestsBase extends WindowTestsBase { DisplayPolicy mDisplayPolicy; @Before public void setUpBase() { super.setUpBase(); public void setUpDisplayPolicy() { mDisplayPolicy = spy(mDisplayContent.getDisplayPolicy()); final TestContextWrapper context = Loading @@ -77,9 +76,9 @@ public class DisplayPolicyTestsBase extends WindowTestsBase { resources.addOverride(R.dimen.navigation_bar_height, NAV_BAR_HEIGHT); resources.addOverride(R.dimen.navigation_bar_height_landscape, NAV_BAR_HEIGHT); resources.addOverride(R.dimen.navigation_bar_width, NAV_BAR_HEIGHT); when(mDisplayPolicy.getSystemUiContext()).thenReturn(context); when(mDisplayPolicy.hasNavigationBar()).thenReturn(true); when(mDisplayPolicy.hasStatusBar()).thenReturn(true); doReturn(context).when(mDisplayPolicy).getSystemUiContext(); doReturn(true).when(mDisplayPolicy).hasNavigationBar(); doReturn(true).when(mDisplayPolicy).hasStatusBar(); final int shortSizeDp = Math.min(DISPLAY_WIDTH, DISPLAY_HEIGHT) * DENSITY_DEFAULT / DISPLAY_DENSITY; Loading services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java +1 −1 Original line number Diff line number Diff line Loading @@ -807,7 +807,7 @@ public class DisplayRotationTests { private void build() throws Exception { mMockContext = mock(Context.class); mMockDisplayContent = mock(WindowTestUtils.TestDisplayContent.class); mMockDisplayContent = mock(DisplayContent.class); mMockDisplayContent.isDefaultDisplay = mIsDefaultDisplay; when(mMockDisplayContent.calculateDisplayCutoutForRotation(anyInt())) .thenReturn(WmDisplayCutout.NO_CUTOUT); Loading services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java→services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java +80 −50 Original line number Diff line number Diff line Loading @@ -57,44 +57,61 @@ import com.android.server.LockGuard; import com.android.server.Watchdog; import com.android.server.input.InputManagerService; import com.android.server.policy.WindowManagerPolicy; import com.android.server.wm.utils.MockTracker; import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.Statement; import org.mockito.invocation.InvocationOnMock; import org.mockito.quality.Strictness; import java.util.concurrent.atomic.AtomicBoolean; /** * A Test utility class to create a mock {@link WindowManagerService} instance for tests. * JUnit test rule to create a mock {@link WindowManagerService} instance for tests. */ class TestSystemServices { private static StaticMockitoSession sMockitoSession; private static WindowManagerService sService; private static TestWindowManagerPolicy sPolicy; public class SystemServicesTestRule implements TestRule { static AtomicBoolean sCurrentMessagesProcessed = new AtomicBoolean(false); private static final String TAG = SystemServicesTestRule.class.getSimpleName(); static void setUpWindowManagerService() { sMockitoSession = mockitoSession() .spyStatic(LockGuard.class) .spyStatic(Watchdog.class) .strictness(Strictness.LENIENT) .startMocking(); private final AtomicBoolean mCurrentMessagesProcessed = new AtomicBoolean(false); runWithDexmakerShareClassLoader(TestSystemServices::setUpTestWindowService); } private MockTracker mMockTracker; private StaticMockitoSession mMockitoSession; private WindowManagerService mWindowManagerService; private TestWindowManagerPolicy mWindowManagerPolicy; static void tearDownWindowManagerService() { waitUntilWindowManagerHandlersIdle(); removeLocalServices(); sService = null; sPolicy = null; /** {@link MockTracker} to track mocks created by {@link SystemServicesTestRule}. */ private static class Tracker extends MockTracker { // This empty extended class is necessary since Mockito distinguishes a listener by it // class. } sMockitoSession.finishMocking(); sMockitoSession = null; @Override public Statement apply(Statement base, Description description) { return new Statement() { @Override public void evaluate() throws Throwable { try { runWithDexmakerShareClassLoader(SystemServicesTestRule.this::setUp); base.evaluate(); } finally { tearDown(); } } }; } private static void setUpTestWindowService() { doReturn(null).when(() -> LockGuard.installLock(any(), anyInt())); private void setUp() { mMockTracker = new Tracker(); mMockitoSession = mockitoSession() .spyStatic(LocalServices.class) .mockStatic(LockGuard.class) .mockStatic(Watchdog.class) .strictness(Strictness.LENIENT) .startMocking(); doReturn(mock(Watchdog.class)).when(Watchdog::getInstance); final Context context = getInstrumentation().getTargetContext(); Loading @@ -116,21 +133,18 @@ class TestSystemServices { doReturn(appOpsManager).when(context) .getSystemService(eq(Context.APP_OPS_SERVICE)); removeLocalServices(); final DisplayManagerInternal dmi = mock(DisplayManagerInternal.class); LocalServices.addService(DisplayManagerInternal.class, dmi); doReturn(dmi).when(() -> LocalServices.getService(eq(DisplayManagerInternal.class))); final PowerManagerInternal pmi = mock(PowerManagerInternal.class); LocalServices.addService(PowerManagerInternal.class, pmi); final PowerSaveState state = new PowerSaveState.Builder().build(); doReturn(state).when(pmi).getLowPowerState(anyInt()); doReturn(pmi).when(() -> LocalServices.getService(eq(PowerManagerInternal.class))); final ActivityManagerInternal ami = mock(ActivityManagerInternal.class); LocalServices.addService(ActivityManagerInternal.class, ami); doReturn(ami).when(() -> LocalServices.getService(eq(ActivityManagerInternal.class))); final ActivityTaskManagerInternal atmi = mock(ActivityTaskManagerInternal.class); LocalServices.addService(ActivityTaskManagerInternal.class, atmi); doAnswer((InvocationOnMock invocationOnMock) -> { final Runnable runnable = invocationOnMock.getArgument(0); if (runnable != null) { Loading @@ -138,6 +152,7 @@ class TestSystemServices { } return null; }).when(atmi).notifyKeyguardFlagsChanged(nullable(Runnable.class), anyInt()); doReturn(atmi).when(() -> LocalServices.getService(eq(ActivityTaskManagerInternal.class))); final InputManagerService ims = mock(InputManagerService.class); // InputChannel is final and can't be mocked. Loading @@ -150,31 +165,46 @@ class TestSystemServices { final WindowManagerGlobalLock wmLock = new WindowManagerGlobalLock(); doReturn(wmLock).when(atms).getGlobalLock(); sPolicy = new TestWindowManagerPolicy(TestSystemServices::getWindowManagerService); sService = WindowManagerService.main(context, ims, false, false, sPolicy, atms); mWindowManagerPolicy = new TestWindowManagerPolicy(this::getWindowManagerService); mWindowManagerService = WindowManagerService.main( context, ims, false, false, mWindowManagerPolicy, atms); sService.onInitReady(); mWindowManagerService.onInitReady(); final Display display = sService.mDisplayManager.getDisplay(DEFAULT_DISPLAY); final Display display = mWindowManagerService.mDisplayManager.getDisplay(DEFAULT_DISPLAY); // Display creation is driven by the ActivityManagerService via // ActivityStackSupervisor. We emulate those steps here. sService.mRoot.createDisplayContent(display, mock(ActivityDisplay.class)); mWindowManagerService.mRoot.createDisplayContent(display, mock(ActivityDisplay.class)); mMockTracker.stopTracking(); } private void tearDown() { waitUntilWindowManagerHandlersIdle(); removeLocalServices(); mWindowManagerService = null; mWindowManagerPolicy = null; if (mMockitoSession != null) { mMockitoSession.finishMocking(); mMockitoSession = null; } if (mMockTracker != null) { mMockTracker.close(); mMockTracker = null; } } private static void removeLocalServices() { LocalServices.removeServiceForTest(DisplayManagerInternal.class); LocalServices.removeServiceForTest(PowerManagerInternal.class); LocalServices.removeServiceForTest(ActivityManagerInternal.class); LocalServices.removeServiceForTest(ActivityTaskManagerInternal.class); LocalServices.removeServiceForTest(WindowManagerInternal.class); LocalServices.removeServiceForTest(WindowManagerPolicy.class); } static WindowManagerService getWindowManagerService() { return sService; WindowManagerService getWindowManagerService() { return mWindowManagerService; } static void cleanupWindowManagerHandlers() { void cleanupWindowManagerHandlers() { final WindowManagerService wm = getWindowManagerService(); if (wm == null) { return; Loading @@ -184,7 +214,7 @@ class TestSystemServices { SurfaceAnimationThread.getHandler().removeCallbacksAndMessages(null); } static void waitUntilWindowManagerHandlersIdle() { void waitUntilWindowManagerHandlersIdle() { final WindowManagerService wm = getWindowManagerService(); if (wm == null) { return; Loading @@ -196,21 +226,21 @@ class TestSystemServices { waitHandlerIdle(SurfaceAnimationThread.getHandler()); } private static void waitHandlerIdle(Handler handler) { synchronized (sCurrentMessagesProcessed) { private void waitHandlerIdle(Handler handler) { synchronized (mCurrentMessagesProcessed) { // Add a message to the handler queue and make sure it is fully processed before we move // on. This makes sure all previous messages in the handler are fully processed vs. just // popping them from the message queue. sCurrentMessagesProcessed.set(false); mCurrentMessagesProcessed.set(false); handler.post(() -> { synchronized (sCurrentMessagesProcessed) { sCurrentMessagesProcessed.set(true); sCurrentMessagesProcessed.notifyAll(); synchronized (mCurrentMessagesProcessed) { mCurrentMessagesProcessed.set(true); mCurrentMessagesProcessed.notifyAll(); } }); while (!sCurrentMessagesProcessed.get()) { while (!mCurrentMessagesProcessed.get()) { try { sCurrentMessagesProcessed.wait(); mCurrentMessagesProcessed.wait(); } catch (InterruptedException e) { } } Loading Loading
services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +12 −14 Original line number Diff line number Diff line Loading @@ -74,7 +74,6 @@ import com.android.server.uri.UriGrantsManagerInternal; import com.android.server.wm.utils.MockTracker; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; Loading @@ -89,8 +88,6 @@ import java.util.List; class ActivityTestsBase { private static int sNextDisplayId = DEFAULT_DISPLAY + 1; private static MockTracker sMockTracker; @Rule public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule = new DexmakerShareClassLoaderRule(); Loading @@ -102,6 +99,8 @@ class ActivityTestsBase { RootActivityContainer mRootActivityContainer; ActivityStackSupervisor mSupervisor; private MockTracker mMockTracker; // Default package name static final String DEFAULT_COMPONENT_PACKAGE_NAME = "com.foo"; Loading @@ -110,19 +109,13 @@ class ActivityTestsBase { @BeforeClass public static void setUpOnceBase() { sMockTracker = new MockTracker(); AttributeCache.init(getInstrumentation().getTargetContext()); } @AfterClass public static void tearDownOnceBase() { sMockTracker.close(); sMockTracker = null; } @Before public void setUpBase() { mMockTracker = new MockTracker(); mTestInjector.setUp(); mService = new TestActivityTaskManagerService(mContext); Loading @@ -137,6 +130,9 @@ class ActivityTestsBase { mService.setWindowManager(null); mService = null; } mMockTracker.close(); mMockTracker = null; } /** Creates a {@link TestActivityDisplay}. */ Loading Loading @@ -651,7 +647,10 @@ class ActivityTestsBase { @Override protected DisplayContent createDisplayContent() { return WindowTestUtils.createTestDisplayContent(); final DisplayContent displayContent = mock(DisplayContent.class); DockedStackDividerController divider = mock(DockedStackDividerController.class); doReturn(divider).when(displayContent).getDockedDividerController(); return displayContent; } void removeAllTasks() { Loading Loading @@ -732,14 +731,13 @@ class ActivityTestsBase { @Override protected void createTaskStack(int displayId, boolean onTop, Rect outBounds) { mTaskStack = WindowTestUtils.createMockTaskStack(); mTaskStack = mock(TaskStack.class); // Primary pinned stacks require a non-empty out bounds to be set or else all tasks // will be moved to the full screen stack. if (getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { outBounds.set(0, 0, 100, 100); } } @Override Loading
services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java +6 −30 Original line number Diff line number Diff line Loading @@ -24,14 +24,13 @@ import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE; import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY; import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE; import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; Loading @@ -39,9 +38,7 @@ import android.view.Display; import androidx.test.filters.SmallTest; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; /** Loading @@ -54,33 +51,12 @@ import org.junit.Test; @Presubmit public class AppTransitionTests extends WindowTestsBase { private static RootWindowContainer sOriginalRootWindowContainer; private DisplayContent mDc; @BeforeClass public static void setUpRootWindowContainerMock() { final WindowManagerService wm = TestSystemServices.getWindowManagerService(); // For unit test, we don't need to test performSurfacePlacement to prevent some abnormal // interaction with surfaceflinger native side. sOriginalRootWindowContainer = wm.mRoot; // Creating spied mock of RootWindowContainer shouldn't be done in @Before, since it will // create unnecessary nested spied objects chain, because WindowManagerService object under // test is a single instance shared among all tests that extend WindowTestsBase class. // Instead it should be done once before running all tests in this test class. wm.mRoot = spy(wm.mRoot); doNothing().when(wm.mRoot).performSurfacePlacement(anyBoolean()); } @AfterClass public static void tearDownRootWindowContainerMock() { final WindowManagerService wm = TestSystemServices.getWindowManagerService(); wm.mRoot = sOriginalRootWindowContainer; sOriginalRootWindowContainer = null; } @Before public void setUp() throws Exception { spyOn(mWm.mRoot); doNothing().when(mWm.mRoot).performSurfacePlacement(anyBoolean()); mDc = mWm.getDefaultDisplayContentLocked(); } Loading
services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java +6 −7 Original line number Diff line number Diff line Loading @@ -26,11 +26,11 @@ import static android.view.Surface.ROTATION_180; import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; import static com.android.server.wm.utils.CoordinateTransforms.transformPhysicalToLogicalCoordinates; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.content.Context; import android.content.ContextWrapper; Loading Loading @@ -65,8 +65,7 @@ public class DisplayPolicyTestsBase extends WindowTestsBase { DisplayPolicy mDisplayPolicy; @Before public void setUpBase() { super.setUpBase(); public void setUpDisplayPolicy() { mDisplayPolicy = spy(mDisplayContent.getDisplayPolicy()); final TestContextWrapper context = Loading @@ -77,9 +76,9 @@ public class DisplayPolicyTestsBase extends WindowTestsBase { resources.addOverride(R.dimen.navigation_bar_height, NAV_BAR_HEIGHT); resources.addOverride(R.dimen.navigation_bar_height_landscape, NAV_BAR_HEIGHT); resources.addOverride(R.dimen.navigation_bar_width, NAV_BAR_HEIGHT); when(mDisplayPolicy.getSystemUiContext()).thenReturn(context); when(mDisplayPolicy.hasNavigationBar()).thenReturn(true); when(mDisplayPolicy.hasStatusBar()).thenReturn(true); doReturn(context).when(mDisplayPolicy).getSystemUiContext(); doReturn(true).when(mDisplayPolicy).hasNavigationBar(); doReturn(true).when(mDisplayPolicy).hasStatusBar(); final int shortSizeDp = Math.min(DISPLAY_WIDTH, DISPLAY_HEIGHT) * DENSITY_DEFAULT / DISPLAY_DENSITY; Loading
services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java +1 −1 Original line number Diff line number Diff line Loading @@ -807,7 +807,7 @@ public class DisplayRotationTests { private void build() throws Exception { mMockContext = mock(Context.class); mMockDisplayContent = mock(WindowTestUtils.TestDisplayContent.class); mMockDisplayContent = mock(DisplayContent.class); mMockDisplayContent.isDefaultDisplay = mIsDefaultDisplay; when(mMockDisplayContent.calculateDisplayCutoutForRotation(anyInt())) .thenReturn(WmDisplayCutout.NO_CUTOUT); Loading
services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java→services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java +80 −50 Original line number Diff line number Diff line Loading @@ -57,44 +57,61 @@ import com.android.server.LockGuard; import com.android.server.Watchdog; import com.android.server.input.InputManagerService; import com.android.server.policy.WindowManagerPolicy; import com.android.server.wm.utils.MockTracker; import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.Statement; import org.mockito.invocation.InvocationOnMock; import org.mockito.quality.Strictness; import java.util.concurrent.atomic.AtomicBoolean; /** * A Test utility class to create a mock {@link WindowManagerService} instance for tests. * JUnit test rule to create a mock {@link WindowManagerService} instance for tests. */ class TestSystemServices { private static StaticMockitoSession sMockitoSession; private static WindowManagerService sService; private static TestWindowManagerPolicy sPolicy; public class SystemServicesTestRule implements TestRule { static AtomicBoolean sCurrentMessagesProcessed = new AtomicBoolean(false); private static final String TAG = SystemServicesTestRule.class.getSimpleName(); static void setUpWindowManagerService() { sMockitoSession = mockitoSession() .spyStatic(LockGuard.class) .spyStatic(Watchdog.class) .strictness(Strictness.LENIENT) .startMocking(); private final AtomicBoolean mCurrentMessagesProcessed = new AtomicBoolean(false); runWithDexmakerShareClassLoader(TestSystemServices::setUpTestWindowService); } private MockTracker mMockTracker; private StaticMockitoSession mMockitoSession; private WindowManagerService mWindowManagerService; private TestWindowManagerPolicy mWindowManagerPolicy; static void tearDownWindowManagerService() { waitUntilWindowManagerHandlersIdle(); removeLocalServices(); sService = null; sPolicy = null; /** {@link MockTracker} to track mocks created by {@link SystemServicesTestRule}. */ private static class Tracker extends MockTracker { // This empty extended class is necessary since Mockito distinguishes a listener by it // class. } sMockitoSession.finishMocking(); sMockitoSession = null; @Override public Statement apply(Statement base, Description description) { return new Statement() { @Override public void evaluate() throws Throwable { try { runWithDexmakerShareClassLoader(SystemServicesTestRule.this::setUp); base.evaluate(); } finally { tearDown(); } } }; } private static void setUpTestWindowService() { doReturn(null).when(() -> LockGuard.installLock(any(), anyInt())); private void setUp() { mMockTracker = new Tracker(); mMockitoSession = mockitoSession() .spyStatic(LocalServices.class) .mockStatic(LockGuard.class) .mockStatic(Watchdog.class) .strictness(Strictness.LENIENT) .startMocking(); doReturn(mock(Watchdog.class)).when(Watchdog::getInstance); final Context context = getInstrumentation().getTargetContext(); Loading @@ -116,21 +133,18 @@ class TestSystemServices { doReturn(appOpsManager).when(context) .getSystemService(eq(Context.APP_OPS_SERVICE)); removeLocalServices(); final DisplayManagerInternal dmi = mock(DisplayManagerInternal.class); LocalServices.addService(DisplayManagerInternal.class, dmi); doReturn(dmi).when(() -> LocalServices.getService(eq(DisplayManagerInternal.class))); final PowerManagerInternal pmi = mock(PowerManagerInternal.class); LocalServices.addService(PowerManagerInternal.class, pmi); final PowerSaveState state = new PowerSaveState.Builder().build(); doReturn(state).when(pmi).getLowPowerState(anyInt()); doReturn(pmi).when(() -> LocalServices.getService(eq(PowerManagerInternal.class))); final ActivityManagerInternal ami = mock(ActivityManagerInternal.class); LocalServices.addService(ActivityManagerInternal.class, ami); doReturn(ami).when(() -> LocalServices.getService(eq(ActivityManagerInternal.class))); final ActivityTaskManagerInternal atmi = mock(ActivityTaskManagerInternal.class); LocalServices.addService(ActivityTaskManagerInternal.class, atmi); doAnswer((InvocationOnMock invocationOnMock) -> { final Runnable runnable = invocationOnMock.getArgument(0); if (runnable != null) { Loading @@ -138,6 +152,7 @@ class TestSystemServices { } return null; }).when(atmi).notifyKeyguardFlagsChanged(nullable(Runnable.class), anyInt()); doReturn(atmi).when(() -> LocalServices.getService(eq(ActivityTaskManagerInternal.class))); final InputManagerService ims = mock(InputManagerService.class); // InputChannel is final and can't be mocked. Loading @@ -150,31 +165,46 @@ class TestSystemServices { final WindowManagerGlobalLock wmLock = new WindowManagerGlobalLock(); doReturn(wmLock).when(atms).getGlobalLock(); sPolicy = new TestWindowManagerPolicy(TestSystemServices::getWindowManagerService); sService = WindowManagerService.main(context, ims, false, false, sPolicy, atms); mWindowManagerPolicy = new TestWindowManagerPolicy(this::getWindowManagerService); mWindowManagerService = WindowManagerService.main( context, ims, false, false, mWindowManagerPolicy, atms); sService.onInitReady(); mWindowManagerService.onInitReady(); final Display display = sService.mDisplayManager.getDisplay(DEFAULT_DISPLAY); final Display display = mWindowManagerService.mDisplayManager.getDisplay(DEFAULT_DISPLAY); // Display creation is driven by the ActivityManagerService via // ActivityStackSupervisor. We emulate those steps here. sService.mRoot.createDisplayContent(display, mock(ActivityDisplay.class)); mWindowManagerService.mRoot.createDisplayContent(display, mock(ActivityDisplay.class)); mMockTracker.stopTracking(); } private void tearDown() { waitUntilWindowManagerHandlersIdle(); removeLocalServices(); mWindowManagerService = null; mWindowManagerPolicy = null; if (mMockitoSession != null) { mMockitoSession.finishMocking(); mMockitoSession = null; } if (mMockTracker != null) { mMockTracker.close(); mMockTracker = null; } } private static void removeLocalServices() { LocalServices.removeServiceForTest(DisplayManagerInternal.class); LocalServices.removeServiceForTest(PowerManagerInternal.class); LocalServices.removeServiceForTest(ActivityManagerInternal.class); LocalServices.removeServiceForTest(ActivityTaskManagerInternal.class); LocalServices.removeServiceForTest(WindowManagerInternal.class); LocalServices.removeServiceForTest(WindowManagerPolicy.class); } static WindowManagerService getWindowManagerService() { return sService; WindowManagerService getWindowManagerService() { return mWindowManagerService; } static void cleanupWindowManagerHandlers() { void cleanupWindowManagerHandlers() { final WindowManagerService wm = getWindowManagerService(); if (wm == null) { return; Loading @@ -184,7 +214,7 @@ class TestSystemServices { SurfaceAnimationThread.getHandler().removeCallbacksAndMessages(null); } static void waitUntilWindowManagerHandlersIdle() { void waitUntilWindowManagerHandlersIdle() { final WindowManagerService wm = getWindowManagerService(); if (wm == null) { return; Loading @@ -196,21 +226,21 @@ class TestSystemServices { waitHandlerIdle(SurfaceAnimationThread.getHandler()); } private static void waitHandlerIdle(Handler handler) { synchronized (sCurrentMessagesProcessed) { private void waitHandlerIdle(Handler handler) { synchronized (mCurrentMessagesProcessed) { // Add a message to the handler queue and make sure it is fully processed before we move // on. This makes sure all previous messages in the handler are fully processed vs. just // popping them from the message queue. sCurrentMessagesProcessed.set(false); mCurrentMessagesProcessed.set(false); handler.post(() -> { synchronized (sCurrentMessagesProcessed) { sCurrentMessagesProcessed.set(true); sCurrentMessagesProcessed.notifyAll(); synchronized (mCurrentMessagesProcessed) { mCurrentMessagesProcessed.set(true); mCurrentMessagesProcessed.notifyAll(); } }); while (!sCurrentMessagesProcessed.get()) { while (!mCurrentMessagesProcessed.get()) { try { sCurrentMessagesProcessed.wait(); mCurrentMessagesProcessed.wait(); } catch (InterruptedException e) { } } Loading