Merge "[MediaProjection] Do not start layer mirroring without a surface" into sc-v2-dev am: 052c311bb2

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15684475

Change-Id: Iffd55a3ae6f1eb736cf6cd0f37a46abe904b1a31
This commit is contained in:
Naomi Musgrave
2021-09-06 10:13:27 +00:00
committed by Automerger Merge Worker
5 changed files with 265 additions and 39 deletions

View File

@@ -82,6 +82,8 @@ public enum ProtoLogGroup implements IProtoLogGroup {
Consts.TAG_WM), Consts.TAG_WM),
WM_DEBUG_WINDOW_INSETS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, WM_DEBUG_WINDOW_INSETS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
Consts.TAG_WM), 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"); TEST_GROUP(true, true, false, "WindowManagerProtoLogTest");
private final boolean mEnabled; private final boolean mEnabled;

View File

@@ -211,6 +211,12 @@
"group": "WM_DEBUG_SYNC_ENGINE", "group": "WM_DEBUG_SYNC_ENGINE",
"at": "com\/android\/server\/wm\/BLASTSyncEngine.java" "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": { "-1895337367": {
"message": "Delete root task display=%d winMode=%d", "message": "Delete root task display=%d winMode=%d",
"level": "VERBOSE", "level": "VERBOSE",
@@ -1093,6 +1099,12 @@
"group": "WM_ERROR", "group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java" "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": { "-883738232": {
"message": "Adding more than one toast window for UID at a time.", "message": "Adding more than one toast window for UID at a time.",
"level": "WARN", "level": "WARN",
@@ -1303,6 +1315,12 @@
"group": "WM_DEBUG_ORIENTATION", "group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/RootWindowContainer.java" "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": { "-655104359": {
"message": "Frontmost changed immersion: %s", "message": "Frontmost changed immersion: %s",
"level": "DEBUG", "level": "DEBUG",
@@ -1561,6 +1579,12 @@
"group": "WM_ERROR", "group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java" "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": { "-381475323": {
"message": "DisplayContent: boot is waiting for window of type %d to be drawn", "message": "DisplayContent: boot is waiting for window of type %d to be drawn",
"level": "DEBUG", "level": "DEBUG",
@@ -1633,6 +1657,12 @@
"group": "WM_DEBUG_STATES", "group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/TaskFragment.java" "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": { "-302468788": {
"message": "Expected target rootTask=%s to be top most but found rootTask=%s", "message": "Expected target rootTask=%s to be top most but found rootTask=%s",
"level": "WARN", "level": "WARN",
@@ -1699,6 +1729,12 @@
"group": "WM_DEBUG_WINDOW_MOVEMENT", "group": "WM_DEBUG_WINDOW_MOVEMENT",
"at": "com\/android\/server\/wm\/WindowManagerService.java" "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": { "-177040661": {
"message": "Start rotation animation. customAnim=%s, mCurRotation=%s, mOriginalRotation=%s", "message": "Start rotation animation. customAnim=%s, mCurRotation=%s, mOriginalRotation=%s",
"level": "DEBUG", "level": "DEBUG",
@@ -1795,6 +1831,12 @@
"group": "WM_DEBUG_STATES", "group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/TaskFragment.java" "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": { "-70719599": {
"message": "Unregister remote animations for organizer=%s uid=%d pid=%d", "message": "Unregister remote animations for organizer=%s uid=%d pid=%d",
"level": "VERBOSE", "level": "VERBOSE",
@@ -2347,6 +2389,12 @@
"group": "WM_DEBUG_WINDOW_ORGANIZER", "group": "WM_DEBUG_WINDOW_ORGANIZER",
"at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java" "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": { "508887531": {
"message": "applyAnimation voice: anim=%s transit=%s isEntrance=%b Callers=%s", "message": "applyAnimation voice: anim=%s transit=%s isEntrance=%b Callers=%s",
"level": "VERBOSE", "level": "VERBOSE",
@@ -3103,6 +3151,12 @@
"group": "WM_DEBUG_SCREEN_ON", "group": "WM_DEBUG_SCREEN_ON",
"at": "com\/android\/server\/wm\/WindowManagerService.java" "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": { "1417601133": {
"message": "Enqueueing ADD_STARTING", "message": "Enqueueing ADD_STARTING",
"level": "VERBOSE", "level": "VERBOSE",
@@ -3349,6 +3403,12 @@
"group": "WM_DEBUG_CONFIGURATION", "group": "WM_DEBUG_CONFIGURATION",
"at": "com\/android\/server\/wm\/ActivityRecord.java" "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": { "1689989893": {
"message": "SyncGroup %d: Set ready", "message": "SyncGroup %d: Set ready",
"level": "VERBOSE", "level": "VERBOSE",
@@ -3753,6 +3813,9 @@
"WM_DEBUG_KEEP_SCREEN_ON": { "WM_DEBUG_KEEP_SCREEN_ON": {
"tag": "WindowManager" "tag": "WindowManager"
}, },
"WM_DEBUG_LAYER_MIRRORING": {
"tag": "WindowManager"
},
"WM_DEBUG_LOCKTASK": { "WM_DEBUG_LOCKTASK": {
"tag": "WindowManager" "tag": "WindowManager"
}, },

View File

@@ -303,6 +303,9 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
@Override @Override
public Point getDisplaySurfaceDefaultSize() { public Point getDisplaySurfaceDefaultSize() {
if (mSurface == null) {
return null;
}
return mSurface.getDefaultSize(); 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;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; 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_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_ORIENTATION;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SCREEN_ON; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SCREEN_ON;
import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS; 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; @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; private SurfaceControl mMirroredSurface = null;
@@ -314,6 +316,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
*/ */
private Rect mLastMirroredDisplayAreaBounds = null; 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 // 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 // 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 // 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); if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Creating display=" + display);
mWmService.mDisplayWindowSettings.applySettingsToDisplayLocked(this); 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() { boolean isReady() {
@@ -2504,19 +2507,42 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// Update mirroring surface for MediaProjection, if this DisplayContent is being used // Update mirroring surface for MediaProjection, if this DisplayContent is being used
// for layer mirroring. // for layer mirroring.
if (mMirroredSurface != null) { if (isCurrentlyMirroring() && mLastMirroredDisplayAreaBounds != null) {
// Retrieve the size of the DisplayArea to mirror, and continue with the update if the // Mirroring has already begun, but update mirroring since the display is now on.
// bounds have changed.
final WindowContainer wc = mWmService.mWindowContextListenerController.getContainer( final WindowContainer wc = mWmService.mWindowContextListenerController.getContainer(
mTokenToMirror); mTokenToMirror);
if (wc != null && mLastMirroredDisplayAreaBounds != null) { if (wc == null) {
// Retrieve the size of the DisplayArea to mirror, and continue with the update ProtoLog.v(WM_DEBUG_LAYER_MIRRORING,
// if the bounds or orientation has changed. "Unable to retrieve window container to update layer mirroring for "
final Rect displayAreaBounds = wc.getDisplayContent().getBounds(); + "display %d",
int displayAreaOrientation = wc.getDisplayContent().getOrientation(); mDisplayId);
if (!mLastMirroredDisplayAreaBounds.equals(displayAreaBounds) return;
|| lastOrientation != displayAreaOrientation) { }
updateMirroredSurface(mWmService.mTransactionFactory.get(), displayAreaBounds);
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, mTmpApplySurfaceChangesTransactionState.preferMinimalPostProcessing,
true /* inTraversal, must call performTraversalInTrans... below */); true /* inTraversal, must call performTraversalInTrans... below */);
} }
// If the display now has content, or no longer has content, update layer mirroring.
updateMirroring(); updateMirroring();
final boolean wallpaperVisible = mWallpaperController.isWallpaperVisible(); final boolean wallpaperVisible = mWallpaperController.isWallpaperVisible();
@@ -5504,6 +5531,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
} else if (displayState == Display.STATE_ON) { } else if (displayState == Display.STATE_ON) {
mOffTokenAcquirer.release(mDisplayId); 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(); mWmService.requestTraversal();
} }
@@ -5982,31 +6018,48 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
* back to original MediaProjection approach. * back to original MediaProjection approach.
*/ */
private void startMirrorIfNeeded() { private void startMirrorIfNeeded() {
// Only mirror if this display does not have its own content. // Only mirror if this display does not have its own content, is not mirroring already,
if (mLastHasContent) { // and if this display is on (it has a surface to write output to).
if (mLastHasContent || isCurrentlyMirroring() || mDisplay.getState() == Display.STATE_OFF) {
return; return;
} }
// Given the WindowToken of the DisplayArea to mirror, retrieve the associated // Given the WindowToken of the DisplayArea to mirror, retrieve the associated
// SurfaceControl. // SurfaceControl.
IBinder tokenToMirror = mWmService.mDisplayManagerInternal.getWindowTokenClientToMirror( IBinder tokenToMirror = mWmService.mDisplayManagerInternal.getWindowTokenClientToMirror(
mDisplayId); mDisplayId);
if (tokenToMirror == null) { if (tokenToMirror == null) {
// This DisplayContent instance is not involved in layer mirroring. If the display // This DisplayContent instance is not involved in layer mirroring. If the display
// has been created for capturing, fall back to prior MediaProjection approach. // has been created for capturing, fall back to prior MediaProjection approach.
return; return;
} }
final WindowContainer wc = mWmService.mWindowContextListenerController.getContainer( final WindowContainer wc = mWmService.mWindowContextListenerController.getContainer(
tokenToMirror); tokenToMirror);
if (wc == null) { if (wc == null) {
// Un-set the window token to mirror for this VirtualDisplay, to fall back to the // Un-set the window token to mirror for this VirtualDisplay, to fall back to the
// original MediaProjection approach. // original MediaProjection approach.
mWmService.mDisplayManagerInternal.setWindowTokenClientToMirror(mDisplayId, null); 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; 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. // Create a mirrored hierarchy for the SurfaceControl of the DisplayArea to capture.
SurfaceControl sc = wc.getDisplayContent().getSurfaceControl();
mMirroredSurface = SurfaceControl.mirrorSurface(sc); mMirroredSurface = SurfaceControl.mirrorSurface(sc);
SurfaceControl.Transaction transaction = mWmService.mTransactionFactory.get() SurfaceControl.Transaction transaction = mWmService.mTransactionFactory.get()
// Set the mMirroredSurface's parent to the root SurfaceControl for this // 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. // VirtualDisplay will show up as part of the mirrored content.
.reparent(mWindowingLayer, null); .reparent(mWindowingLayer, null);
// Retrieve the size of the DisplayArea to mirror. // Retrieve the size of the DisplayArea to mirror.
updateMirroredSurface(transaction, wc.getDisplayContent().getBounds()); updateMirroredSurface(transaction, wc.getDisplayContent().getBounds(), surfaceSize);
mTokenToMirror = tokenToMirror; mTokenToMirror = tokenToMirror;
// No need to clean up. In SurfaceFlinger, parents hold references to their children. The // 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() { private void updateMirroring() {
if (mLastHasContent && mMirroredSurface != null) { if (isCurrentlyMirroring() && (mLastHasContent
// Display now has content, so stop mirroring to it. || 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() mWmService.mTransactionFactory.get()
// Remove the reference to mMirroredSurface, to clean up associated memory. // Remove the reference to mMirroredSurface, to clean up associated memory.
.remove(mMirroredSurface) .remove(mMirroredSurface)
@@ -6044,8 +6104,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// Stop mirroring by destroying the reference to the mirrored layer. // Stop mirroring by destroying the reference to the mirrored layer.
mMirroredSurface = null; mMirroredSurface = null;
// Do not un-set the token, in case content is removed and mirroring should begin again. // Do not un-set the token, in case content is removed and mirroring should begin again.
} else if (!mLastHasContent && mMirroredSurface == null) { } else {
// Display no longer has content, so start mirroring to it. // Display no longer has content, or now has a surface to write to, so try to start
// mirroring to it.
startMirrorIfNeeded(); 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 * Apply transformations to the mirrored surface to ensure the captured contents are scaled to
* fit and centred in the output surface. * fit and centred in the output surface.
* *
* @param transaction the transaction to include transformations of mMirroredSurface * @param transaction the transaction to include transformations of mMirroredSurface
* to. Transaction is not applied before returning. * to. Transaction is not applied before returning.
* @param displayAreaBounds bounds of the DisplayArea to mirror to the surface provided by * @param displayAreaBounds bounds of the DisplayArea to mirror to the surface provided by
* the app. * the app.
* @param surfaceSize the default size of the surface to write the display area content to
*/ */
@VisibleForTesting @VisibleForTesting
void updateMirroredSurface(SurfaceControl.Transaction transaction, void updateMirroredSurface(SurfaceControl.Transaction transaction,
Rect displayAreaBounds) { Rect displayAreaBounds, Point surfaceSize) {
// 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);
// Calculate the scale to apply to the root mirror SurfaceControl to fit the size of the // Calculate the scale to apply to the root mirror SurfaceControl to fit the size of the
// output surface. // output surface.
float scaleX = surfaceSize.x / (float) displayAreaBounds.width(); float scaleX = surfaceSize.x / (float) displayAreaBounds.width();
@@ -6103,6 +6158,36 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
mLastMirroredDisplayAreaBounds = new Rect(displayAreaBounds); 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}. */ /** The entry for proceeding to handle {@link #mFixedRotationLaunchingApp}. */
class FixedRotationTransitionListener extends WindowManagerInternal.AppTransitionListener { 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_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 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.P;
import static android.os.Build.VERSION_CODES.Q; import static android.os.Build.VERSION_CODES.Q;
import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.DEFAULT_DISPLAY;
@@ -111,6 +112,7 @@ import android.graphics.Insets;
import android.graphics.Point; import android.graphics.Point;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.Region; import android.graphics.Region;
import android.hardware.display.VirtualDisplay;
import android.metrics.LogMaker; import android.metrics.LogMaker;
import android.os.Binder; import android.os.Binder;
import android.os.IBinder; import android.os.IBinder;
@@ -2292,7 +2294,7 @@ public class DisplayContentTests extends WindowTestsBase {
float yScale = 2f; float yScale = 2f;
Rect displayAreaBounds = new Rect(0, 0, Math.round(surfaceSize.x * xScale), Rect displayAreaBounds = new Rect(0, 0, Math.round(surfaceSize.x * xScale),
Math.round(surfaceSize.y * yScale)); 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. // THEN content in the captured DisplayArea is scaled to fit the surface size.
verify(mTransaction, atLeastOnce()).setMatrix(mirroredSurface, 1.0f / yScale, 0, 0, verify(mTransaction, atLeastOnce()).setMatrix(mirroredSurface, 1.0f / yScale, 0, 0,
@@ -2305,6 +2307,72 @@ public class DisplayContentTests extends WindowTestsBase {
mockSession.finishMocking(); 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 { private class TestToken extends Binder {
} }
@@ -2342,6 +2410,11 @@ public class DisplayContentTests extends WindowTestsBase {
return mirroredSurface; 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) { private void removeRootTaskTests(Runnable runnable) {
final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
final Task rootTask1 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, final Task rootTask1 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,