[MediaProjection] Do not start layer mirroring without a surface

An app may pass a null surface to MediaProjection#createVirtualDisplay,
and later set the surface on the VirtualDisplay. The display's state
will change from off to on when the surface is set.

When determining if layer mirroring should be started/updated in
DisplayContent, take the presence of the surface/display state
into account, to prevent the app from crashing.

Bug: 197863746
Test: atest WmTests:DisplayContentTests
Change-Id: I01af07fff681aab6fc8235c861375eb79118cbfe
This commit is contained in:
Naomi Musgrave
2021-08-27 17:41:08 +01:00
parent 6426637598
commit fcef782559
5 changed files with 265 additions and 39 deletions

View File

@@ -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;

View File

@@ -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"
},

View File

@@ -303,6 +303,9 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
@Override
public Point getDisplaySurfaceDefaultSize() {
if (mSurface == null) {
return null;
}
return mSurface.getDefaultSize();
}

View File

@@ -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 {

View File

@@ -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,