[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:
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -303,6 +303,9 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
|
||||
|
||||
@Override
|
||||
public Point getDisplaySurfaceDefaultSize() {
|
||||
if (mSurface == null) {
|
||||
return null;
|
||||
}
|
||||
return mSurface.getDefaultSize();
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user