diff --git a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java index bbec091b9924e..41c0caaea06e6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java @@ -453,6 +453,78 @@ public class ContentRecorderTests extends WindowTestsBase { displayAreaBounds.width(), displayAreaBounds.height()); } + @Test + public void testDisplayContentUpdatesRecording_withoutSurface() { + // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to + // mirror. + setUpDefaultTaskDisplayAreaWindowToken(); + + // WHEN getting the DisplayContent for the new virtual display without providing a valid + // size from getDisplaySurfaceDefaultSize, i.e. the case of null surface. + final DisplayContent virtualDisplay = + mRootWindowContainer.getDisplayContent(mDisplaySession.getVirtualDisplayId()); + doReturn(null).when(mWm.mDisplayManagerInternal).getDisplaySurfaceDefaultSize(anyInt()); + mWm.mContentRecordingController.setContentRecordingSessionLocked(mDisplaySession, mWm); + virtualDisplay.updateRecording(); + + // THEN mirroring is not started, since a null surface indicates the VirtualDisplay is off. + assertThat(virtualDisplay.isCurrentlyRecording()).isFalse(); + } + + @Test + public void testDisplayContentUpdatesRecording_withSurface() { + // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to + // mirror. + setUpDefaultTaskDisplayAreaWindowToken(); + + // WHEN getting the DisplayContent for the virtual display with a valid size from + // getDisplaySurfaceDefaultSize (done by surfaceControlMirrors in setUp). + final DisplayContent virtualDisplay = + mRootWindowContainer.getDisplayContent(mDisplaySession.getVirtualDisplayId()); + mWm.mContentRecordingController.setContentRecordingSessionLocked(mDisplaySession, mWm); + virtualDisplay.updateRecording(); + + // THEN mirroring is initiated for the default display's DisplayArea. + assertThat(virtualDisplay.isCurrentlyRecording()).isTrue(); + } + + @Test + public void testDisplayContentUpdatesRecording_displayMirroring() { + // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to + // mirror. + setUpDefaultTaskDisplayAreaWindowToken(); + + // GIVEN SurfaceControl can successfully mirror the provided surface. + surfaceControlMirrors(sSurfaceSize); + // Initially disable getDisplayIdToMirror since the DMS may create the DC outside the direct + // call in the test. We need to spy on the DC before updateRecording is called or we can't + // verify setDisplayMirroring is called + doReturn(INVALID_DISPLAY).when(mWm.mDisplayManagerInternal).getDisplayIdToMirror(anyInt()); + + // WHEN getting the DisplayContent for the new virtual display. + final DisplayContent virtualDisplay = + mRootWindowContainer.getDisplayContent(mDisplaySession.getVirtualDisplayId()); + // Return the default display as the value to mirror to ensure the VD with flag mirroring + // creates a ContentRecordingSession automatically. + doReturn(DEFAULT_DISPLAY).when(mWm.mDisplayManagerInternal).getDisplayIdToMirror(anyInt()); + virtualDisplay.updateRecording(); + + // THEN mirroring is initiated for the default display's DisplayArea. + verify(virtualDisplay).setDisplayMirroring(); + assertThat(virtualDisplay.isCurrentlyRecording()).isTrue(); + } + + /** + * Creates a WindowToken associated with the default task DisplayArea, in order for that + * DisplayArea to be mirrored. + */ + private void setUpDefaultTaskDisplayAreaWindowToken() { + // GIVEN the default task display area is represented by the WindowToken. + spyOn(mWm.mWindowContextListenerController); + doReturn(mDefaultDisplay.getDefaultTaskDisplayArea()).when( + mWm.mWindowContextListenerController).getContainer(any()); + } + /** * Creates a {@link android.window.WindowContainerToken} associated with a task, in order for * that task to be recorded. diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index bdd178b0b3178..d015ca302e272 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -27,12 +27,10 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; -import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR; import static android.os.Build.VERSION_CODES.P; import static android.os.Build.VERSION_CODES.Q; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.FLAG_PRIVATE; -import static android.view.Display.INVALID_DISPLAY; import static android.view.DisplayCutout.BOUNDS_POSITION_TOP; import static android.view.DisplayCutout.fromBoundingRect; import static android.view.Surface.ROTATION_0; @@ -112,11 +110,9 @@ import android.app.ActivityTaskManager; import android.app.WindowConfiguration; import android.content.res.Configuration; import android.graphics.Insets; -import android.graphics.Point; import android.graphics.Rect; import android.graphics.Region; import android.hardware.HardwareBuffer; -import android.hardware.display.VirtualDisplay; import android.metrics.LogMaker; import android.os.Binder; import android.os.RemoteException; @@ -124,7 +120,6 @@ import android.os.SystemClock; import android.platform.test.annotations.Presubmit; import android.util.ArraySet; import android.util.DisplayMetrics; -import android.view.ContentRecordingSession; import android.view.Display; import android.view.DisplayCutout; import android.view.DisplayInfo; @@ -2654,138 +2649,6 @@ public class DisplayContentTests extends WindowTestsBase { assertNotEquals(imeMenuDialog, mDisplayContent.findFocusedWindow()); } - @Test - public void testVirtualDisplayContent_withoutSurface() { - // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to - // mirror. - setUpDefaultTaskDisplayAreaWindowToken(); - - // GIVEN SurfaceControl does not mirror a null surface. - Point surfaceSize = new Point( - mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().width(), - mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().height()); - - // GIVEN a new VirtualDisplay with an associated surface. - final VirtualDisplay display = createVirtualDisplay(surfaceSize, null /* surface */); - final int displayId = display.getDisplay().getDisplayId(); - mWm.mRoot.onDisplayAdded(displayId); - - // WHEN getting the DisplayContent for the new virtual display. - DisplayContent actualDC = mWm.mRoot.getDisplayContent(displayId); - ContentRecordingSession session = ContentRecordingSession.createDisplaySession( - DEFAULT_DISPLAY); - session.setVirtualDisplayId(displayId); - mWm.mContentRecordingController.setContentRecordingSessionLocked(session, mWm); - actualDC.updateRecording(); - - // THEN mirroring is not started, since a null surface indicates the VirtualDisplay is off. - assertThat(actualDC.isCurrentlyRecording()).isFalse(); - - display.release(); - } - - @Test - public void testVirtualDisplayContent_withSurface() { - // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to - // mirror. - setUpDefaultTaskDisplayAreaWindowToken(); - - // GIVEN SurfaceControl can successfully mirror the provided surface. - Point surfaceSize = new Point( - mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().width(), - mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().height()); - surfaceControlMirrors(surfaceSize); - - // GIVEN a new VirtualDisplay with an associated surface. - final VirtualDisplay display = createVirtualDisplay(surfaceSize, new Surface()); - final int displayId = display.getDisplay().getDisplayId(); - - // GIVEN a session for this display. - ContentRecordingSession session = ContentRecordingSession.createDisplaySession( - DEFAULT_DISPLAY); - session.setVirtualDisplayId(displayId); - mWm.mContentRecordingController.setContentRecordingSessionLocked(session, mWm); - mWm.mRoot.onDisplayAdded(displayId); - - // WHEN getting the DisplayContent for the new virtual display. - DisplayContent actualDC = mWm.mRoot.getDisplayContent(displayId); - actualDC.updateRecording(); - - // THEN mirroring is initiated for the default display's DisplayArea. - assertThat(actualDC.isCurrentlyRecording()).isTrue(); - - display.release(); - } - - @Test - public void testVirtualDisplayContent_displayMirroring() { - // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to - // mirror. - setUpDefaultTaskDisplayAreaWindowToken(); - - // GIVEN SurfaceControl can successfully mirror the provided surface. - Point surfaceSize = new Point( - mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().width(), - mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().height()); - surfaceControlMirrors(surfaceSize); - // Initially disable getDisplayIdToMirror since the DMS may create the DC outside the direct - // call in the test. We need to spy on the DC before updateRecording is called or we can't - // verify setDisplayMirroring is called - doReturn(INVALID_DISPLAY).when(mWm.mDisplayManagerInternal).getDisplayIdToMirror(anyInt()); - - // GIVEN a new VirtualDisplay with an associated surface. - final VirtualDisplay display = createVirtualDisplay(surfaceSize, new Surface()); - final int displayId = display.getDisplay().getDisplayId(); - - // GIVEN a session for this display. - mWm.mRoot.onDisplayAdded(displayId); - - // WHEN getting the DisplayContent for the new virtual display. - DisplayContent actualDC = mWm.mRoot.getDisplayContent(displayId); - spyOn(actualDC); - // Return the default display as the value to mirror to ensure the VD with flag mirroring - // creates a ContentRecordingSession automatically. - doReturn(DEFAULT_DISPLAY).when(mWm.mDisplayManagerInternal).getDisplayIdToMirror(anyInt()); - actualDC.updateRecording(); - - // THEN mirroring is initiated for the default display's DisplayArea. - verify(actualDC).setDisplayMirroring(); - assertThat(actualDC.isCurrentlyRecording()).isTrue(); - display.release(); - } - - /** - * Creates a WindowToken associated with the default task DisplayArea, in order for that - * DisplayArea to be mirrored. - */ - private void setUpDefaultTaskDisplayAreaWindowToken() { - // GIVEN the default task display area is represented by the WindowToken. - spyOn(mWm.mWindowContextListenerController); - doReturn(mDefaultDisplay.getDefaultTaskDisplayArea()).when( - mWm.mWindowContextListenerController).getContainer(any()); - } - - /** - * SurfaceControl successfully creates a mirrored surface of the given size. - */ - private SurfaceControl surfaceControlMirrors(Point surfaceSize) { - // Do not set the parent, since the mirrored surface is the root of a new surface hierarchy. - SurfaceControl mirroredSurface = new SurfaceControl.Builder() - .setName("mirroredSurface") - .setBufferSize(surfaceSize.x, surfaceSize.y) - .setCallsite("mirrorSurface") - .build(); - doReturn(mirroredSurface).when(() -> SurfaceControl.mirrorSurface(any())); - doReturn(surfaceSize).when(mWm.mDisplayManagerInternal).getDisplaySurfaceDefaultSize( - anyInt()); - return mirroredSurface; - } - - private VirtualDisplay createVirtualDisplay(Point size, Surface surface) { - return mWm.mDisplayManager.createVirtualDisplay("VirtualDisplay", size.x, size.y, - DisplayMetrics.DENSITY_140, surface, VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR); - } - @Test public void testKeepClearAreasMultipleWindows() { final WindowState w1 = createWindow(null, TYPE_NAVIGATION_BAR, mDisplayContent, "w1"); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java index d502cd1c93cbe..325176fbe7a86 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java @@ -21,9 +21,6 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; -import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_FOCUS; -import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC; -import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.FLAG_OWN_FOCUS; import static android.view.Display.INVALID_DISPLAY; @@ -63,6 +60,8 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.description; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -71,9 +70,7 @@ import static org.mockito.Mockito.when; import android.app.ActivityThread; import android.app.IApplicationThread; import android.content.pm.ActivityInfo; -import android.graphics.Point; import android.graphics.Rect; -import android.hardware.display.VirtualDisplay; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; @@ -82,7 +79,6 @@ import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; import android.platform.test.annotations.Presubmit; -import android.util.DisplayMetrics; import android.util.MergedConfiguration; import android.view.ContentRecordingSession; import android.view.IWindow; @@ -90,7 +86,6 @@ import android.view.IWindowSessionCallback; import android.view.InputChannel; import android.view.InsetsSourceControl; import android.view.InsetsState; -import android.view.Surface; import android.view.SurfaceControl; import android.view.View; import android.view.WindowInsets; @@ -575,13 +570,14 @@ public class WindowManagerServiceTests extends WindowTestsBase { mWm.mPerDisplayFocusEnabled = false; // Create one extra display - final VirtualDisplay virtualDisplay = createVirtualDisplay(/* ownFocus= */ false); - final VirtualDisplay virtualDisplayOwnTouchMode = - createVirtualDisplay(/* ownFocus= */ true); + final DisplayContent display = createMockSimulatedDisplay(); + display.getDisplayInfo().flags &= ~FLAG_OWN_FOCUS; + final DisplayContent displayOwnTouchMode = createMockSimulatedDisplay(); + displayOwnTouchMode.getDisplayInfo().flags |= FLAG_OWN_FOCUS; final int numberOfDisplays = mWm.mRoot.mChildren.size(); assertThat(numberOfDisplays).isAtLeast(3); final int numberOfGlobalTouchModeDisplays = (int) mWm.mRoot.mChildren.stream() - .filter(d -> (d.getDisplay().getFlags() & FLAG_OWN_FOCUS) == 0) + .filter(d -> (d.getDisplayInfo().flags & FLAG_OWN_FOCUS) == 0) .count(); assertThat(numberOfGlobalTouchModeDisplays).isAtLeast(2); @@ -601,12 +597,13 @@ public class WindowManagerServiceTests extends WindowTestsBase { } @Test - public void testSetInTouchMode_multiDisplay_perDisplayFocus_singleDisplayTouchModeUpdate() { + public void testSetInTouchMode_multiDisplay_singleDisplayTouchModeUpdate() { // Enable global touch mode mWm.mPerDisplayFocusEnabled = true; // Create one extra display - final VirtualDisplay virtualDisplay = createVirtualDisplay(/* ownFocus= */ false); + final DisplayContent virtualDisplay = createMockSimulatedDisplay(); + virtualDisplay.getDisplayInfo().flags &= ~FLAG_OWN_FOCUS; final int numberOfDisplays = mWm.mRoot.mChildren.size(); assertThat(numberOfDisplays).isAtLeast(2); @@ -618,99 +615,64 @@ public class WindowManagerServiceTests extends WindowTestsBase { when(mWm.mAtmService.instrumentationSourceHasPermission(callingPid, android.Manifest.permission.MODIFY_TOUCH_MODE_STATE)).thenReturn(true); - mWm.setInTouchMode(!currentTouchMode, virtualDisplay.getDisplay().getDisplayId()); + mWm.setInTouchMode(!currentTouchMode, virtualDisplay.mDisplayId); // Ensure that new display touch mode state has changed. verify(mWm.mInputManager).setInTouchMode( !currentTouchMode, callingPid, callingUid, /* hasPermission= */ true, - virtualDisplay.getDisplay().getDisplayId()); - } + virtualDisplay.mDisplayId); - @Test - public void testSetInTouchMode_multiDisplay_ownTouchMode_singleDisplayTouchModeUpdate() { - // Disable global touch mode + // Disable global touch mode and make the virtual display own focus. mWm.mPerDisplayFocusEnabled = false; - - // Create one extra display - final VirtualDisplay virtualDisplay = createVirtualDisplay(/* ownFocus= */ true); - final int numberOfDisplays = mWm.mRoot.mChildren.size(); - assertThat(numberOfDisplays).isAtLeast(2); - - // Get current touch mode state and setup WMS to run setInTouchMode - boolean currentTouchMode = mWm.isInTouchMode(DEFAULT_DISPLAY); - int callingPid = Binder.getCallingPid(); - int callingUid = Binder.getCallingUid(); - doReturn(false).when(mWm).checkCallingPermission(anyString(), anyString(), anyBoolean()); - when(mWm.mAtmService.instrumentationSourceHasPermission(callingPid, - android.Manifest.permission.MODIFY_TOUCH_MODE_STATE)).thenReturn(true); - - mWm.setInTouchMode(!currentTouchMode, virtualDisplay.getDisplay().getDisplayId()); + virtualDisplay.getDisplayInfo().flags |= FLAG_OWN_FOCUS; + clearInvocations(mWm.mInputManager); + mWm.setInTouchMode(!currentTouchMode, virtualDisplay.mDisplayId); // Ensure that new display touch mode state has changed. verify(mWm.mInputManager).setInTouchMode( !currentTouchMode, callingPid, callingUid, /* hasPermission= */ true, - virtualDisplay.getDisplay().getDisplayId()); + virtualDisplay.mDisplayId); } @Test - public void testSetInTouchModeOnAllDisplays_perDisplayFocusDisabled() { - testSetInTouchModeOnAllDisplays(/* perDisplayFocusEnabled= */ false); - } - - @Test - public void testSetInTouchModeOnAllDisplays_perDisplayFocusEnabled() { - testSetInTouchModeOnAllDisplays(/* perDisplayFocusEnabled= */ true); - } - - private void testSetInTouchModeOnAllDisplays(boolean perDisplayFocusEnabled) { - // Set global touch mode with the value passed as argument. - mWm.mPerDisplayFocusEnabled = perDisplayFocusEnabled; - + public void testSetInTouchModeOnAllDisplays() { // Create a couple of extra displays. // setInTouchModeOnAllDisplays should ignore the ownFocus setting. - final VirtualDisplay virtualDisplay = createVirtualDisplay(/* ownFocus= */ false); - final VirtualDisplay virtualDisplayOwnFocus = createVirtualDisplay(/* ownFocus= */ true); + final DisplayContent display = createMockSimulatedDisplay(); + display.getDisplayInfo().flags &= ~FLAG_OWN_FOCUS; + final DisplayContent displayOwnTouchMode = createMockSimulatedDisplay(); + displayOwnTouchMode.getDisplayInfo().flags |= FLAG_OWN_FOCUS; int callingPid = Binder.getCallingPid(); int callingUid = Binder.getCallingUid(); + doReturn(true).when(mWm.mInputManager).setInTouchMode(anyBoolean(), anyInt(), + anyInt(), anyBoolean(), anyInt()); doReturn(false).when(mWm).checkCallingPermission(anyString(), anyString(), anyBoolean()); when(mWm.mAtmService.instrumentationSourceHasPermission(callingPid, android.Manifest.permission.MODIFY_TOUCH_MODE_STATE)).thenReturn(true); - for (boolean inTouchMode : new boolean[]{true, false}) { - mWm.setInTouchModeOnAllDisplays(inTouchMode); - for (int i = 0; i < mWm.mRoot.mChildren.size(); ++i) { - DisplayContent dc = mWm.mRoot.mChildren.get(i); - // All displays that are not already in the desired touch mode are requested to - // change their touch mode. - if (dc.isInTouchMode() != inTouchMode) { - verify(mWm.mInputManager).setInTouchMode( - true, callingPid, callingUid, /* hasPermission= */ true, - dc.getDisplay().getDisplayId()); + final Runnable verification = () -> { + for (boolean inTouchMode : new boolean[] { true, false }) { + mWm.setInTouchModeOnAllDisplays(inTouchMode); + for (int i = 0; i < mRootWindowContainer.getChildCount(); ++i) { + final DisplayContent dc = mRootWindowContainer.getChildAt(i); + // All displays that are not already in the desired touch mode are requested to + // change their touch mode. + if (dc.isInTouchMode() != inTouchMode) { + verify(mWm.mInputManager, description("perDisplayFocusEnabled=" + + mWm.mPerDisplayFocusEnabled)).setInTouchMode(true, + callingPid, callingUid, /* hasPermission= */ true, dc.mDisplayId); + } } } - } - } + }; - private VirtualDisplay createVirtualDisplay(boolean ownFocus) { - // Create virtual display - Point surfaceSize = new Point( - mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().width(), - mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().height()); - int flags = VIRTUAL_DISPLAY_FLAG_PUBLIC; - if (ownFocus) { - flags |= VIRTUAL_DISPLAY_FLAG_OWN_FOCUS | VIRTUAL_DISPLAY_FLAG_TRUSTED; - } - VirtualDisplay virtualDisplay = mWm.mDisplayManager.createVirtualDisplay("VirtualDisplay", - surfaceSize.x, surfaceSize.y, DisplayMetrics.DENSITY_140, new Surface(), flags); - final int displayId = virtualDisplay.getDisplay().getDisplayId(); - mWm.mRoot.onDisplayAdded(displayId); + mWm.mPerDisplayFocusEnabled = false; + verification.run(); - // Ensure that virtual display was properly created and stored in WRC - assertThat(mWm.mRoot.getDisplayContent( - virtualDisplay.getDisplay().getDisplayId())).isNotNull(); - - return virtualDisplay; + clearInvocations(mWm.mInputManager); + mWm.mPerDisplayFocusEnabled = true; + verification.run(); } @Test 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 873c7f4e0e300..62de67a165c5b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -901,6 +901,7 @@ class WindowTestsBase extends SystemServiceTestsBase { DisplayInfo displayInfo = new DisplayInfo(); displayInfo.copyFrom(mDisplayInfo); displayInfo.type = Display.TYPE_VIRTUAL; + displayInfo.state = Display.STATE_ON; displayInfo.ownerUid = SYSTEM_UID; return createNewDisplay(displayInfo, DISPLAY_IME_POLICY_FALLBACK_DISPLAY, overrideSettings); }