Merge "Send core-created snapshots to transition player" into tm-qpr-dev

This commit is contained in:
Evan Rosky
2022-09-07 17:15:05 +00:00
committed by Android (Google) Code Review
4 changed files with 127 additions and 39 deletions

View File

@@ -397,6 +397,8 @@ public final class TransitionInfo implements Parcelable {
private @Surface.Rotation int mEndFixedRotation = ROTATION_UNDEFINED; private @Surface.Rotation int mEndFixedRotation = ROTATION_UNDEFINED;
private int mRotationAnimation = ROTATION_ANIMATION_UNSPECIFIED; private int mRotationAnimation = ROTATION_ANIMATION_UNSPECIFIED;
private @ColorInt int mBackgroundColor; private @ColorInt int mBackgroundColor;
private SurfaceControl mSnapshot = null;
private float mSnapshotLuma;
public Change(@Nullable WindowContainerToken container, @NonNull SurfaceControl leash) { public Change(@Nullable WindowContainerToken container, @NonNull SurfaceControl leash) {
mContainer = container; mContainer = container;
@@ -420,6 +422,8 @@ public final class TransitionInfo implements Parcelable {
mEndFixedRotation = in.readInt(); mEndFixedRotation = in.readInt();
mRotationAnimation = in.readInt(); mRotationAnimation = in.readInt();
mBackgroundColor = in.readInt(); mBackgroundColor = in.readInt();
mSnapshot = in.readTypedObject(SurfaceControl.CREATOR);
mSnapshotLuma = in.readFloat();
} }
/** Sets the parent of this change's container. The parent must be a participant or null. */ /** Sets the parent of this change's container. The parent must be a participant or null. */
@@ -489,6 +493,12 @@ public final class TransitionInfo implements Parcelable {
mBackgroundColor = backgroundColor; mBackgroundColor = backgroundColor;
} }
/** Sets a snapshot surface for the "start" state of the container. */
public void setSnapshot(@Nullable SurfaceControl snapshot, float luma) {
mSnapshot = snapshot;
mSnapshotLuma = luma;
}
/** @return the container that is changing. May be null if non-remotable (eg. activity) */ /** @return the container that is changing. May be null if non-remotable (eg. activity) */
@Nullable @Nullable
public WindowContainerToken getContainer() { public WindowContainerToken getContainer() {
@@ -587,6 +597,17 @@ public final class TransitionInfo implements Parcelable {
return mBackgroundColor; return mBackgroundColor;
} }
/** @return a snapshot surface (if applicable). */
@Nullable
public SurfaceControl getSnapshot() {
return mSnapshot;
}
/** @return the luma calculated for the snapshot surface (if applicable). */
public float getSnapshotLuma() {
return mSnapshotLuma;
}
/** @hide */ /** @hide */
@Override @Override
public void writeToParcel(@NonNull Parcel dest, int flags) { public void writeToParcel(@NonNull Parcel dest, int flags) {
@@ -605,6 +626,8 @@ public final class TransitionInfo implements Parcelable {
dest.writeInt(mEndFixedRotation); dest.writeInt(mEndFixedRotation);
dest.writeInt(mRotationAnimation); dest.writeInt(mRotationAnimation);
dest.writeInt(mBackgroundColor); dest.writeInt(mBackgroundColor);
dest.writeTypedObject(mSnapshot, flags);
dest.writeFloat(mSnapshotLuma);
} }
@NonNull @NonNull
@@ -629,11 +652,13 @@ public final class TransitionInfo implements Parcelable {
@Override @Override
public String toString() { public String toString() {
return "{" + mContainer + "(" + mParent + ") leash=" + mLeash String out = "{" + mContainer + "(" + mParent + ") leash=" + mLeash
+ " m=" + modeToString(mMode) + " f=" + flagsToString(mFlags) + " sb=" + " m=" + modeToString(mMode) + " f=" + flagsToString(mFlags) + " sb="
+ mStartAbsBounds + " eb=" + mEndAbsBounds + " eo=" + mEndRelOffset + " r=" + mStartAbsBounds + " eb=" + mEndAbsBounds + " eo=" + mEndRelOffset + " r="
+ mStartRotation + "->" + mEndRotation + ":" + mRotationAnimation + mStartRotation + "->" + mEndRotation + ":" + mRotationAnimation
+ " endFixedRotation=" + mEndFixedRotation + "}"; + " endFixedRotation=" + mEndFixedRotation;
if (mSnapshot != null) out += " snapshot=" + mSnapshot;
return out + "}";
} }
} }

View File

@@ -139,6 +139,11 @@ class ScreenRotationAnimation {
.build(); .build();
try { try {
if (change.getSnapshot() != null) {
mScreenshotLayer = change.getSnapshot();
t.reparent(mScreenshotLayer, mAnimLeash);
mStartLuma = change.getSnapshotLuma();
} else {
SurfaceControl.LayerCaptureArgs args = SurfaceControl.LayerCaptureArgs args =
new SurfaceControl.LayerCaptureArgs.Builder(mSurfaceControl) new SurfaceControl.LayerCaptureArgs.Builder(mSurfaceControl)
.setCaptureSecureLayers(true) .setCaptureSecureLayers(true)
@@ -161,16 +166,20 @@ class ScreenRotationAnimation {
.setName("RotationLayer") .setName("RotationLayer")
.build(); .build();
t.setLayer(mAnimLeash, SCREEN_FREEZE_LAYER_BASE);
t.show(mAnimLeash);
// Crop the real content in case it contains a larger child layer, e.g. wallpaper.
t.setCrop(mSurfaceControl, new Rect(0, 0, mEndWidth, mEndHeight));
final ColorSpace colorSpace = screenshotBuffer.getColorSpace(); final ColorSpace colorSpace = screenshotBuffer.getColorSpace();
final HardwareBuffer hardwareBuffer = screenshotBuffer.getHardwareBuffer(); final HardwareBuffer hardwareBuffer = screenshotBuffer.getHardwareBuffer();
t.setDataSpace(mScreenshotLayer, colorSpace.getDataSpace()); t.setDataSpace(mScreenshotLayer, colorSpace.getDataSpace());
t.setBuffer(mScreenshotLayer, hardwareBuffer); t.setBuffer(mScreenshotLayer, hardwareBuffer);
t.show(mScreenshotLayer); t.show(mScreenshotLayer);
if (!isCustomRotate()) {
mStartLuma = getMedianBorderLuma(hardwareBuffer, colorSpace);
}
}
t.setLayer(mAnimLeash, SCREEN_FREEZE_LAYER_BASE);
t.show(mAnimLeash);
// Crop the real content in case it contains a larger child layer, e.g. wallpaper.
t.setCrop(mSurfaceControl, new Rect(0, 0, mEndWidth, mEndHeight));
if (!isCustomRotate()) { if (!isCustomRotate()) {
mBackColorSurface = new SurfaceControl.Builder(session) mBackColorSurface = new SurfaceControl.Builder(session)
@@ -181,8 +190,6 @@ class ScreenRotationAnimation {
.setName("BackColorSurface") .setName("BackColorSurface")
.build(); .build();
mStartLuma = getMedianBorderLuma(hardwareBuffer, colorSpace);
t.setLayer(mBackColorSurface, -1); t.setLayer(mBackColorSurface, -1);
t.setColor(mBackColorSurface, new float[]{mStartLuma, mStartLuma, mStartLuma}); t.setColor(mBackColorSurface, new float[]{mStartLuma, mStartLuma, mStartLuma});
t.show(mBackColorSurface); t.show(mBackColorSurface);

View File

@@ -93,11 +93,13 @@ import com.android.internal.protolog.ProtoLogGroup;
import com.android.internal.protolog.common.ProtoLog; import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.function.pooled.PooledLambda; import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.inputmethod.InputMethodManagerInternal; import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.wm.utils.RotationAnimationUtils;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.function.Predicate; import java.util.function.Predicate;
/** /**
@@ -289,9 +291,9 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
if (mContainerFreezer == null) { if (mContainerFreezer == null) {
mContainerFreezer = new ScreenshotFreezer(); mContainerFreezer = new ScreenshotFreezer();
} }
mIsSeamlessRotation = true;
final WindowState top = dc.getDisplayPolicy().getTopFullscreenOpaqueWindow(); final WindowState top = dc.getDisplayPolicy().getTopFullscreenOpaqueWindow();
if (top != null) { if (top != null) {
mIsSeamlessRotation = true;
top.mSyncMethodOverride = BLASTSyncEngine.METHOD_BLAST; top.mSyncMethodOverride = BLASTSyncEngine.METHOD_BLAST;
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Override sync-method for %s " ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Override sync-method for %s "
+ "because seamless rotating", top.getName()); + "because seamless rotating", top.getName());
@@ -1635,6 +1637,9 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
change.setEndAbsBounds(bounds); change.setEndAbsBounds(bounds);
} }
change.setRotation(info.mRotation, endRotation); change.setRotation(info.mRotation, endRotation);
if (info.mSnapshot != null) {
change.setSnapshot(info.mSnapshot, info.mSnapshotLuma);
}
out.addChange(change); out.addChange(change);
} }
@@ -1790,6 +1795,10 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
/** These are just extra info. They aren't used for change-detection. */ /** These are just extra info. They aren't used for change-detection. */
@Flag int mFlags = FLAG_NONE; @Flag int mFlags = FLAG_NONE;
/** Snapshot surface and luma, if relevant. */
SurfaceControl mSnapshot;
float mSnapshotLuma;
ChangeInfo(@NonNull WindowContainer origState) { ChangeInfo(@NonNull WindowContainer origState) {
mVisible = origState.isVisibleRequested(); mVisible = origState.isVisibleRequested();
mWindowingMode = origState.getWindowingMode(); mWindowingMode = origState.getWindowingMode();
@@ -2098,8 +2107,8 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
*/ */
@VisibleForTesting @VisibleForTesting
private class ScreenshotFreezer implements IContainerFreezer { private class ScreenshotFreezer implements IContainerFreezer {
/** Values are the screenshot "surfaces" or null if it was frozen via BLAST override. */ /** Keeps track of which windows are frozen. Not all frozen windows have snapshots. */
private final ArrayMap<WindowContainer, SurfaceControl> mSnapshots = new ArrayMap<>(); private final ArraySet<WindowContainer> mFrozen = new ArraySet<>();
/** Takes a screenshot and puts it at the top of the container's surface. */ /** Takes a screenshot and puts it at the top of the container's surface. */
@Override @Override
@@ -2109,7 +2118,7 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
// Check if any parents have already been "frozen". If so, `wc` is already part of that // Check if any parents have already been "frozen". If so, `wc` is already part of that
// snapshot, so just skip it. // snapshot, so just skip it.
for (WindowContainer p = wc; p != null; p = p.getParent()) { for (WindowContainer p = wc; p != null; p = p.getParent()) {
if (mSnapshots.containsKey(p)) return false; if (mFrozen.contains(p)) return false;
} }
if (mIsSeamlessRotation) { if (mIsSeamlessRotation) {
@@ -2118,7 +2127,7 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
if (top != null && (top == wc || top.isDescendantOf(wc))) { if (top != null && (top == wc || top.isDescendantOf(wc))) {
// Don't use screenshots for seamless windows: these will use BLAST even if not // Don't use screenshots for seamless windows: these will use BLAST even if not
// BLAST mode. // BLAST mode.
mSnapshots.put(wc, null); mFrozen.add(wc);
return true; return true;
} }
} }
@@ -2151,7 +2160,15 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
.setCallsite("Transition.ScreenshotSync") .setCallsite("Transition.ScreenshotSync")
.setBLASTLayer() .setBLASTLayer()
.build(); .build();
mSnapshots.put(wc, snapshotSurface); mFrozen.add(wc);
final ChangeInfo changeInfo = Objects.requireNonNull(mChanges.get(wc));
changeInfo.mSnapshot = snapshotSurface;
if (wc.asDisplayContent() != null) {
// This isn't cheap, so only do it for rotations: assume display-level is rotate
// since most of the time it is.
changeInfo.mSnapshotLuma = RotationAnimationUtils.getMedianBorderLuma(
screenshotBuffer.getHardwareBuffer(), screenshotBuffer.getColorSpace());
}
SurfaceControl.Transaction t = wc.mWmService.mTransactionFactory.get(); SurfaceControl.Transaction t = wc.mWmService.mTransactionFactory.get();
t.setBuffer(snapshotSurface, buffer); t.setBuffer(snapshotSurface, buffer);
@@ -2172,11 +2189,12 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
@Override @Override
public void cleanUp(SurfaceControl.Transaction t) { public void cleanUp(SurfaceControl.Transaction t) {
for (int i = 0; i < mSnapshots.size(); ++i) { for (int i = 0; i < mFrozen.size(); ++i) {
SurfaceControl snap = mSnapshots.valueAt(i); SurfaceControl snap =
Objects.requireNonNull(mChanges.get(mFrozen.valueAt(i))).mSnapshot;
// May be null if it was frozen via BLAST override. // May be null if it was frozen via BLAST override.
if (snap == null) continue; if (snap == null) continue;
t.remove(snap); t.reparent(snap, null /* newParent */);
} }
} }
} }

View File

@@ -27,6 +27,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.view.WindowManager.TRANSIT_TO_BACK;
@@ -82,6 +83,7 @@ import org.mockito.ArgumentCaptor;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Objects;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.function.Function; import java.util.function.Function;
@@ -1167,6 +1169,42 @@ public class TransitionTests extends WindowTestsBase {
assertTrue(mSyncEngine.isReady(transition.getSyncId())); assertTrue(mSyncEngine.isReady(transition.getSyncId()));
} }
@Test
public void testVisibleChange_snapshot() {
registerTestTransitionPlayer();
final ActivityRecord app = createActivityRecord(mDisplayContent);
final Transition transition = new Transition(TRANSIT_CHANGE, 0 /* flags */,
app.mTransitionController, mWm.mSyncEngine);
app.mTransitionController.moveToCollecting(transition, BLASTSyncEngine.METHOD_NONE);
final SurfaceControl mockSnapshot = mock(SurfaceControl.class);
transition.setContainerFreezer(new Transition.IContainerFreezer() {
@Override
public boolean freeze(@NonNull WindowContainer wc, @NonNull Rect bounds) {
Objects.requireNonNull(transition.mChanges.get(wc)).mSnapshot = mockSnapshot;
return true;
}
@Override
public void cleanUp(SurfaceControl.Transaction t) {
}
});
final Task task = app.getTask();
transition.collect(task);
final Rect bounds = new Rect(task.getBounds());
Configuration c = new Configuration(task.getRequestedOverrideConfiguration());
bounds.inset(10, 10);
c.windowConfiguration.setBounds(bounds);
task.onRequestedOverrideConfigurationChanged(c);
ArrayList<WindowContainer> targets = Transition.calculateTargets(
transition.mParticipants, transition.mChanges);
TransitionInfo info = Transition.calculateTransitionInfo(
TRANSIT_CHANGE, 0, targets, transition.mChanges, mMockT);
assertEquals(mockSnapshot,
info.getChange(task.mRemoteToken.toWindowContainerToken()).getSnapshot());
transition.abort();
}
private static void makeTaskOrganized(Task... tasks) { private static void makeTaskOrganized(Task... tasks) {
final ITaskOrganizer organizer = mock(ITaskOrganizer.class); final ITaskOrganizer organizer = mock(ITaskOrganizer.class);
for (Task t : tasks) { for (Task t : tasks) {