Merge "Use singleton WindowManagerService for testing"
This commit is contained in:
committed by
Android (Google) Code Review
commit
0217050032
@@ -119,6 +119,10 @@ class ActivityTestsBase {
|
||||
@After
|
||||
public void tearDownBase() {
|
||||
mTestInjector.tearDown();
|
||||
if (mService != null) {
|
||||
mService.setWindowManager(null);
|
||||
mService = null;
|
||||
}
|
||||
}
|
||||
|
||||
ActivityTaskManagerService createActivityTaskManagerService() {
|
||||
@@ -638,7 +642,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);
|
||||
|
||||
@@ -650,6 +660,7 @@ class ActivityTestsBase {
|
||||
return null;
|
||||
}).when(service).inSurfaceTransaction(any());
|
||||
|
||||
sMockWindowManagerService = service;
|
||||
return service;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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<View> mWindows = new ArrayList<>();
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
* <p>
|
||||
* Usage:
|
||||
* <pre>
|
||||
* {@literal @}Rule
|
||||
* public final WindowManagerServiceRule mWmRule = new WindowManagerServiceRule();
|
||||
* </pre>
|
||||
*/
|
||||
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<WeakReference<Transaction>> mSurfaceTransactions = new ArrayList<>();
|
||||
// Record all {@link SurfaceControl} created while testing and releases native resources when
|
||||
// test finishes.
|
||||
private final List<WeakReference<SurfaceControl>> 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.<Runnable>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<SurfaceControl> 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<Transaction> reference : mSurfaceTransactions) {
|
||||
final Transaction transaction = reference.get();
|
||||
if (transaction != null) {
|
||||
reference.clear();
|
||||
transaction.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void destroyAllSurfaceControls() {
|
||||
for (final WeakReference<SurfaceControl> reference : mSurfaceControls) {
|
||||
final SurfaceControl control = reference.get();
|
||||
if (control != null) {
|
||||
reference.clear();
|
||||
control.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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(
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user