diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index 448188583b1ab..4c81f9cd38081 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -344,6 +344,16 @@ public final class DisplayManager { */ public static final int VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP = 1 << 11; + /** + * Virtual display flags: Indicates that the virtual display should always be unlocked and not + * have keyguard displayed on it. Only valid for virtual displays that aren't in the default + * display group. + * + * @see #createVirtualDisplay + * @see #VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP + * @hide + */ + public static final int VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED = 1 << 12; /** @hide */ @IntDef(prefix = {"MATCH_CONTENT_FRAMERATE_"}, value = { @@ -1363,5 +1373,13 @@ public final class DisplayManager { * @hide */ String KEY_HIGH_REFRESH_RATE_BLACKLIST = "high_refresh_rate_blacklist"; + + /** + * Whether to allow the creation of always unlocked virtual displays by apps having the + * required permissions. + * @hide + */ + String KEY_ALLOW_ALWAYS_UNLOCKED_VIRTUAL_DISPLAYS = + "allow_always_unlocked_virtual_displays"; } } diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 8259a9d981255..3cc51c7e8b51d 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -298,6 +298,15 @@ public final class Display { */ public static final int FLAG_OWN_DISPLAY_GROUP = 1 << 8; + /** + * Flag: Indicates that the display should always be unlocked. Only valid on virtual displays + * that aren't in the default display group. + * + * @hide + * @see #getFlags() + */ + public static final int FLAG_ALWAYS_UNLOCKED = 1 << 9; + /** * Display flag: Indicates that the contents of the display should not be scaled * to fit the physical screen dimensions. Used for development only to emulate diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java index 6572510465513..b8614ccde6fd1 100644 --- a/core/java/android/view/DisplayInfo.java +++ b/core/java/android/view/DisplayInfo.java @@ -863,6 +863,9 @@ public final class DisplayInfo implements Parcelable { if ((flags & Display.FLAG_OWN_DISPLAY_GROUP) != 0) { result.append(", FLAG_OWN_DISPLAY_GROUP"); } + if ((flags & Display.FLAG_ALWAYS_UNLOCKED) != 0) { + result.append(", FLAG_ALWAYS_UNLOCKED"); + } return result.toString(); } } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index a49e3b502c965..aada7eb2df8f4 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -5882,6 +5882,10 @@ + + + diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java index 40cee66a67914..fd4cd8e6ec88e 100644 --- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java +++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java @@ -141,6 +141,15 @@ final class DisplayDeviceInfo { */ public static final int FLAG_OWN_DISPLAY_GROUP = 1 << 14; + /** + * Flag: Indicates that the display should always be unlocked. Only valid on virtual displays + * that aren't in the default display group. + * @see #FLAG_OWN_DISPLAY_GROUP + * @hide + */ + public static final int FLAG_ALWAYS_UNLOCKED = 1 << 15; + + /** * Touch attachment: Display does not receive touch. */ diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index a36a1a9183fb3..77ab81301059e 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -16,11 +16,13 @@ package com.android.server.display; +import static android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY; import static android.Manifest.permission.ADD_TRUSTED_DISPLAY; import static android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT; import static android.Manifest.permission.CAPTURE_VIDEO_OUTPUT; import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; import static android.hardware.display.DisplayManager.EventsMask; +import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY; @@ -94,6 +96,8 @@ import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; +import android.provider.DeviceConfig; +import android.provider.DeviceConfigInterface; import android.provider.Settings; import android.sysprop.DisplayProperties; import android.text.TextUtils; @@ -393,6 +397,7 @@ public final class DisplayManagerService extends SystemService { private final SparseArray mDisplayAccessUIDs = new SparseArray<>(); private final Injector mInjector; + private final DeviceConfigInterface mDeviceConfig; // The minimum brightness curve, which guarantess that any brightness curve that dips below it // is rejected by the system. @@ -443,6 +448,7 @@ public final class DisplayManagerService extends SystemService { DisplayManagerService(Context context, Injector injector) { super(context); mInjector = injector; + mDeviceConfig = mInjector.getDeviceConfig(); mContext = context; mHandler = new DisplayManagerHandler(DisplayThread.get().getLooper()); mUiHandler = UiThread.getHandler(); @@ -1254,6 +1260,31 @@ public final class DisplayManagerService extends SystemService { } } + if ((flags & VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED) != 0) { + if (callingUid != Process.SYSTEM_UID + && !checkCallingPermission(ADD_ALWAYS_UNLOCKED_DISPLAY, + "createVirtualDisplay()")) { + throw new SecurityException( + "Requires ADD_ALWAYS_UNLOCKED_DISPLAY permission to " + + "create an always unlocked virtual display."); + } + boolean allowedByDeviceConfig = false; + final long token = Binder.clearCallingIdentity(); + try { + allowedByDeviceConfig = mDeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_DISPLAY_MANAGER, + DisplayManager.DeviceConfig.KEY_ALLOW_ALWAYS_UNLOCKED_VIRTUAL_DISPLAYS, + false); + } finally { + Binder.restoreCallingIdentity(token); + } + if (!allowedByDeviceConfig) { + Slog.w(TAG, "Ignoring flag VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED " + + "because it is not allowed by DeviceConfig"); + flags &= ~VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED; + } + } + if ((flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) == 0) { flags &= ~VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS; } @@ -2366,6 +2397,11 @@ public final class DisplayManagerService extends SystemService { return DisplayProperties .debug_allow_non_native_refresh_rate_override().orElse(false); } + + @NonNull + public DeviceConfigInterface getDeviceConfig() { + return DeviceConfigInterface.REAL; + } } @VisibleForTesting diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java index 48eea8938bb8e..4d1367a3d0834 100644 --- a/services/core/java/com/android/server/display/LogicalDisplay.java +++ b/services/core/java/com/android/server/display/LogicalDisplay.java @@ -378,6 +378,9 @@ final class LogicalDisplay { if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP) != 0) { mBaseDisplayInfo.flags |= Display.FLAG_OWN_DISPLAY_GROUP; } + if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_ALWAYS_UNLOCKED) != 0) { + mBaseDisplayInfo.flags |= Display.FLAG_ALWAYS_UNLOCKED; + } Rect maskingInsets = getMaskingInsets(deviceInfo); int maskedWidth = deviceInfo.width - maskingInsets.left - maskingInsets.right; int maskedHeight = deviceInfo.height - maskingInsets.top - maskingInsets.bottom; diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java index a59219265e2cd..797c3fb443383 100644 --- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java +++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java @@ -16,6 +16,7 @@ package com.android.server.display; +import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL; @@ -28,6 +29,7 @@ import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SHOUL import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED; +import static com.android.server.display.DisplayDeviceInfo.FLAG_ALWAYS_UNLOCKED; import static com.android.server.display.DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP; import static com.android.server.display.DisplayDeviceInfo.FLAG_TRUSTED; @@ -453,6 +455,10 @@ public class VirtualDisplayAdapter extends DisplayAdapter { if ((mFlags & VIRTUAL_DISPLAY_FLAG_TRUSTED) != 0) { mInfo.flags |= FLAG_TRUSTED; } + if ((mFlags & VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED) != 0 + && (mInfo.flags & DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP) != 0) { + mInfo.flags |= FLAG_ALWAYS_UNLOCKED; + } mInfo.type = Display.TYPE_VIRTUAL; mInfo.touch = ((mFlags & VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH) == 0) ? diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 68eff9a5450e8..9d8f1fc5f1bf4 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -5927,6 +5927,13 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp .getKeyguardController().isKeyguardGoingAway(mDisplayId); } + /** + * @return whether keyguard should always be unlocked for this display + */ + boolean isKeyguardAlwaysUnlocked() { + return (mDisplayInfo.flags & Display.FLAG_ALWAYS_UNLOCKED) != 0; + } + /** * @return whether AOD is showing on this display */ diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java index a843909dd26ca..cabe414395269 100644 --- a/services/core/java/com/android/server/wm/KeyguardController.java +++ b/services/core/java/com/android/server/wm/KeyguardController.java @@ -157,6 +157,11 @@ class KeyguardController { * Update the Keyguard showing state. */ void setKeyguardShown(int displayId, boolean keyguardShowing, boolean aodShowing) { + if (mRootWindowContainer.getDisplayContent(displayId).isKeyguardAlwaysUnlocked()) { + Slog.i(TAG, "setKeyguardShown ignoring always unlocked display " + displayId); + return; + } + final KeyguardDisplayState state = getDisplayState(displayId); final boolean aodChanged = aodShowing != state.mAodShowing; // If keyguard is going away, but SystemUI aborted the transition, need to reset state. diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java index fcfe27397df6c..68e90fbadd0c3 100644 --- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java @@ -16,20 +16,27 @@ package com.android.server.display; +import static android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY; +import static android.Manifest.permission.ADD_TRUSTED_DISPLAY; + import static com.android.server.display.VirtualDisplayAdapter.UNIQUE_ID_PREFIX; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.PropertyInvalidatedCache; import android.compat.testing.PlatformCompatChangeRule; import android.content.Context; +import android.content.ContextWrapper; +import android.content.pm.PackageManager; import android.graphics.Insets; import android.graphics.Rect; import android.hardware.display.BrightnessConfiguration; @@ -48,6 +55,8 @@ import android.os.IBinder; import android.os.MessageQueue; import android.os.Process; import android.platform.test.annotations.Presubmit; +import android.provider.DeviceConfig; +import android.provider.DeviceConfigInterface; import android.view.Display; import android.view.DisplayCutout; import android.view.DisplayEventReceiver; @@ -55,7 +64,9 @@ import android.view.DisplayInfo; import android.view.Surface; import android.view.SurfaceControl; +import androidx.annotation.NonNull; import androidx.test.InstrumentationRegistry; +import androidx.test.core.app.ApplicationProvider; import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -65,6 +76,7 @@ import com.android.server.SystemService; import com.android.server.display.DisplayManagerService.SyncRoot; import com.android.server.lights.LightsManager; import com.android.server.sensors.SensorManagerInternal; +import com.android.server.testutils.FakeDeviceConfigInterface; import com.android.server.wm.WindowManagerInternal; import com.google.common.collect.ImmutableMap; @@ -105,6 +117,7 @@ public class DisplayManagerServiceTest { public TestRule compatChangeRule = new PlatformCompatChangeRule(); private Context mContext; + private FakeDeviceConfigInterface mDeviceConfig; private final DisplayManagerService.Injector mShortMockedInjector = new DisplayManagerService.Injector() { @@ -127,6 +140,12 @@ public class DisplayManagerServiceTest { return new VirtualDisplayAdapter(syncRoot, context, handler, displayAdapterListener, (String name, boolean secure) -> mMockDisplayToken); } + + @NonNull + @Override + public DeviceConfigInterface getDeviceConfig() { + return mDeviceConfig; + } } private final DisplayManagerService.Injector mBasicInjector = new BasicInjector(); @@ -169,7 +188,8 @@ public class DisplayManagerServiceTest { LocalServices.removeServiceForTest(SensorManagerInternal.class); LocalServices.addService(SensorManagerInternal.class, mMockSensorManagerInternal); - mContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + mContext = spy(new ContextWrapper(ApplicationProvider.getApplicationContext())); + mDeviceConfig = new FakeDeviceConfigInterface(); // Disable binder caches in this process. PropertyInvalidatedCache.disableForTestMode(); @@ -618,6 +638,25 @@ public class DisplayManagerServiceTest { assertEquals(displayManager.getVirtualDisplaySurfaceInternal(mMockAppToken), surface); } + /** + * Tests that specifying the VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED flag is processed correctly + * when it is allowed by DeviceConfig. + */ + @Test + public void testCreateVirtualDisplay_alwaysUnlockedAllowed() { + testCreateVirtualDisplay_alwaysUnlocked(/*deviceConfigAllows*/ true, /*flagExpected*/ true); + } + + /** + * Tests that specifying the VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED flag when DeviceConfig does + * not allow it results in the flag being stripped from the final flags. + */ + @Test + public void testCreateVirtualDisplay_alwaysUnlockedDisallowed() { + testCreateVirtualDisplay_alwaysUnlocked( + /*deviceConfigAllows*/ false, /*flagExpected*/ false); + } + /** * Tests that there is a display change notification if the frame rate override * list is updated. @@ -1042,6 +1081,45 @@ public class DisplayManagerServiceTest { assertEquals(expectedRefreshRate, displayInfo.getRefreshRate(), 0.01f); } + private void testCreateVirtualDisplay_alwaysUnlocked(boolean deviceConfigAllows, + boolean flagExpected) { + mDeviceConfig.setProperty(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, + DisplayManager.DeviceConfig.KEY_ALLOW_ALWAYS_UNLOCKED_VIRTUAL_DISPLAYS, + deviceConfigAllows ? "true" : "false", /*makeDefault*/ false); + + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mBasicInjector); + registerDefaultDisplays(displayManager); + String uniqueId = "uniqueId --- ALWAYS_UNLOCKED"; + int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP + | DisplayManager.VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED; + + DisplayManagerService.BinderService bs = displayManager.new BinderService(); + when(mMockAppToken.asBinder()).thenReturn(mMockAppToken); + + when(mContext.checkCallingPermission(ADD_ALWAYS_UNLOCKED_DISPLAY)).thenReturn( + PackageManager.PERMISSION_GRANTED); + when(mContext.checkCallingPermission(ADD_TRUSTED_DISPLAY)).thenReturn( + PackageManager.PERMISSION_GRANTED); + + final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder( + VIRTUAL_DISPLAY_NAME, 600, 800, 320); + builder.setFlags(flags); + builder.setUniqueId(uniqueId); + + int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */, + null /* projection */, PACKAGE_NAME); + displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class)); + displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */); + DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId); + assertNotNull(ddi); + if (flagExpected) { + assertNotEquals(ddi.flags & DisplayDeviceInfo.FLAG_ALWAYS_UNLOCKED, 0); + } else { + assertEquals(ddi.flags & DisplayDeviceInfo.FLAG_ALWAYS_UNLOCKED, 0); + } + } + private int getDisplayIdForDisplayDevice( DisplayManagerService displayManager, DisplayManagerService.BinderService displayManagerBinderService, diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java index afc2b8748abb6..e0072b441577a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java @@ -35,6 +35,7 @@ import static com.android.server.wm.ActivityRecord.State.STOPPING; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -63,6 +64,8 @@ import android.os.LocaleList; import android.os.PowerManager; import android.os.RemoteException; import android.platform.test.annotations.Presubmit; +import android.view.Display; +import android.view.DisplayInfo; import android.view.IDisplayWindowListener; import androidx.test.filters.MediumTest; @@ -220,6 +223,66 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase { assertEquals(1, removed.size()); } + @Test + public void testSetLockScreenShownWithVirtualDisplay() { + DisplayInfo displayInfo = new DisplayInfo(); + displayInfo.copyFrom(mDisplayInfo); + displayInfo.type = Display.TYPE_VIRTUAL; + DisplayContent virtualDisplay = createNewDisplay(displayInfo); + + // Make sure we're starting out with 2 unlocked displays + assertEquals(2, mRootWindowContainer.getChildCount()); + mRootWindowContainer.forAllDisplays(displayContent -> { + assertFalse(displayContent.isKeyguardLocked()); + assertFalse(displayContent.isAodShowing()); + }); + + // Check that setLockScreenShown locks both displays + mAtm.setLockScreenShown(true, true); + mRootWindowContainer.forAllDisplays(displayContent -> { + assertTrue(displayContent.isKeyguardLocked()); + assertTrue(displayContent.isAodShowing()); + }); + + // Check setLockScreenShown unlocking both displays + mAtm.setLockScreenShown(false, false); + mRootWindowContainer.forAllDisplays(displayContent -> { + assertFalse(displayContent.isKeyguardLocked()); + assertFalse(displayContent.isAodShowing()); + }); + } + + @Test + public void testSetLockScreenShownWithAlwaysUnlockedVirtualDisplay() { + assertEquals(Display.DEFAULT_DISPLAY, mRootWindowContainer.getChildAt(0).getDisplayId()); + + DisplayInfo displayInfo = new DisplayInfo(); + displayInfo.copyFrom(mDisplayInfo); + displayInfo.type = Display.TYPE_VIRTUAL; + displayInfo.displayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1; + displayInfo.flags = Display.FLAG_OWN_DISPLAY_GROUP | Display.FLAG_ALWAYS_UNLOCKED; + DisplayContent newDisplay = createNewDisplay(displayInfo); + + // Make sure we're starting out with 2 unlocked displays + assertEquals(2, mRootWindowContainer.getChildCount()); + mRootWindowContainer.forAllDisplays(displayContent -> { + assertFalse(displayContent.isKeyguardLocked()); + assertFalse(displayContent.isAodShowing()); + }); + + // setLockScreenShown should only lock the default display, not the virtual one + mAtm.setLockScreenShown(true, true); + + assertTrue(mDefaultDisplay.isKeyguardLocked()); + assertTrue(mDefaultDisplay.isAodShowing()); + + DisplayContent virtualDisplay = mRootWindowContainer.getDisplayContent( + newDisplay.getDisplayId()); + assertNotEquals(Display.DEFAULT_DISPLAY, virtualDisplay.getDisplayId()); + assertFalse(virtualDisplay.isKeyguardLocked()); + assertFalse(virtualDisplay.isAodShowing()); + } + /* a test to verify b/144045134 - ignore PIP mode request for destroyed activity. mocks r.getParent() to return null to cause NPE inside enterPipRunnable#run() in diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java index db60b98a7785e..9a33e23fcb30b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java +++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java @@ -266,6 +266,7 @@ public class SystemServicesTestRule implements TestRule { doNothing().when(amInternal).updateOomLevelsForDisplay(anyInt()); doNothing().when(amInternal).broadcastGlobalConfigurationChanged(anyInt(), anyBoolean()); doNothing().when(amInternal).cleanUpServices(anyInt(), any(), any()); + doNothing().when(amInternal).reportCurKeyguardUsageEvent(anyBoolean()); doReturn(UserHandle.USER_SYSTEM).when(amInternal).getCurrentUserId(); doReturn(TEST_USER_PROFILE_IDS).when(amInternal).getCurrentProfileIds(); doReturn(true).when(amInternal).isUserRunning(anyInt(), anyInt());