diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java index 569c6d4af37d3..e3ce6be3e4437 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java @@ -115,6 +115,10 @@ class ActivityTestsBase { @After public void tearDownBase() { mTestInjector.tearDown(); + if (mService != null) { + mService.setWindowManager(null); + mService = null; + } } ActivityTaskManagerService createActivityTaskManagerService() { @@ -619,7 +623,13 @@ class ActivityTestsBase { } } + private static WindowManagerService sMockWindowManagerService; + private static WindowManagerService prepareMockWindowManager() { + if (sMockWindowManagerService != null) { + return sMockWindowManagerService; + } + final WindowManagerService service = mock(WindowManagerService.class); service.mRoot = mock(RootWindowContainer.class); @@ -631,6 +641,7 @@ class ActivityTestsBase { return null; }).when(service).inSurfaceTransaction(any()); + sMockWindowManagerService = service; return service; } diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java index 6b31e6fdbd289..198e7ce63f527 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java @@ -63,6 +63,7 @@ import com.android.server.statusbar.StatusBarManagerInternal; import org.junit.After; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.mockito.ArgumentCaptor; @@ -86,7 +87,7 @@ public class DisplayRotationTests { private StatusBarManagerInternal mPreviousStatusBarManagerInternal; - private WindowManagerService mMockWm; + private static WindowManagerService sMockWm; private DisplayContent mMockDisplayContent; private DisplayPolicy mMockDisplayPolicy; private Context mMockContext; @@ -108,13 +109,16 @@ public class DisplayRotationTests { private DisplayRotation mTarget; + @BeforeClass + public static void setUpOnce() { + sMockWm = mock(WindowManagerService.class); + sMockWm.mPowerManagerInternal = mock(PowerManagerInternal.class); + } + @Before public void setUp() { FakeSettingsProvider.clearSettingsProvider(); - mMockWm = mock(WindowManagerService.class); - mMockWm.mPowerManagerInternal = mock(PowerManagerInternal.class); - mPreviousStatusBarManagerInternal = LocalServices.getService( StatusBarManagerInternal.class); LocalServices.removeServiceForTest(StatusBarManagerInternal.class); @@ -452,7 +456,7 @@ public class DisplayRotationTests { mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90)); assertTrue(waitForUiHandler()); - verify(mMockWm).updateRotation(false, false); + verify(sMockWm).updateRotation(false, false); } @Test @@ -833,8 +837,9 @@ public class DisplayRotationTests { .thenReturn(mFakeSettingsProvider.getIContentProvider()); mMockDisplayWindowSettings = mock(DisplayWindowSettings.class); - mTarget = new DisplayRotation(mMockWm, mMockDisplayContent, mMockDisplayPolicy, + mTarget = new DisplayRotation(sMockWm, mMockDisplayContent, mMockDisplayPolicy, mMockDisplayWindowSettings, mMockContext, new Object()); + reset(sMockWm); captureObservers(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java index a9f150b10e73a..e24eb75a2750b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java @@ -34,7 +34,12 @@ import static android.telecom.TelecomManager.EMERGENCY_DIALER_COMPONENT; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.isNull; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset; @@ -47,10 +52,6 @@ import static com.android.server.wm.LockTaskController.STATUS_BAR_MASK_PINNED; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; import android.app.StatusBarManager; import android.app.admin.DevicePolicyManager; @@ -115,6 +116,7 @@ public class LockTaskControllerTest { private LockTaskController mLockTaskController; private Context mContext; + private String mPackageName; private String mLockToAppSetting; @Before @@ -122,6 +124,7 @@ public class LockTaskControllerTest { MockitoAnnotations.initMocks(this); mContext = getInstrumentation().getTargetContext(); + mPackageName = mContext.getPackageName(); mLockToAppSetting = Settings.Secure.getString(mContext.getContentResolver(), Settings.Secure.LOCK_TO_APP_EXIT_LOCKED); @@ -146,6 +149,7 @@ public class LockTaskControllerTest { @After public void tearDown() throws Exception { + mLockTaskController.setWindowManager(null); Settings.Secure.putString(mContext.getContentResolver(), Settings.Secure.LOCK_TO_APP_EXIT_LOCKED, mLockToAppSetting); } @@ -223,7 +227,7 @@ public class LockTaskControllerTest { // THEN lock task mode should be started verifyLockTaskStarted(STATUS_BAR_MASK_PINNED, DISABLE2_NONE); // THEN screen pinning toast should be shown - verify(mStatusBarService).showPinningEnterExitToast(true /* entering */); + verify(mStatusBarService).showPinningEnterExitToast(eq(true /* entering */)); } @Test @@ -390,9 +394,9 @@ public class LockTaskControllerTest { // THEN lock task mode should have been finished verifyLockTaskStopped(times(1)); // THEN the keyguard should be shown - verify(mLockPatternUtils).requireCredentialEntry(UserHandle.USER_ALL); + verify(mLockPatternUtils).requireCredentialEntry(eq(UserHandle.USER_ALL)); // THEN screen pinning toast should be shown - verify(mStatusBarService).showPinningEnterExitToast(false /* entering */); + verify(mStatusBarService).showPinningEnterExitToast(eq(false /* entering */)); } @Test @@ -509,9 +513,9 @@ public class LockTaskControllerTest { & ~DISABLE_HOME; int expectedFlags2 = DISABLE2_MASK; verify(mStatusBarService).disable(eq(expectedFlags), any(IBinder.class), - eq(mContext.getPackageName())); + eq(mPackageName)); verify(mStatusBarService).disable2(eq(expectedFlags2), any(IBinder.class), - eq(mContext.getPackageName())); + eq(mPackageName)); // reset invocation counter reset(mStatusBarService); @@ -526,9 +530,9 @@ public class LockTaskControllerTest { expectedFlags2 = DISABLE2_MASK & ~DISABLE2_NOTIFICATION_SHADE; verify(mStatusBarService).disable(eq(expectedFlags), any(IBinder.class), - eq(mContext.getPackageName())); + eq(mPackageName)); verify(mStatusBarService).disable2(eq(expectedFlags2), any(IBinder.class), - eq(mContext.getPackageName())); + eq(mPackageName)); } @Test @@ -548,9 +552,9 @@ public class LockTaskControllerTest { // THEN status bar shouldn't change verify(mStatusBarService, never()).disable(anyInt(), any(IBinder.class), - eq(mContext.getPackageName())); + eq(mPackageName)); verify(mStatusBarService, never()).disable2(anyInt(), any(IBinder.class), - eq(mContext.getPackageName())); + eq(mPackageName)); } @Test @@ -657,14 +661,14 @@ public class LockTaskControllerTest { verify(mWindowManager).disableKeyguard(any(IBinder.class), anyString(), eq(TEST_USER_ID)); // THEN the status bar should have been disabled verify(mStatusBarService).disable(eq(statusBarMask), any(IBinder.class), - eq(mContext.getPackageName())); + eq(mPackageName)); verify(mStatusBarService).disable2(eq(statusBarMask2), any(IBinder.class), - eq(mContext.getPackageName())); + eq(mPackageName)); // THEN recents should have been notified verify(mRecentTasks).onLockTaskModeStateChanged(anyInt(), eq(TEST_USER_ID)); // THEN the DO/PO should be informed about the operation - verify(mDevicePolicyManager).notifyLockTaskModeChanged(true, TEST_PACKAGE_NAME, - TEST_USER_ID); + verify(mDevicePolicyManager).notifyLockTaskModeChanged(eq(true), eq(TEST_PACKAGE_NAME), + eq(TEST_USER_ID)); } private void verifyLockTaskStopped(VerificationMode mode) throws Exception { @@ -672,11 +676,12 @@ public class LockTaskControllerTest { verify(mWindowManager, mode).reenableKeyguard(any(IBinder.class), eq(TEST_USER_ID)); // THEN the status bar should have been disabled verify(mStatusBarService, mode).disable(eq(StatusBarManager.DISABLE_NONE), - any(IBinder.class), eq(mContext.getPackageName())); + any(IBinder.class), eq(mPackageName)); verify(mStatusBarService, mode).disable2(eq(StatusBarManager.DISABLE2_NONE), - any(IBinder.class), eq(mContext.getPackageName())); + any(IBinder.class), eq(mPackageName)); // THEN the DO/PO should be informed about the operation - verify(mDevicePolicyManager, mode).notifyLockTaskModeChanged(false, null, TEST_USER_ID); + verify(mDevicePolicyManager, mode).notifyLockTaskModeChanged(eq(false), isNull(), + eq(TEST_USER_ID)); } /** diff --git a/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java b/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java index 36eccd1892a7c..03aba39517ebc 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java @@ -33,6 +33,8 @@ import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; @@ -58,7 +60,6 @@ import android.view.WindowInsets; import android.view.WindowManager; import android.widget.TextView; -import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import org.junit.After; @@ -80,8 +81,8 @@ import java.util.function.BooleanSupplier; @Presubmit public class ScreenDecorWindowTests { - private final Context mContext = InstrumentationRegistry.getTargetContext(); - private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation(); + private final Context mContext = getInstrumentation().getTargetContext(); + private final Instrumentation mInstrumentation = getInstrumentation(); private WindowManager mWm; private ArrayList mWindows = new ArrayList<>(); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRule.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRule.java deleted file mode 100644 index cba958682401c..0000000000000 --- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRule.java +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.wm; - -import static android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader; -import static android.view.Display.DEFAULT_DISPLAY; - -import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; - -import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; -import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.when; - -import android.app.ActivityManagerInternal; -import android.content.Context; -import android.hardware.display.DisplayManagerInternal; -import android.os.Handler; -import android.os.PowerManagerInternal; -import android.os.PowerSaveState; -import android.view.Display; -import android.view.InputChannel; -import android.view.SurfaceControl; -import android.view.SurfaceControl.Transaction; - -import com.android.server.LocalServices; -import com.android.server.input.InputManagerService; -import com.android.server.policy.WindowManagerPolicy; - -import org.junit.rules.TestRule; -import org.junit.runner.Description; -import org.junit.runners.model.Statement; -import org.mockito.invocation.InvocationOnMock; - -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CountDownLatch; - -/** - * A test rule that sets up a fresh WindowManagerService instance before each test and makes sure - * to properly tear it down after. - * - *

- * Usage: - *

- * {@literal @}Rule
- *  public final WindowManagerServiceRule mWmRule = new WindowManagerServiceRule();
- * 
- */ -public class WindowManagerServiceRule implements TestRule { - - private WindowManagerService mService; - private TestWindowManagerPolicy mPolicy; - // Record all {@link SurfaceControl.Transaction} created while testing and releases native - // resources when test finishes. - private final List> mSurfaceTransactions = new ArrayList<>(); - // Record all {@link SurfaceControl} created while testing and releases native resources when - // test finishes. - private final List> mSurfaceControls = new ArrayList<>(); - - @Override - public Statement apply(Statement base, Description description) { - return new Statement() { - @Override - public void evaluate() throws Throwable { - runWithDexmakerShareClassLoader(this::setUp); - try { - base.evaluate(); - } finally { - tearDown(); - } - } - - private void setUp() { - final Context context = getInstrumentation().getTargetContext(); - - removeServices(); - - LocalServices.addService(DisplayManagerInternal.class, - mock(DisplayManagerInternal.class)); - - LocalServices.addService(PowerManagerInternal.class, - mock(PowerManagerInternal.class)); - final PowerManagerInternal pm = - LocalServices.getService(PowerManagerInternal.class); - doNothing().when(pm).registerLowPowerModeObserver(any()); - PowerSaveState state = new PowerSaveState.Builder().build(); - doReturn(state).when(pm).getLowPowerState(anyInt()); - - LocalServices.addService(ActivityManagerInternal.class, - mock(ActivityManagerInternal.class)); - LocalServices.addService(ActivityTaskManagerInternal.class, - mock(ActivityTaskManagerInternal.class)); - final ActivityTaskManagerInternal atm = - LocalServices.getService(ActivityTaskManagerInternal.class); - doAnswer((InvocationOnMock invocationOnMock) -> { - final Runnable runnable = invocationOnMock.getArgument(0); - if (runnable != null) { - runnable.run(); - } - return null; - }).when(atm).notifyKeyguardFlagsChanged(any(), anyInt()); - - InputManagerService ims = mock(InputManagerService.class); - // InputChannel is final and can't be mocked. - InputChannel[] input = InputChannel.openInputChannelPair(TAG_WM); - if (input != null && input.length > 1) { - doReturn(input[1]).when(ims).monitorInput(anyString(), anyInt()); - } - ActivityTaskManagerService atms = mock(ActivityTaskManagerService.class); - when(atms.getGlobalLock()).thenReturn(new WindowManagerGlobalLock()); - - mService = WindowManagerService.main(context, ims, false, false, - mPolicy = new TestWindowManagerPolicy( - WindowManagerServiceRule.this::getWindowManagerService), atms); - mService.mTransactionFactory = () -> { - final SurfaceControl.Transaction transaction = new SurfaceControl.Transaction(); - mSurfaceTransactions.add(new WeakReference<>(transaction)); - return transaction; - }; - mService.mSurfaceBuilderFactory = session -> new SurfaceControl.Builder(session) { - @Override - public SurfaceControl build() { - final SurfaceControl control = super.build(); - mSurfaceControls.add(new WeakReference<>(control)); - return control; - } - }; - - mService.onInitReady(); - - final Display display = mService.mDisplayManager.getDisplay(DEFAULT_DISPLAY); - // Display creation is driven by the ActivityManagerService via - // ActivityStackSupervisor. We emulate those steps here. - mService.mRoot.createDisplayContent(display, mock(ActivityDisplay.class)); - } - - private void removeServices() { - LocalServices.removeServiceForTest(DisplayManagerInternal.class); - LocalServices.removeServiceForTest(PowerManagerInternal.class); - LocalServices.removeServiceForTest(ActivityManagerInternal.class); - LocalServices.removeServiceForTest(ActivityTaskManagerInternal.class); - LocalServices.removeServiceForTest(WindowManagerInternal.class); - LocalServices.removeServiceForTest(WindowManagerPolicy.class); - } - - private void tearDown() { - cancelAllPendingAnimations(); - waitUntilWindowManagerHandlersIdle(); - destroyAllSurfaceTransactions(); - destroyAllSurfaceControls(); - removeServices(); - mService = null; - mPolicy = null; - } - }; - } - - WindowManagerService getWindowManagerService() { - return mService; - } - - private void cancelAllPendingAnimations() { - for (final WeakReference reference : mSurfaceControls) { - final SurfaceControl sc = reference.get(); - if (sc != null) { - mService.mSurfaceAnimationRunner.onAnimationCancelled(sc); - } - } - } - - void waitUntilWindowManagerHandlersIdle() { - final WindowManagerService wm = getWindowManagerService(); - if (wm == null) { - return; - } - // Removing delayed FORCE_GC message decreases time for waiting idle. - wm.mH.removeMessages(WindowManagerService.H.FORCE_GC); - waitHandlerIdle(wm.mH); - waitHandlerIdle(wm.mAnimationHandler); - waitHandlerIdle(SurfaceAnimationThread.getHandler()); - } - - private static void waitHandlerIdle(Handler handler) { - if (handler.hasMessagesOrCallbacks()) { - final CountDownLatch latch = new CountDownLatch(1); - // Wait for delayed messages are processed. - handler.getLooper().getQueue().addIdleHandler(() -> { - if (handler.hasMessagesOrCallbacks()) { - return true; // keep idle handler. - } - latch.countDown(); - return false; // remove idle handler. - }); - try { - latch.await(); - } catch (InterruptedException e) { - } - } - } - - private void destroyAllSurfaceTransactions() { - for (final WeakReference reference : mSurfaceTransactions) { - final Transaction transaction = reference.get(); - if (transaction != null) { - reference.clear(); - transaction.close(); - } - } - } - - private void destroyAllSurfaceControls() { - for (final WeakReference reference : mSurfaceControls) { - final SurfaceControl control = reference.get(); - if (control != null) { - reference.clear(); - control.destroy(); - } - } - } -} diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRuleTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRuleTest.java deleted file mode 100644 index 343d35959df4f..0000000000000 --- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRuleTest.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.wm; - -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.junit.Assert.assertThat; - -import android.platform.test.annotations.Presubmit; - -import androidx.test.filters.SmallTest; - -import org.junit.Rule; -import org.junit.Test; - -/** - * Build/InstallRun: - * atest FrameworksServicesTests:WindowManagerServiceRuleTest - */ -@Presubmit -@SmallTest -public class WindowManagerServiceRuleTest { - - @Rule - public final WindowManagerServiceRule mRule = new WindowManagerServiceRule(); - - @Test - public void testWindowManagerSetUp() { - assertThat(mRule.getWindowManagerService(), notNullValue()); - } -} diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index 5c3368bd25acc..3813891ef0e0a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -53,6 +53,7 @@ import android.view.WindowManager; import com.android.server.AttributeCache; import org.junit.After; +import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; @@ -95,17 +96,22 @@ class WindowTestsBase { public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule = new DexmakerShareClassLoaderRule(); - @Rule - public final WindowManagerServiceRule mWmRule = new WindowManagerServiceRule(); - - static WindowState.PowerManagerWrapper sPowerManagerWrapper; // TODO(roosa): make non-static. + static WindowState.PowerManagerWrapper sPowerManagerWrapper; @BeforeClass public static void setUpOnceBase() { AttributeCache.init(getInstrumentation().getTargetContext()); + + WmServiceUtils.setUpWindowManagerService(); + sPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class); } + @AfterClass + public static void tearDonwOnceBase() { + WmServiceUtils.tearDownWindowManagerService(); + } + @Before public void setUpBase() { // If @Before throws an exception, the error isn't logged. This will make sure any failures @@ -115,7 +121,7 @@ class WindowTestsBase { final Context context = getInstrumentation().getTargetContext(); - mWm = mWmRule.getWindowManagerService(); + mWm = WmServiceUtils.getWindowManagerService(); beforeCreateDisplay(); context.getDisplay().getDisplayInfo(mDisplayInfo); @@ -214,7 +220,7 @@ class WindowTestsBase { * Waits until the main handler for WM has processed all messages. */ void waitUntilHandlersIdle() { - mWmRule.waitUntilWindowManagerHandlersIdle(); + WmServiceUtils.waitUntilWindowManagerHandlersIdle(); } private WindowToken createWindowToken( diff --git a/services/tests/wmtests/src/com/android/server/wm/WmServiceUtils.java b/services/tests/wmtests/src/com/android/server/wm/WmServiceUtils.java new file mode 100644 index 0000000000000..2465e5d89bb11 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/WmServiceUtils.java @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm; + +import static android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader; +import static android.view.Display.DEFAULT_DISPLAY; + +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + +import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.nullable; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; +import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; + +import android.app.ActivityManagerInternal; +import android.app.AppOpsManager; +import android.content.BroadcastReceiver; +import android.content.ContentResolver; +import android.content.Context; +import android.content.IntentFilter; +import android.database.ContentObserver; +import android.hardware.display.DisplayManagerInternal; +import android.net.Uri; +import android.os.Handler; +import android.os.PowerManagerInternal; +import android.os.PowerSaveState; +import android.os.UserHandle; +import android.view.Display; +import android.view.InputChannel; + +import com.android.dx.mockito.inline.extended.StaticMockitoSession; +import com.android.server.LocalServices; +import com.android.server.LockGuard; +import com.android.server.Watchdog; +import com.android.server.input.InputManagerService; +import com.android.server.policy.WindowManagerPolicy; + +import org.mockito.invocation.InvocationOnMock; +import org.mockito.quality.Strictness; + +import java.util.concurrent.CountDownLatch; + +/** + * A Test utility class to create a mock {@link WindowManagerService} instance for tests. + */ +class WmServiceUtils { + private static StaticMockitoSession sMockitoSession; + private static WindowManagerService sService; + private static TestWindowManagerPolicy sPolicy; + + static void setUpWindowManagerService() { + sMockitoSession = mockitoSession() + .spyStatic(LockGuard.class) + .spyStatic(Watchdog.class) + .strictness(Strictness.LENIENT) + .startMocking(); + + runWithDexmakerShareClassLoader(WmServiceUtils::setUpTestWindowService); + } + + static void tearDownWindowManagerService() { + waitUntilWindowManagerHandlersIdle(); + removeLocalServices(); + sService = null; + sPolicy = null; + + sMockitoSession.finishMocking(); + } + + private static void setUpTestWindowService() { + doReturn(null).when(() -> LockGuard.installLock(any(), anyInt())); + doReturn(mock(Watchdog.class)).when(Watchdog::getInstance); + + final Context context = getInstrumentation().getTargetContext(); + spyOn(context); + + doReturn(null).when(context) + .registerReceiver(nullable(BroadcastReceiver.class), any(IntentFilter.class)); + doReturn(null).when(context) + .registerReceiverAsUser(any(BroadcastReceiver.class), any(UserHandle.class), + any(IntentFilter.class), nullable(String.class), nullable(Handler.class)); + + final ContentResolver contentResolver = context.getContentResolver(); + spyOn(contentResolver); + doNothing().when(contentResolver) + .registerContentObserver(any(Uri.class), anyBoolean(), any(ContentObserver.class), + anyInt()); + + final AppOpsManager appOpsManager = mock(AppOpsManager.class); + doReturn(appOpsManager).when(context) + .getSystemService(eq(Context.APP_OPS_SERVICE)); + + removeLocalServices(); + + final DisplayManagerInternal dmi = mock(DisplayManagerInternal.class); + LocalServices.addService(DisplayManagerInternal.class, dmi); + + final PowerManagerInternal pmi = mock(PowerManagerInternal.class); + LocalServices.addService(PowerManagerInternal.class, pmi); + final PowerSaveState state = new PowerSaveState.Builder().build(); + doReturn(state).when(pmi).getLowPowerState(anyInt()); + + final ActivityManagerInternal ami = mock(ActivityManagerInternal.class); + LocalServices.addService(ActivityManagerInternal.class, ami); + + final ActivityTaskManagerInternal atmi = mock(ActivityTaskManagerInternal.class); + LocalServices.addService(ActivityTaskManagerInternal.class, atmi); + doAnswer((InvocationOnMock invocationOnMock) -> { + final Runnable runnable = invocationOnMock.getArgument(0); + if (runnable != null) { + runnable.run(); + } + return null; + }).when(atmi).notifyKeyguardFlagsChanged(nullable(Runnable.class), anyInt()); + + final InputManagerService ims = mock(InputManagerService.class); + // InputChannel is final and can't be mocked. + final InputChannel[] input = InputChannel.openInputChannelPair(TAG_WM); + if (input != null && input.length > 1) { + doReturn(input[1]).when(ims).monitorInput(anyString(), anyInt()); + } + + final ActivityTaskManagerService atms = mock(ActivityTaskManagerService.class); + final WindowManagerGlobalLock wmLock = new WindowManagerGlobalLock(); + doReturn(wmLock).when(atms).getGlobalLock(); + + sPolicy = new TestWindowManagerPolicy(WmServiceUtils::getWindowManagerService); + sService = WindowManagerService.main(context, ims, false, false, sPolicy, atms); + + sService.onInitReady(); + + final Display display = sService.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)); + } + + 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; + } + + static void waitUntilWindowManagerHandlersIdle() { + final WindowManagerService wm = getWindowManagerService(); + if (wm == null) { + return; + } + // Removing delayed FORCE_GC message decreases time for waiting idle. + wm.mH.removeMessages(WindowManagerService.H.FORCE_GC); + waitHandlerIdle(wm.mH); + waitHandlerIdle(wm.mAnimationHandler); + waitHandlerIdle(SurfaceAnimationThread.getHandler()); + } + + private static void waitHandlerIdle(Handler handler) { + if (!handler.hasMessagesOrCallbacks()) { + return; + } + final CountDownLatch latch = new CountDownLatch(1); + // Wait for delayed messages are processed. + handler.getLooper().getQueue().addIdleHandler(() -> { + if (handler.hasMessagesOrCallbacks()) { + return true; // keep idle handler. + } + latch.countDown(); + return false; // remove idle handler. + }); + try { + latch.await(); + } catch (InterruptedException e) { + } + } +}