diff options
| author | 2021-09-06 09:57:30 +0000 | |
|---|---|---|
| committer | 2021-09-06 09:57:30 +0000 | |
| commit | 052c311bb21e2cebee61dd104466cc2613dacf01 (patch) | |
| tree | 08a6bfb894dc29fce34cb422802a166628c5a19c | |
| parent | 506fa0bebd0e9ee013eaa5b15868a2ea4a379493 (diff) | |
| parent | fcef782559e0dcfeffb7c000f8c80c1259f89fad (diff) | |
Merge "[MediaProjection] Do not start layer mirroring without a surface" into sc-v2-dev
5 files changed, 265 insertions, 39 deletions
diff --git a/core/java/com/android/internal/protolog/ProtoLogGroup.java b/core/java/com/android/internal/protolog/ProtoLogGroup.java index 0f153bcdf1d4..db019a67772f 100644 --- a/core/java/com/android/internal/protolog/ProtoLogGroup.java +++ b/core/java/com/android/internal/protolog/ProtoLogGroup.java @@ -82,6 +82,8 @@ public enum ProtoLogGroup implements IProtoLogGroup { Consts.TAG_WM), WM_DEBUG_WINDOW_INSETS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM), + WM_DEBUG_LAYER_MIRRORING(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true, + Consts.TAG_WM), TEST_GROUP(true, true, false, "WindowManagerProtoLogTest"); private final boolean mEnabled; diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 6a93761454f1..0d7225be9e03 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -211,6 +211,12 @@ "group": "WM_DEBUG_SYNC_ENGINE", "at": "com\/android\/server\/wm\/BLASTSyncEngine.java" }, + "-1898316768": { + "message": "Unable to retrieve window container to start layer mirroring for display %d", + "level": "VERBOSE", + "group": "WM_DEBUG_LAYER_MIRRORING", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, "-1895337367": { "message": "Delete root task display=%d winMode=%d", "level": "VERBOSE", @@ -1093,6 +1099,12 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "-904499590": { + "message": "Provided surface for layer mirroring on display %d is not present, so do not update the surface", + "level": "VERBOSE", + "group": "WM_DEBUG_LAYER_MIRRORING", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, "-883738232": { "message": "Adding more than one toast window for UID at a time.", "level": "WARN", @@ -1303,6 +1315,12 @@ "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/RootWindowContainer.java" }, + "-663411559": { + "message": "Going ahead with updating layer mirroring for display %d to new bounds %s and\/or orientation %d.", + "level": "VERBOSE", + "group": "WM_DEBUG_LAYER_MIRRORING", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, "-655104359": { "message": "Frontmost changed immersion: %s", "level": "DEBUG", @@ -1561,6 +1579,12 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "-384564722": { + "message": "Unable to start layer mirroring for display %d since the surface is not available.", + "level": "VERBOSE", + "group": "WM_DEBUG_LAYER_MIRRORING", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, "-381475323": { "message": "DisplayContent: boot is waiting for window of type %d to be drawn", "level": "DEBUG", @@ -1633,6 +1657,12 @@ "group": "WM_DEBUG_STATES", "at": "com\/android\/server\/wm\/TaskFragment.java" }, + "-309399422": { + "message": "Display %d state is now (%d), so update layer mirroring?", + "level": "VERBOSE", + "group": "WM_DEBUG_LAYER_MIRRORING", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, "-302468788": { "message": "Expected target rootTask=%s to be top most but found rootTask=%s", "level": "WARN", @@ -1699,6 +1729,12 @@ "group": "WM_DEBUG_WINDOW_MOVEMENT", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "-190034097": { + "message": "Unable to retrieve window container to update layer mirroring for display %d", + "level": "VERBOSE", + "group": "WM_DEBUG_LAYER_MIRRORING", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, "-177040661": { "message": "Start rotation animation. customAnim=%s, mCurRotation=%s, mOriginalRotation=%s", "level": "DEBUG", @@ -1795,6 +1831,12 @@ "group": "WM_DEBUG_STATES", "at": "com\/android\/server\/wm\/TaskFragment.java" }, + "-79877120": { + "message": "Display %d has content (%b) so disable layer mirroring", + "level": "VERBOSE", + "group": "WM_DEBUG_LAYER_MIRRORING", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, "-70719599": { "message": "Unregister remote animations for organizer=%s uid=%d pid=%d", "level": "VERBOSE", @@ -2347,6 +2389,12 @@ "group": "WM_DEBUG_WINDOW_ORGANIZER", "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java" }, + "504397469": { + "message": "Unable to update layer mirroring for display %d to new bounds %s and\/or orientation %d, since the surface is not available.", + "level": "VERBOSE", + "group": "WM_DEBUG_LAYER_MIRRORING", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, "508887531": { "message": "applyAnimation voice: anim=%s transit=%s isEntrance=%b Callers=%s", "level": "VERBOSE", @@ -3103,6 +3151,12 @@ "group": "WM_DEBUG_SCREEN_ON", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "1407569006": { + "message": "Display %d was already layer mirroring, so apply transformations if necessary", + "level": "VERBOSE", + "group": "WM_DEBUG_LAYER_MIRRORING", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, "1417601133": { "message": "Enqueueing ADD_STARTING", "level": "VERBOSE", @@ -3349,6 +3403,12 @@ "group": "WM_DEBUG_CONFIGURATION", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, + "1687376052": { + "message": "Display %d has no content and is on, so start layer mirroring for state %d", + "level": "VERBOSE", + "group": "WM_DEBUG_LAYER_MIRRORING", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, "1689989893": { "message": "SyncGroup %d: Set ready", "level": "VERBOSE", @@ -3753,6 +3813,9 @@ "WM_DEBUG_KEEP_SCREEN_ON": { "tag": "WindowManager" }, + "WM_DEBUG_LAYER_MIRRORING": { + "tag": "WindowManager" + }, "WM_DEBUG_LOCKTASK": { "tag": "WindowManager" }, diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java index 34d2b0160c3c..a59219265e2c 100644 --- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java +++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java @@ -303,6 +303,9 @@ public class VirtualDisplayAdapter extends DisplayAdapter { @Override public Point getDisplaySurfaceDefaultSize() { + if (mSurface == null) { + return null; + } return mSurface.getDefaultSize(); } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index b110d8d44fc5..71c41e43ac2e 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -88,6 +88,7 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BOOT; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LAYER_MIRRORING; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SCREEN_ON; import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS; @@ -305,7 +306,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp @VisibleForTesting IBinder mTokenToMirror = null; /** - * The surface for mirroring the contents of this hierarchy. + * The surface for mirroring the contents of this hierarchy, or null if layer mirroring is + * temporarily disabled. */ private SurfaceControl mMirroredSurface = null; @@ -314,6 +316,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp */ private Rect mLastMirroredDisplayAreaBounds = null; + /** + * The last state of the display. + */ + private int mLastDisplayState; + // Contains all IME window containers. Note that the z-ordering of the IME windows will depend // on the IME target. We mainly have this container grouping so we can keep track of all the IME // window containers together and move them in-sync if/when needed. We use a subclass of @@ -1142,10 +1149,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Creating display=" + display); mWmService.mDisplayWindowSettings.applySettingsToDisplayLocked(this); - - // Check if this DisplayContent is for a new VirtualDisplay, that should use layer mirroring - // to capture the contents of a DisplayArea. - startMirrorIfNeeded(); } boolean isReady() { @@ -2504,19 +2507,42 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp // Update mirroring surface for MediaProjection, if this DisplayContent is being used // for layer mirroring. - if (mMirroredSurface != null) { - // Retrieve the size of the DisplayArea to mirror, and continue with the update if the - // bounds have changed. + if (isCurrentlyMirroring() && mLastMirroredDisplayAreaBounds != null) { + // Mirroring has already begun, but update mirroring since the display is now on. final WindowContainer wc = mWmService.mWindowContextListenerController.getContainer( mTokenToMirror); - if (wc != null && mLastMirroredDisplayAreaBounds != null) { - // Retrieve the size of the DisplayArea to mirror, and continue with the update - // if the bounds or orientation has changed. - final Rect displayAreaBounds = wc.getDisplayContent().getBounds(); - int displayAreaOrientation = wc.getDisplayContent().getOrientation(); - if (!mLastMirroredDisplayAreaBounds.equals(displayAreaBounds) - || lastOrientation != displayAreaOrientation) { - updateMirroredSurface(mWmService.mTransactionFactory.get(), displayAreaBounds); + if (wc == null) { + ProtoLog.v(WM_DEBUG_LAYER_MIRRORING, + "Unable to retrieve window container to update layer mirroring for " + + "display %d", + mDisplayId); + return; + } + + ProtoLog.v(WM_DEBUG_LAYER_MIRRORING, + "Display %d was already layer mirroring, so apply transformations if necessary", + mDisplayId); + // Retrieve the size of the DisplayArea to mirror, and continue with the update + // if the bounds or orientation has changed. + final Rect displayAreaBounds = wc.getDisplayContent().getBounds(); + int displayAreaOrientation = wc.getDisplayContent().getOrientation(); + if (!mLastMirroredDisplayAreaBounds.equals(displayAreaBounds) + || lastOrientation != displayAreaOrientation) { + Point surfaceSize = fetchSurfaceSizeIfPresent(); + if (surfaceSize != null) { + ProtoLog.v(WM_DEBUG_LAYER_MIRRORING, + "Going ahead with updating layer mirroring for display %d to new " + + "bounds %s and/or orientation %d.", + mDisplayId, displayAreaBounds, displayAreaOrientation); + updateMirroredSurface(mWmService.mTransactionFactory.get(), + displayAreaBounds, surfaceSize); + } else { + // If the surface removed, do nothing. We will handle this via onDisplayChanged + // (the display will be off if the surface is removed). + ProtoLog.v(WM_DEBUG_LAYER_MIRRORING, + "Unable to update layer mirroring for display %d to new bounds %s" + + " and/or orientation %d, since the surface is not available.", + mDisplayId, displayAreaBounds, displayAreaOrientation); } } } @@ -4405,6 +4431,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mTmpApplySurfaceChangesTransactionState.preferMinimalPostProcessing, true /* inTraversal, must call performTraversalInTrans... below */); } + // If the display now has content, or no longer has content, update layer mirroring. updateMirroring(); final boolean wallpaperVisible = mWallpaperController.isWallpaperVisible(); @@ -5504,6 +5531,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } else if (displayState == Display.STATE_ON) { mOffTokenAcquirer.release(mDisplayId); } + ProtoLog.v(WM_DEBUG_LAYER_MIRRORING, + "Display %d state is now (%d), so update layer mirroring?", + mDisplayId, displayState); + if (mLastDisplayState != displayState) { + // If state is on due to surface being added, then start layer mirroring. + // If state is off due to surface being removed, then stop layer mirroring. + updateMirroring(); + } + mLastDisplayState = displayState; } mWmService.requestTraversal(); } @@ -5982,31 +6018,48 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp * back to original MediaProjection approach. */ private void startMirrorIfNeeded() { - // Only mirror if this display does not have its own content. - if (mLastHasContent) { + // Only mirror if this display does not have its own content, is not mirroring already, + // and if this display is on (it has a surface to write output to). + if (mLastHasContent || isCurrentlyMirroring() || mDisplay.getState() == Display.STATE_OFF) { return; } + // Given the WindowToken of the DisplayArea to mirror, retrieve the associated // SurfaceControl. IBinder tokenToMirror = mWmService.mDisplayManagerInternal.getWindowTokenClientToMirror( mDisplayId); - if (tokenToMirror == null) { // This DisplayContent instance is not involved in layer mirroring. If the display // has been created for capturing, fall back to prior MediaProjection approach. return; } + final WindowContainer wc = mWmService.mWindowContextListenerController.getContainer( tokenToMirror); if (wc == null) { // Un-set the window token to mirror for this VirtualDisplay, to fall back to the // original MediaProjection approach. mWmService.mDisplayManagerInternal.setWindowTokenClientToMirror(mDisplayId, null); + ProtoLog.v(WM_DEBUG_LAYER_MIRRORING, + "Unable to retrieve window container to start layer mirroring for display %d", + mDisplayId); return; } - SurfaceControl sc = wc.getDisplayContent().getSurfaceControl(); + + Point surfaceSize = fetchSurfaceSizeIfPresent(); + if (surfaceSize == null) { + ProtoLog.v(WM_DEBUG_LAYER_MIRRORING, + "Unable to start layer mirroring for display %d since the surface is not " + + "available.", + mDisplayId); + return; + } + ProtoLog.v(WM_DEBUG_LAYER_MIRRORING, + "Display %d has no content and is on, so start layer mirroring for state %d", + mDisplayId, mDisplay.getState()); // Create a mirrored hierarchy for the SurfaceControl of the DisplayArea to capture. + SurfaceControl sc = wc.getDisplayContent().getSurfaceControl(); mMirroredSurface = SurfaceControl.mirrorSurface(sc); SurfaceControl.Transaction transaction = mWmService.mTransactionFactory.get() // Set the mMirroredSurface's parent to the root SurfaceControl for this @@ -6019,7 +6072,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp // VirtualDisplay will show up as part of the mirrored content. .reparent(mWindowingLayer, null); // Retrieve the size of the DisplayArea to mirror. - updateMirroredSurface(transaction, wc.getDisplayContent().getBounds()); + updateMirroredSurface(transaction, wc.getDisplayContent().getBounds(), surfaceSize); mTokenToMirror = tokenToMirror; // No need to clean up. In SurfaceFlinger, parents hold references to their children. The @@ -6029,11 +6082,18 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } /** - * Start or stop mirroring if this DisplayContent now has content, or no longer has content. + * Start mirroring if this DisplayContent no longer has content. Stop mirroring if it now + * has content or the display is not on. */ private void updateMirroring() { - if (mLastHasContent && mMirroredSurface != null) { - // Display now has content, so stop mirroring to it. + if (isCurrentlyMirroring() && (mLastHasContent + || mDisplay.getState() == Display.STATE_OFF)) { + ProtoLog.v(WM_DEBUG_LAYER_MIRRORING, + "Display %d has content (%b) so disable layer mirroring", mDisplayId, + mLastHasContent); + // If the display is not on and it is a virtual display, then it no longer has an + // associated surface to write output to. + // If the display now has content, stop mirroring to it. mWmService.mTransactionFactory.get() // Remove the reference to mMirroredSurface, to clean up associated memory. .remove(mMirroredSurface) @@ -6044,8 +6104,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp // Stop mirroring by destroying the reference to the mirrored layer. mMirroredSurface = null; // Do not un-set the token, in case content is removed and mirroring should begin again. - } else if (!mLastHasContent && mMirroredSurface == null) { - // Display no longer has content, so start mirroring to it. + } else { + // Display no longer has content, or now has a surface to write to, so try to start + // mirroring to it. startMirrorIfNeeded(); } } @@ -6054,21 +6115,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp * Apply transformations to the mirrored surface to ensure the captured contents are scaled to * fit and centred in the output surface. * - * @param transaction the transaction to include transformations of mMirroredSurface - * to. Transaction is not applied before returning. - * @param displayAreaBounds bounds of the DisplayArea to mirror to the surface provided by - * the app. + * @param transaction the transaction to include transformations of mMirroredSurface + * to. Transaction is not applied before returning. + * @param displayAreaBounds bounds of the DisplayArea to mirror to the surface provided by + * the app. + * @param surfaceSize the default size of the surface to write the display area content to */ @VisibleForTesting void updateMirroredSurface(SurfaceControl.Transaction transaction, - Rect displayAreaBounds) { - // Retrieve the default size of the surface the app provided to - // MediaProjection#createVirtualDisplay. Note the app is the consumer of the surface, - // since it reads out buffers from the surface, and SurfaceFlinger is the producer since - // it writes the mirrored layers to the buffers. - final Point surfaceSize = mWmService.mDisplayManagerInternal.getDisplaySurfaceDefaultSize( - mDisplayId); - + Rect displayAreaBounds, Point surfaceSize) { // Calculate the scale to apply to the root mirror SurfaceControl to fit the size of the // output surface. float scaleX = surfaceSize.x / (float) displayAreaBounds.width(); @@ -6103,6 +6158,36 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mLastMirroredDisplayAreaBounds = new Rect(displayAreaBounds); } + /** + * Returns a non-null {@link Point} if the surface is present, or null otherwise + */ + Point fetchSurfaceSizeIfPresent() { + // Retrieve the default size of the surface the app provided to + // MediaProjection#createVirtualDisplay. Note the app is the consumer of the surface, + // since it reads out buffers from the surface, and SurfaceFlinger is the producer since + // it writes the mirrored layers to the buffers. + Point surfaceSize = mWmService.mDisplayManagerInternal.getDisplaySurfaceDefaultSize( + mDisplayId); + if (surfaceSize == null) { + // Layer mirroring started with a null surface, so do not apply any transformations yet. + // State of virtual display will change to 'ON' when the surface is set. + // will get event DISPLAY_DEVICE_EVENT_CHANGED + ProtoLog.v(WM_DEBUG_LAYER_MIRRORING, + "Provided surface for layer mirroring on display %d is not present, so do not" + + " update the surface", + mDisplayId); + return null; + } + return surfaceSize; + } + + /** + * Returns {@code true} if this DisplayContent is currently layer mirroring. + */ + boolean isCurrentlyMirroring() { + return mTokenToMirror != null && mMirroredSurface != null; + } + /** The entry for proceeding to handle {@link #mFixedRotationLaunchingApp}. */ class FixedRotationTransitionListener extends WindowManagerInternal.AppTransitionListener { 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 14dc33e5840b..4ee0c6090504 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -25,6 +25,7 @@ import static android.content.pm.ActivityInfo.FLAG_SHOW_WHEN_LOCKED; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; 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; @@ -111,6 +112,7 @@ import android.graphics.Insets; import android.graphics.Point; import android.graphics.Rect; import android.graphics.Region; +import android.hardware.display.VirtualDisplay; import android.metrics.LogMaker; import android.os.Binder; import android.os.IBinder; @@ -2292,7 +2294,7 @@ public class DisplayContentTests extends WindowTestsBase { float yScale = 2f; Rect displayAreaBounds = new Rect(0, 0, Math.round(surfaceSize.x * xScale), Math.round(surfaceSize.y * yScale)); - virtualDisplay.updateMirroredSurface(mTransaction, displayAreaBounds); + virtualDisplay.updateMirroredSurface(mTransaction, displayAreaBounds, surfaceSize); // THEN content in the captured DisplayArea is scaled to fit the surface size. verify(mTransaction, atLeastOnce()).setMatrix(mirroredSurface, 1.0f / yScale, 0, 0, @@ -2305,6 +2307,72 @@ public class DisplayContentTests extends WindowTestsBase { mockSession.finishMocking(); } + @Test + public void testVirtualDisplayContent_withoutSurface() { + MockitoSession mockSession = mockitoSession() + .initMocks(this) + .spyStatic(SurfaceControl.class) + .strictness(Strictness.LENIENT) + .startMocking(); + + // 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, 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); + + // THEN mirroring is not started, since a null surface indicates the VirtualDisplay is off. + assertThat(actualDC.mTokenToMirror).isNull(); + + display.release(); + mockSession.finishMocking(); + } + + @Test + public void testVirtualDisplayContent_withSurface() { + MockitoSession mockSession = mockitoSession() + .initMocks(this) + .spyStatic(SurfaceControl.class) + .strictness(Strictness.LENIENT) + .startMocking(); + + // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to + // mirror. + final IBinder tokenToMirror = 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(); + mWm.mRoot.onDisplayAdded(displayId); + + // WHEN getting the DisplayContent for the new virtual display. + DisplayContent actualDC = mWm.mRoot.getDisplayContent(displayId); + + // THEN mirroring is initiated for the default display's DisplayArea. + assertThat(actualDC.mTokenToMirror).isEqualTo(tokenToMirror); + + display.release(); + mockSession.finishMocking(); + } + private class TestToken extends Binder { } @@ -2342,6 +2410,11 @@ public class DisplayContentTests extends WindowTestsBase { 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); + } + private void removeRootTaskTests(Runnable runnable) { final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); final Task rootTask1 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, |