Merge "Add support for multiple roots in a transition" into udc-dev
This commit is contained in:
@@ -24,6 +24,7 @@ import static android.app.ActivityOptions.ANIM_SCALE_UP;
|
||||
import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN;
|
||||
import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP;
|
||||
import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
|
||||
import static android.view.Display.INVALID_DISPLAY;
|
||||
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
|
||||
import static android.view.WindowManager.TRANSIT_CHANGE;
|
||||
import static android.view.WindowManager.TRANSIT_CLOSE;
|
||||
@@ -58,6 +59,7 @@ import java.util.List;
|
||||
* @hide
|
||||
*/
|
||||
public final class TransitionInfo implements Parcelable {
|
||||
private static final String TAG = "TransitionInfo";
|
||||
|
||||
/**
|
||||
* Modes are only a sub-set of all the transit-types since they are per-container
|
||||
@@ -184,9 +186,7 @@ public final class TransitionInfo implements Parcelable {
|
||||
private final @TransitionType int mType;
|
||||
private final @TransitionFlags int mFlags;
|
||||
private final ArrayList<Change> mChanges = new ArrayList<>();
|
||||
|
||||
private SurfaceControl mRootLeash;
|
||||
private final Point mRootOffset = new Point();
|
||||
private final ArrayList<Root> mRoots = new ArrayList<>();
|
||||
|
||||
private AnimationOptions mOptions;
|
||||
|
||||
@@ -200,10 +200,7 @@ public final class TransitionInfo implements Parcelable {
|
||||
mType = in.readInt();
|
||||
mFlags = in.readInt();
|
||||
in.readTypedList(mChanges, Change.CREATOR);
|
||||
mRootLeash = new SurfaceControl();
|
||||
mRootLeash.readFromParcel(in);
|
||||
mRootLeash.setUnreleasedWarningCallSite("TransitionInfo");
|
||||
mRootOffset.readFromParcel(in);
|
||||
in.readTypedList(mRoots, Root.CREATOR);
|
||||
mOptions = in.readTypedObject(AnimationOptions.CREATOR);
|
||||
}
|
||||
|
||||
@@ -213,8 +210,7 @@ public final class TransitionInfo implements Parcelable {
|
||||
dest.writeInt(mType);
|
||||
dest.writeInt(mFlags);
|
||||
dest.writeTypedList(mChanges);
|
||||
mRootLeash.writeToParcel(dest, flags);
|
||||
mRootOffset.writeToParcel(dest, flags);
|
||||
dest.writeTypedList(mRoots, flags);
|
||||
dest.writeTypedObject(mOptions, flags);
|
||||
}
|
||||
|
||||
@@ -238,10 +234,15 @@ public final class TransitionInfo implements Parcelable {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @see #getRootLeash() */
|
||||
public void setRootLeash(@NonNull SurfaceControl leash, int offsetLeft, int offsetTop) {
|
||||
mRootLeash = leash;
|
||||
mRootOffset.set(offsetLeft, offsetTop);
|
||||
/** @see #getRoot */
|
||||
public void addRootLeash(int displayId, @NonNull SurfaceControl leash,
|
||||
int offsetLeft, int offsetTop) {
|
||||
mRoots.add(new Root(displayId, leash, offsetLeft, offsetTop));
|
||||
}
|
||||
|
||||
/** @see #getRoot */
|
||||
public void addRoot(Root other) {
|
||||
mRoots.add(other);
|
||||
}
|
||||
|
||||
public void setAnimationOptions(AnimationOptions options) {
|
||||
@@ -256,24 +257,53 @@ public final class TransitionInfo implements Parcelable {
|
||||
return mFlags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The number of animation roots. Most transitions should have 1, but there may be more
|
||||
* in some cases (such as a transition spanning multiple displays).
|
||||
*/
|
||||
public int getRootCount() {
|
||||
return mRoots.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the transition-root at a specific index.
|
||||
*/
|
||||
@NonNull
|
||||
public Root getRoot(int idx) {
|
||||
return mRoots.get(idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the index of the transition-root associated with `displayId` or -1 if not found.
|
||||
*/
|
||||
public int findRootIndex(int displayId) {
|
||||
for (int i = 0; i < mRoots.size(); ++i) {
|
||||
if (mRoots.get(i).mDisplayId == displayId) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a surfacecontrol that can serve as a parent surfacecontrol for all the changing
|
||||
* participants to animate within. This will generally be placed at the highest-z-order
|
||||
* shared ancestor of all participants. While this is non-null, it's possible for the rootleash
|
||||
* to be invalid if the transition is a no-op.
|
||||
*
|
||||
* @deprecated Use {@link #getRoot} instead. This call assumes there is only one root.
|
||||
*/
|
||||
@Deprecated
|
||||
@NonNull
|
||||
public SurfaceControl getRootLeash() {
|
||||
if (mRootLeash == null) {
|
||||
throw new IllegalStateException("Trying to get a leash which wasn't set");
|
||||
if (mRoots.isEmpty()) {
|
||||
throw new IllegalStateException("Trying to get a root leash from a no-op transition.");
|
||||
}
|
||||
return mRootLeash;
|
||||
}
|
||||
|
||||
/** @return the offset (relative to the screen) of the root leash. */
|
||||
@NonNull
|
||||
public Point getRootOffset() {
|
||||
return mRootOffset;
|
||||
if (mRoots.size() > 1) {
|
||||
android.util.Log.e(TAG, "Assuming one animation root when there are more.",
|
||||
new Throwable());
|
||||
}
|
||||
return mRoots.get(0).mLeash;
|
||||
}
|
||||
|
||||
public AnimationOptions getAnimationOptions() {
|
||||
@@ -320,8 +350,15 @@ public final class TransitionInfo implements Parcelable {
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("{t=" + transitTypeToString(mType) + " f=0x" + Integer.toHexString(mFlags)
|
||||
+ " ro=" + mRootOffset + " c=[");
|
||||
sb.append("{t=").append(transitTypeToString(mType)).append(" f=0x")
|
||||
.append(Integer.toHexString(mFlags)).append(" r=[");
|
||||
for (int i = 0; i < mRoots.size(); ++i) {
|
||||
if (i > 0) {
|
||||
sb.append(',');
|
||||
}
|
||||
sb.append(mRoots.get(i).mDisplayId).append("@").append(mRoots.get(i).mOffset);
|
||||
}
|
||||
sb.append("] c=[");
|
||||
for (int i = 0; i < mChanges.size(); ++i) {
|
||||
if (i > 0) {
|
||||
sb.append(',');
|
||||
@@ -448,8 +485,8 @@ public final class TransitionInfo implements Parcelable {
|
||||
c.mSnapshot = null;
|
||||
}
|
||||
}
|
||||
if (mRootLeash != null) {
|
||||
mRootLeash.release();
|
||||
for (int i = 0; i < mRoots.size(); ++i) {
|
||||
mRoots.get(i).mLeash.release();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -476,10 +513,11 @@ public final class TransitionInfo implements Parcelable {
|
||||
for (int i = 0; i < mChanges.size(); ++i) {
|
||||
out.mChanges.add(mChanges.get(i).localRemoteCopy());
|
||||
}
|
||||
out.mRootLeash = mRootLeash != null ? new SurfaceControl(mRootLeash, "localRemote") : null;
|
||||
for (int i = 0; i < mRoots.size(); ++i) {
|
||||
out.mRoots.add(mRoots.get(i).localRemoteCopy());
|
||||
}
|
||||
// Doesn't have any native stuff, so no need for actual copy
|
||||
out.mOptions = mOptions;
|
||||
out.mRootOffset.set(mRootOffset);
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -496,6 +534,8 @@ public final class TransitionInfo implements Parcelable {
|
||||
private final Point mEndRelOffset = new Point();
|
||||
private ActivityManager.RunningTaskInfo mTaskInfo = null;
|
||||
private boolean mAllowEnterPip;
|
||||
private int mStartDisplayId = INVALID_DISPLAY;
|
||||
private int mEndDisplayId = INVALID_DISPLAY;
|
||||
private @Surface.Rotation int mStartRotation = ROTATION_UNDEFINED;
|
||||
private @Surface.Rotation int mEndRotation = ROTATION_UNDEFINED;
|
||||
/**
|
||||
@@ -526,6 +566,8 @@ public final class TransitionInfo implements Parcelable {
|
||||
mEndRelOffset.readFromParcel(in);
|
||||
mTaskInfo = in.readTypedObject(ActivityManager.RunningTaskInfo.CREATOR);
|
||||
mAllowEnterPip = in.readBoolean();
|
||||
mStartDisplayId = in.readInt();
|
||||
mEndDisplayId = in.readInt();
|
||||
mStartRotation = in.readInt();
|
||||
mEndRotation = in.readInt();
|
||||
mEndFixedRotation = in.readInt();
|
||||
@@ -546,6 +588,8 @@ public final class TransitionInfo implements Parcelable {
|
||||
out.mEndRelOffset.set(mEndRelOffset);
|
||||
out.mTaskInfo = mTaskInfo;
|
||||
out.mAllowEnterPip = mAllowEnterPip;
|
||||
out.mStartDisplayId = mStartDisplayId;
|
||||
out.mEndDisplayId = mEndDisplayId;
|
||||
out.mStartRotation = mStartRotation;
|
||||
out.mEndRotation = mEndRotation;
|
||||
out.mEndFixedRotation = mEndFixedRotation;
|
||||
@@ -607,6 +651,12 @@ public final class TransitionInfo implements Parcelable {
|
||||
mAllowEnterPip = allowEnterPip;
|
||||
}
|
||||
|
||||
/** Sets the start and end rotation of this container. */
|
||||
public void setDisplayId(int start, int end) {
|
||||
mStartDisplayId = start;
|
||||
mEndDisplayId = end;
|
||||
}
|
||||
|
||||
/** Sets the start and end rotation of this container. */
|
||||
public void setRotation(@Surface.Rotation int start, @Surface.Rotation int end) {
|
||||
mStartRotation = start;
|
||||
@@ -725,6 +775,14 @@ public final class TransitionInfo implements Parcelable {
|
||||
return mAllowEnterPip;
|
||||
}
|
||||
|
||||
public int getStartDisplayId() {
|
||||
return mStartDisplayId;
|
||||
}
|
||||
|
||||
public int getEndDisplayId() {
|
||||
return mEndDisplayId;
|
||||
}
|
||||
|
||||
@Surface.Rotation
|
||||
public int getStartRotation() {
|
||||
return mStartRotation;
|
||||
@@ -776,6 +834,8 @@ public final class TransitionInfo implements Parcelable {
|
||||
mEndRelOffset.writeToParcel(dest, flags);
|
||||
dest.writeTypedObject(mTaskInfo, flags);
|
||||
dest.writeBoolean(mAllowEnterPip);
|
||||
dest.writeInt(mStartDisplayId);
|
||||
dest.writeInt(mEndDisplayId);
|
||||
dest.writeInt(mStartRotation);
|
||||
dest.writeInt(mEndRotation);
|
||||
dest.writeInt(mEndFixedRotation);
|
||||
@@ -822,6 +882,11 @@ public final class TransitionInfo implements Parcelable {
|
||||
if (mEndRelOffset.x != 0 || mEndRelOffset.y != 0) {
|
||||
sb.append(" eo="); sb.append(mEndRelOffset);
|
||||
}
|
||||
sb.append(" d=");
|
||||
if (mStartDisplayId != mEndDisplayId) {
|
||||
sb.append(mStartDisplayId).append("->");
|
||||
}
|
||||
sb.append(mEndDisplayId);
|
||||
if (mStartRotation != mEndRotation) {
|
||||
sb.append(" r="); sb.append(mStartRotation);
|
||||
sb.append("->"); sb.append(mEndRotation);
|
||||
@@ -1108,4 +1173,86 @@ public final class TransitionInfo implements Parcelable {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An animation root in a transition. There is one of these for each display that contains
|
||||
* participants. It will be placed, in z-order, right above the top-most participant and at the
|
||||
* same position in the hierarchy. As a result, if all participants are animating within a
|
||||
* part of the screen, the root-leash will only be in that part of the screen. In these cases,
|
||||
* it's relative position (from the screen) is stored in {@link Root#getOffset}.
|
||||
*/
|
||||
public static final class Root implements Parcelable {
|
||||
private final int mDisplayId;
|
||||
private final SurfaceControl mLeash;
|
||||
private final Point mOffset = new Point();
|
||||
|
||||
public Root(int displayId, @NonNull SurfaceControl leash, int offsetLeft, int offsetTop) {
|
||||
mDisplayId = displayId;
|
||||
mLeash = leash;
|
||||
mOffset.set(offsetLeft, offsetTop);
|
||||
}
|
||||
|
||||
private Root(Parcel in) {
|
||||
mDisplayId = in.readInt();
|
||||
mLeash = new SurfaceControl();
|
||||
mLeash.readFromParcel(in);
|
||||
mLeash.setUnreleasedWarningCallSite("TransitionInfo.Root");
|
||||
mOffset.readFromParcel(in);
|
||||
}
|
||||
|
||||
private Root localRemoteCopy() {
|
||||
return new Root(mDisplayId, new SurfaceControl(mLeash, "localRemote"),
|
||||
mOffset.x, mOffset.y);
|
||||
}
|
||||
|
||||
/** @return the id of the display this root is on. */
|
||||
public int getDisplayId() {
|
||||
return mDisplayId;
|
||||
}
|
||||
|
||||
/** @return the root's leash. Surfaces should be parented to this while animating. */
|
||||
@NonNull
|
||||
public SurfaceControl getLeash() {
|
||||
return mLeash;
|
||||
}
|
||||
|
||||
/** @return the offset (relative to its screen) of the root leash. */
|
||||
@NonNull
|
||||
public Point getOffset() {
|
||||
return mOffset;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeInt(mDisplayId);
|
||||
mLeash.writeToParcel(dest, flags);
|
||||
mOffset.writeToParcel(dest, flags);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static final Creator<Root> CREATOR =
|
||||
new Creator<Root>() {
|
||||
@Override
|
||||
public Root createFromParcel(Parcel in) {
|
||||
return new Root(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Root[] newArray(int size) {
|
||||
return new Root[size];
|
||||
}
|
||||
};
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return mDisplayId + "@" + mOffset + ":" + mLeash;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -489,10 +489,11 @@ public class PipTransition extends PipTransitionController {
|
||||
// Reparent the pip leash to the root with max layer so that we can animate it outside of
|
||||
// parent crop, and make sure it is not covered by other windows.
|
||||
final SurfaceControl pipLeash = pipChange.getLeash();
|
||||
startTransaction.reparent(pipLeash, info.getRootLeash());
|
||||
final int rootIdx = TransitionUtil.rootIndexFor(pipChange, info);
|
||||
startTransaction.reparent(pipLeash, info.getRoot(rootIdx).getLeash());
|
||||
startTransaction.setLayer(pipLeash, Integer.MAX_VALUE);
|
||||
// Note: because of this, the bounds to animate should be translated to the root coordinate.
|
||||
final Point offset = info.getRootOffset();
|
||||
final Point offset = info.getRoot(rootIdx).getOffset();
|
||||
final Rect currentBounds = mPipBoundsState.getBounds();
|
||||
currentBounds.offset(-offset.x, -offset.y);
|
||||
startTransaction.setPosition(pipLeash, currentBounds.left, currentBounds.top);
|
||||
|
||||
@@ -37,6 +37,7 @@ import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.os.IBinder;
|
||||
import android.view.SurfaceControl;
|
||||
@@ -128,6 +129,7 @@ class SplitScreenTransitions {
|
||||
final int mode = info.getChanges().get(i).getMode();
|
||||
|
||||
if (mode == TRANSIT_CHANGE) {
|
||||
final int rootIdx = TransitionUtil.rootIndexFor(change, info);
|
||||
if (change.getParent() != null) {
|
||||
// This is probably reparented, so we want the parent to be immediately visible
|
||||
final TransitionInfo.Change parentChange = info.getChange(change.getParent());
|
||||
@@ -135,7 +137,7 @@ class SplitScreenTransitions {
|
||||
t.setAlpha(parentChange.getLeash(), 1.f);
|
||||
// and then animate this layer outside the parent (since, for example, this is
|
||||
// the home task animating from fullscreen to part-screen).
|
||||
t.reparent(leash, info.getRootLeash());
|
||||
t.reparent(leash, info.getRoot(rootIdx).getLeash());
|
||||
t.setLayer(leash, info.getChanges().size() - i);
|
||||
// build the finish reparent/reposition
|
||||
mFinishTransaction.reparent(leash, parentChange.getLeash());
|
||||
@@ -145,8 +147,9 @@ class SplitScreenTransitions {
|
||||
// TODO(shell-transitions): screenshot here
|
||||
final Rect startBounds = new Rect(change.getStartAbsBounds());
|
||||
final Rect endBounds = new Rect(change.getEndAbsBounds());
|
||||
startBounds.offset(-info.getRootOffset().x, -info.getRootOffset().y);
|
||||
endBounds.offset(-info.getRootOffset().x, -info.getRootOffset().y);
|
||||
final Point rootOffset = info.getRoot(rootIdx).getOffset();
|
||||
startBounds.offset(-rootOffset.x, -rootOffset.y);
|
||||
endBounds.offset(-rootOffset.x, -rootOffset.y);
|
||||
startExampleResizeAnimation(leash, startBounds, endBounds);
|
||||
}
|
||||
boolean isRootOrSplitSideRoot = change.getParent() == null
|
||||
|
||||
@@ -179,7 +179,9 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler {
|
||||
out.getChanges().add(info.getChanges().get(i));
|
||||
}
|
||||
}
|
||||
out.setRootLeash(info.getRootLeash(), info.getRootOffset().x, info.getRootOffset().y);
|
||||
for (int i = 0; i < info.getRootCount(); ++i) {
|
||||
out.addRoot(info.getRoot(i));
|
||||
}
|
||||
out.setAnimationOptions(info.getAnimationOptions());
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -383,9 +383,10 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
|
||||
continue;
|
||||
}
|
||||
// No default animation for this, so just update bounds/position.
|
||||
final int rootIdx = TransitionUtil.rootIndexFor(change, info);
|
||||
startTransaction.setPosition(change.getLeash(),
|
||||
change.getEndAbsBounds().left - info.getRootOffset().x,
|
||||
change.getEndAbsBounds().top - info.getRootOffset().y);
|
||||
change.getEndAbsBounds().left - info.getRoot(rootIdx).getOffset().x,
|
||||
change.getEndAbsBounds().top - info.getRoot(rootIdx).getOffset().y);
|
||||
// Seamless display transition doesn't need to animate.
|
||||
if (isSeamlessDisplayChange) continue;
|
||||
if (isTask || (change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY)
|
||||
@@ -474,8 +475,10 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
|
||||
}
|
||||
|
||||
if (backgroundColorForTransition != 0) {
|
||||
addBackgroundToTransition(info.getRootLeash(), backgroundColorForTransition,
|
||||
startTransaction, finishTransaction);
|
||||
for (int i = 0; i < info.getRootCount(); ++i) {
|
||||
addBackgroundToTransition(info.getRoot(i).getLeash(), backgroundColorForTransition,
|
||||
startTransaction, finishTransaction);
|
||||
}
|
||||
}
|
||||
|
||||
if (postStartTransactionCallbacks.size() > 0) {
|
||||
@@ -520,8 +523,10 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
|
||||
private void startRotationAnimation(SurfaceControl.Transaction startTransaction,
|
||||
TransitionInfo.Change change, TransitionInfo info, int animHint,
|
||||
ArrayList<Animator> animations, Runnable onAnimFinish) {
|
||||
final int rootIdx = TransitionUtil.rootIndexFor(change, info);
|
||||
final ScreenRotationAnimation anim = new ScreenRotationAnimation(mContext, mSurfaceSession,
|
||||
mTransactionPool, startTransaction, change, info.getRootLeash(), animHint);
|
||||
mTransactionPool, startTransaction, change, info.getRoot(rootIdx).getLeash(),
|
||||
animHint);
|
||||
// The rotation animation may consist of 3 animations: fade-out screenshot, fade-in real
|
||||
// content, and background color. The item of "animGroup" will be removed if the sub
|
||||
// animation is finished. Then if the list becomes empty, the rotation animation is done.
|
||||
|
||||
@@ -75,6 +75,7 @@ import com.android.wm.shell.common.annotations.ExternalThread;
|
||||
import com.android.wm.shell.protolog.ShellProtoLogGroup;
|
||||
import com.android.wm.shell.sysui.ShellController;
|
||||
import com.android.wm.shell.sysui.ShellInit;
|
||||
import com.android.wm.shell.util.TransitionUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -415,8 +416,8 @@ public class Transitions implements RemoteCallable<Transitions> {
|
||||
private static void setupAnimHierarchy(@NonNull TransitionInfo info,
|
||||
@NonNull SurfaceControl.Transaction t, @NonNull SurfaceControl.Transaction finishT) {
|
||||
boolean isOpening = isOpeningType(info.getType());
|
||||
if (info.getRootLeash().isValid()) {
|
||||
t.show(info.getRootLeash());
|
||||
for (int i = 0; i < info.getRootCount(); ++i) {
|
||||
t.show(info.getRoot(i).getLeash());
|
||||
}
|
||||
final int numChanges = info.getChanges().size();
|
||||
// Put animating stuff above this line and put static stuff below it.
|
||||
@@ -434,10 +435,12 @@ public class Transitions implements RemoteCallable<Transitions> {
|
||||
|
||||
boolean hasParent = change.getParent() != null;
|
||||
|
||||
final int rootIdx = TransitionUtil.rootIndexFor(change, info);
|
||||
if (!hasParent) {
|
||||
t.reparent(leash, info.getRootLeash());
|
||||
t.setPosition(leash, change.getStartAbsBounds().left - info.getRootOffset().x,
|
||||
change.getStartAbsBounds().top - info.getRootOffset().y);
|
||||
t.reparent(leash, info.getRoot(rootIdx).getLeash());
|
||||
t.setPosition(leash,
|
||||
change.getStartAbsBounds().left - info.getRoot(rootIdx).getOffset().x,
|
||||
change.getStartAbsBounds().top - info.getRoot(rootIdx).getOffset().y);
|
||||
}
|
||||
final int layer;
|
||||
// Put all the OPEN/SHOW on top
|
||||
@@ -532,12 +535,6 @@ public class Transitions implements RemoteCallable<Transitions> {
|
||||
|
||||
if (info.getType() == TRANSIT_SLEEP) {
|
||||
if (activeIdx > 0) {
|
||||
if (!info.getRootLeash().isValid()) {
|
||||
// Shell has some debug settings which makes calling binders with invalid
|
||||
// surfaces crash, so replace it with a "real" one.
|
||||
info.setRootLeash(new SurfaceControl.Builder().setName("Invalid")
|
||||
.setContainerLayer().build(), 0, 0);
|
||||
}
|
||||
// Sleep starts a process of forcing all prior transitions to finish immediately
|
||||
finishForSleep(null /* forceFinish */);
|
||||
return;
|
||||
@@ -546,10 +543,10 @@ public class Transitions implements RemoteCallable<Transitions> {
|
||||
|
||||
// Allow to notify keyguard un-occluding state to KeyguardService, which can happen while
|
||||
// screen-off, so there might no visibility change involved.
|
||||
if (!info.getRootLeash().isValid() && info.getType() != TRANSIT_KEYGUARD_UNOCCLUDE) {
|
||||
// Invalid root-leash implies that the transition is empty/no-op, so just do
|
||||
if (info.getRootCount() == 0 && info.getType() != TRANSIT_KEYGUARD_UNOCCLUDE) {
|
||||
// No root-leashes implies that the transition is empty/no-op, so just do
|
||||
// housekeeping and return.
|
||||
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Invalid root leash (%s): %s",
|
||||
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "No transition roots (%s): %s",
|
||||
transitionToken, info);
|
||||
onAbort(active);
|
||||
return;
|
||||
|
||||
@@ -139,11 +139,12 @@ public class TransitionUtil {
|
||||
// changes should be ordered top-to-bottom in z
|
||||
final int mode = change.getMode();
|
||||
|
||||
t.reparent(leash, info.getRootLeash());
|
||||
final int rootIdx = TransitionUtil.rootIndexFor(change, info);
|
||||
t.reparent(leash, info.getRoot(rootIdx).getLeash());
|
||||
final Rect absBounds =
|
||||
(mode == TRANSIT_OPEN) ? change.getEndAbsBounds() : change.getStartAbsBounds();
|
||||
t.setPosition(leash, absBounds.left - info.getRootOffset().x,
|
||||
absBounds.top - info.getRootOffset().y);
|
||||
t.setPosition(leash, absBounds.left - info.getRoot(rootIdx).getOffset().x,
|
||||
absBounds.top - info.getRoot(rootIdx).getOffset().y);
|
||||
|
||||
// Put all the OPEN/SHOW on top
|
||||
if (TransitionUtil.isOpeningType(mode)) {
|
||||
@@ -179,12 +180,13 @@ public class TransitionUtil {
|
||||
// making leashes means we have to handle them specially.
|
||||
return change.getLeash();
|
||||
}
|
||||
final int rootIdx = TransitionUtil.rootIndexFor(change, info);
|
||||
SurfaceControl leashSurface = new SurfaceControl.Builder()
|
||||
.setName(change.getLeash().toString() + "_transition-leash")
|
||||
.setContainerLayer()
|
||||
// Initial the surface visible to respect the visibility of the original surface.
|
||||
.setHidden(false)
|
||||
.setParent(info.getRootLeash())
|
||||
.setParent(info.getRoot(rootIdx).getLeash())
|
||||
.build();
|
||||
// Copied Transitions setup code (which expects bottom-to-top order, so we swap here)
|
||||
setupLeash(leashSurface, change, info.getChanges().size() - order, info, t);
|
||||
@@ -261,4 +263,18 @@ public class TransitionUtil {
|
||||
target.setRotationChange(change.getEndRotation() - change.getStartRotation());
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the "correct" root idx for a change. The change's end display is prioritized, then
|
||||
* the start display. If there is no display, it will fallback on the 0th root in the
|
||||
* transition. There MUST be at-least 1 root in the transition (ie. it's not a no-op).
|
||||
*/
|
||||
public static int rootIndexFor(@NonNull TransitionInfo.Change change,
|
||||
@NonNull TransitionInfo info) {
|
||||
int rootIdx = info.findRootIndex(change.getEndDisplayId());
|
||||
if (rootIdx >= 0) return rootIdx;
|
||||
rootIdx = info.findRootIndex(change.getStartDisplayId());
|
||||
if (rootIdx >= 0) return rootIdx;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import android.window.TransitionInfo;
|
||||
*/
|
||||
public class TransitionInfoBuilder {
|
||||
final TransitionInfo mInfo;
|
||||
static final int DISPLAY_ID = 0;
|
||||
|
||||
public TransitionInfoBuilder(@WindowManager.TransitionType int type) {
|
||||
this(type, 0 /* flags */);
|
||||
@@ -38,7 +39,7 @@ public class TransitionInfoBuilder {
|
||||
public TransitionInfoBuilder(@WindowManager.TransitionType int type,
|
||||
@WindowManager.TransitionFlags int flags) {
|
||||
mInfo = new TransitionInfo(type, flags);
|
||||
mInfo.setRootLeash(createMockSurface(true /* valid */), 0, 0);
|
||||
mInfo.addRootLeash(DISPLAY_ID, createMockSurface(true /* valid */), 0, 0);
|
||||
}
|
||||
|
||||
public TransitionInfoBuilder addChange(@WindowManager.TransitionType int mode,
|
||||
@@ -61,6 +62,7 @@ public class TransitionInfoBuilder {
|
||||
}
|
||||
|
||||
public TransitionInfoBuilder addChange(TransitionInfo.Change change) {
|
||||
change.setDisplayId(DISPLAY_ID, DISPLAY_ID);
|
||||
mInfo.addChange(change);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -59,12 +59,14 @@ class RemoteTransitionAdapter {
|
||||
// changes should be ordered top-to-bottom in z
|
||||
val mode = change.mode
|
||||
|
||||
var rootIdx = info.findRootIndex(change.endDisplayId)
|
||||
if (rootIdx < 0) rootIdx = 0
|
||||
// Launcher animates leaf tasks directly, so always reparent all task leashes to root.
|
||||
t.reparent(leash, info.rootLeash)
|
||||
t.reparent(leash, info.getRoot(rootIdx).leash)
|
||||
t.setPosition(
|
||||
leash,
|
||||
(change.startAbsBounds.left - info.rootOffset.x).toFloat(),
|
||||
(change.startAbsBounds.top - info.rootOffset.y).toFloat()
|
||||
(change.startAbsBounds.left - info.getRoot(rootIdx).offset.x).toFloat(),
|
||||
(change.startAbsBounds.top - info.getRoot(rootIdx).offset.y).toFloat()
|
||||
)
|
||||
t.show(leash)
|
||||
// Put all the OPEN/SHOW on top
|
||||
@@ -114,8 +116,11 @@ class RemoteTransitionAdapter {
|
||||
.setName(change.leash.toString() + "_transition-leash")
|
||||
.setContainerLayer()
|
||||
.setParent(
|
||||
if (change.parent == null) info.rootLeash
|
||||
else info.getChange(change.parent!!)!!.leash
|
||||
if (change.parent == null) {
|
||||
var rootIdx = info.findRootIndex(change.endDisplayId)
|
||||
if (rootIdx < 0) rootIdx = 0
|
||||
info.getRoot(rootIdx).leash
|
||||
} else info.getChange(change.parent!!)!!.leash
|
||||
)
|
||||
.build()
|
||||
// Copied Transitions setup code (which expects bottom-to-top order, so we swap here)
|
||||
|
||||
@@ -321,7 +321,9 @@ public class RemoteTransitionCompat {
|
||||
} else {
|
||||
// We are receiving new opening tasks, so convert to onTasksAppeared.
|
||||
targets[i] = TransitionUtil.newTarget(change, layer, info, t, mLeashMap);
|
||||
t.reparent(targets[i].leash, mInfo.getRootLeash());
|
||||
// reparent into the original `mInfo` since that's where we are animating.
|
||||
final int rootIdx = TransitionUtil.rootIndexFor(change, mInfo);
|
||||
t.reparent(targets[i].leash, mInfo.getRoot(rootIdx).getLeash());
|
||||
t.setLayer(targets[i].leash, layer);
|
||||
mOpeningTasks.add(new TaskState(change, targets[i].leash));
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ public class RemoteTransitionTest extends SysuiTestCase {
|
||||
|
||||
TransitionInfoBuilder(@WindowManager.TransitionType int type) {
|
||||
mInfo = new TransitionInfo(type, 0 /* flags */);
|
||||
mInfo.setRootLeash(createMockSurface(true /* valid */), 0, 0);
|
||||
mInfo.addRootLeash(0, createMockSurface(true /* valid */), 0, 0);
|
||||
}
|
||||
|
||||
TransitionInfoBuilder addChange(@WindowManager.TransitionType int mode,
|
||||
@@ -144,6 +144,7 @@ public class RemoteTransitionTest extends SysuiTestCase {
|
||||
change.setMode(mode);
|
||||
change.setFlags(flags);
|
||||
change.setTaskInfo(taskInfo);
|
||||
change.setDisplayId(0, 0);
|
||||
mInfo.addChange(change);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -675,7 +675,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
|
||||
* needs to be passed/applied in shell because until finish is called, shell owns the surfaces.
|
||||
* Additionally, this gives shell the ability to better deal with merged transitions.
|
||||
*/
|
||||
private void buildFinishTransaction(SurfaceControl.Transaction t, SurfaceControl rootLeash) {
|
||||
private void buildFinishTransaction(SurfaceControl.Transaction t, TransitionInfo info) {
|
||||
final Point tmpPos = new Point();
|
||||
// usually only size 1
|
||||
final ArraySet<DisplayContent> displays = new ArraySet<>();
|
||||
@@ -728,8 +728,8 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
|
||||
} finally {
|
||||
mController.mBuildingFinishLayers = false;
|
||||
}
|
||||
if (rootLeash.isValid()) {
|
||||
t.reparent(rootLeash, null);
|
||||
for (int i = 0; i < info.getRootCount(); ++i) {
|
||||
t.reparent(info.getRoot(i).getLeash(), null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1066,13 +1066,6 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
|
||||
Slog.e(TAG, "Unexpected Sync ID " + syncId + ". Expected " + mSyncId);
|
||||
return;
|
||||
}
|
||||
if (mTargetDisplays.isEmpty()) {
|
||||
mTargetDisplays.add(mController.mAtm.mRootWindowContainer.getDefaultDisplay());
|
||||
}
|
||||
// While there can be multiple DC's involved. For now, we just use the first one as
|
||||
// the "primary" one for most things. Eventually, this will need to change, but, for the
|
||||
// time being, we don't have full cross-display transitions so it isn't a problem.
|
||||
final DisplayContent dc = mTargetDisplays.get(0);
|
||||
|
||||
// Commit the visibility of visible activities before calculateTransitionInfo(), so the
|
||||
// TaskInfo can be visible. Also it needs to be done before moveToPlaying(), otherwise
|
||||
@@ -1082,6 +1075,9 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
|
||||
|
||||
if (mState == STATE_ABORT) {
|
||||
mController.abort(this);
|
||||
// Fall-back to the default display if there isn't one participating.
|
||||
final DisplayContent dc = !mTargetDisplays.isEmpty() ? mTargetDisplays.get(0)
|
||||
: mController.mAtm.mRootWindowContainer.getDefaultDisplay();
|
||||
dc.getPendingTransaction().merge(transaction);
|
||||
mSyncId = -1;
|
||||
mOverrideOptions = null;
|
||||
@@ -1094,16 +1090,24 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
|
||||
mFinishTransaction = mController.mAtm.mWindowManager.mTransactionFactory.get();
|
||||
mController.moveToPlaying(this);
|
||||
|
||||
if (dc.isKeyguardLocked()) {
|
||||
mFlags |= TRANSIT_FLAG_KEYGUARD_LOCKED;
|
||||
}
|
||||
|
||||
// Check whether the participants were animated from back navigation.
|
||||
final boolean markBackAnimated = mController.mAtm.mBackNavigationController
|
||||
.containsBackAnimationTargets(this);
|
||||
// Resolve the animating targets from the participants
|
||||
// Resolve the animating targets from the participants.
|
||||
mTargets = calculateTargets(mParticipants, mChanges);
|
||||
final TransitionInfo info = calculateTransitionInfo(mType, mFlags, mTargets, transaction);
|
||||
|
||||
// Repopulate the displays based on the resolved targets.
|
||||
mTargetDisplays.clear();
|
||||
for (int i = 0; i < info.getRootCount(); ++i) {
|
||||
final DisplayContent dc = mController.mAtm.mRootWindowContainer.getDisplayContent(
|
||||
info.getRoot(i).getDisplayId());
|
||||
mTargetDisplays.add(dc);
|
||||
if (dc.isKeyguardLocked()) {
|
||||
mFlags |= TRANSIT_FLAG_KEYGUARD_LOCKED;
|
||||
}
|
||||
}
|
||||
|
||||
if (markBackAnimated) {
|
||||
mController.mAtm.mBackNavigationController.clearBackAnimations(mStartTransaction);
|
||||
}
|
||||
@@ -1125,9 +1129,12 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
|
||||
}
|
||||
|
||||
// TODO(b/188669821): Move to animation impl in shell.
|
||||
handleLegacyRecentsStartBehavior(dc, info);
|
||||
for (int i = 0; i < mTargetDisplays.size(); ++i) {
|
||||
handleLegacyRecentsStartBehavior(mTargetDisplays.get(i), info);
|
||||
if (mRecentsDisplayId != INVALID_DISPLAY) break;
|
||||
}
|
||||
|
||||
handleNonAppWindowsInTransition(dc, mType, mFlags);
|
||||
handleNonAppWindowsInTransition(mType, mFlags);
|
||||
|
||||
// The callback is only populated for custom activity-level client animations
|
||||
sendRemoteCallback(mClientAnimationStartCallback);
|
||||
@@ -1191,11 +1198,14 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
|
||||
|
||||
// This is non-null only if display has changes. It handles the visible windows that don't
|
||||
// need to be participated in the transition.
|
||||
final AsyncRotationController controller = dc.getAsyncRotationController();
|
||||
if (controller != null && containsChangeFor(dc, mTargets)) {
|
||||
controller.setupStartTransaction(transaction);
|
||||
for (int i = 0; i < mTargetDisplays.size(); ++i) {
|
||||
final DisplayContent dc = mTargetDisplays.get(i);
|
||||
final AsyncRotationController controller = dc.getAsyncRotationController();
|
||||
if (controller != null && containsChangeFor(dc, mTargets)) {
|
||||
controller.setupStartTransaction(transaction);
|
||||
}
|
||||
}
|
||||
buildFinishTransaction(mFinishTransaction, info.getRootLeash());
|
||||
buildFinishTransaction(mFinishTransaction, info);
|
||||
if (mController.getTransitionPlayer() != null && mIsPlayerEnabled) {
|
||||
mController.dispatchLegacyAppTransitionStarting(info, mStatusBarTransitionDelay);
|
||||
try {
|
||||
@@ -1216,10 +1226,13 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
|
||||
// client, we should finish and apply it here so the transactions aren't lost.
|
||||
postCleanupOnFailure();
|
||||
}
|
||||
final AccessibilityController accessibilityController =
|
||||
dc.mWmService.mAccessibilityController;
|
||||
if (accessibilityController.hasCallbacks()) {
|
||||
accessibilityController.onWMTransition(dc.getDisplayId(), mType);
|
||||
for (int i = 0; i < mTargetDisplays.size(); ++i) {
|
||||
final DisplayContent dc = mTargetDisplays.get(i);
|
||||
final AccessibilityController accessibilityController =
|
||||
dc.mWmService.mAccessibilityController;
|
||||
if (accessibilityController.hasCallbacks()) {
|
||||
accessibilityController.onWMTransition(dc.getDisplayId(), mType);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No player registered or it's not enabled, so just finish/apply immediately
|
||||
@@ -1296,16 +1309,15 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
|
||||
if ((mFlags & TRANSIT_FLAG_IS_RECENTS) == 0) {
|
||||
return;
|
||||
}
|
||||
mRecentsDisplayId = dc.mDisplayId;
|
||||
|
||||
// Recents has an input-consumer to grab input from the "live tile" app. Set that up here
|
||||
final InputConsumerImpl recentsAnimationInputConsumer =
|
||||
dc.getInputMonitor().getInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION);
|
||||
ActivityRecord recentsActivity = null;
|
||||
if (recentsAnimationInputConsumer != null) {
|
||||
// find the top-most going-away activity and the recents activity. The top-most
|
||||
// is used as layer reference while the recents is used for registering the consumer
|
||||
// override.
|
||||
ActivityRecord recentsActivity = null;
|
||||
ActivityRecord topActivity = null;
|
||||
for (int i = 0; i < info.getChanges().size(); ++i) {
|
||||
final TransitionInfo.Change change = info.getChanges().get(i);
|
||||
@@ -1329,6 +1341,12 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
|
||||
}
|
||||
}
|
||||
|
||||
if (recentsActivity == null) {
|
||||
// No recents activity on `dc`, its probably on a different display.
|
||||
return;
|
||||
}
|
||||
mRecentsDisplayId = dc.mDisplayId;
|
||||
|
||||
// The rest of this function handles nav-bar reparenting
|
||||
|
||||
if (!dc.getDisplayPolicy().shouldAttachNavBarToAppDuringTransition()
|
||||
@@ -1423,7 +1441,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
|
||||
}
|
||||
}
|
||||
|
||||
private void handleNonAppWindowsInTransition(@NonNull DisplayContent dc,
|
||||
private void handleNonAppWindowsInTransition(
|
||||
@TransitionType int transit, @TransitionFlags int flags) {
|
||||
if ((flags & TRANSIT_FLAG_KEYGUARD_LOCKED) != 0) {
|
||||
// If the occlusion changed but the transition isn't an occlude/unocclude transition,
|
||||
@@ -1801,6 +1819,41 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
|
||||
return wc instanceof DisplayContent;
|
||||
}
|
||||
|
||||
private static int getDisplayId(@NonNull WindowContainer wc) {
|
||||
return wc.getDisplayContent() != null
|
||||
? wc.getDisplayContent().getDisplayId() : INVALID_DISPLAY;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static void calculateTransitionRoots(@NonNull TransitionInfo outInfo,
|
||||
ArrayList<ChangeInfo> sortedTargets,
|
||||
@NonNull SurfaceControl.Transaction startT) {
|
||||
// There needs to be a root on each display.
|
||||
for (int i = 0; i < sortedTargets.size(); ++i) {
|
||||
final WindowContainer<?> wc = sortedTargets.get(i).mContainer;
|
||||
// Don't include wallpapers since they are in a different DA.
|
||||
if (isWallpaper(wc)) continue;
|
||||
final int endDisplayId = getDisplayId(wc);
|
||||
if (endDisplayId < 0) continue;
|
||||
|
||||
// Check if Root was already created for this display with a higher-Z window
|
||||
if (outInfo.findRootIndex(endDisplayId) >= 0) continue;
|
||||
|
||||
WindowContainer<?> ancestor = findCommonAncestor(sortedTargets, wc);
|
||||
|
||||
// Make leash based on highest (z-order) direct child of ancestor with a participant.
|
||||
WindowContainer leashReference = wc;
|
||||
while (leashReference.getParent() != ancestor) {
|
||||
leashReference = leashReference.getParent();
|
||||
}
|
||||
final SurfaceControl rootLeash = leashReference.makeAnimationLeash().setName(
|
||||
"Transition Root: " + leashReference.getName()).build();
|
||||
startT.setLayer(rootLeash, leashReference.getLastLayer());
|
||||
outInfo.addRootLeash(endDisplayId, rootLeash,
|
||||
ancestor.getBounds().left, ancestor.getBounds().top);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a TransitionInfo object from a set of targets and changes. Also populates the
|
||||
* root surface.
|
||||
@@ -1811,37 +1864,13 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
|
||||
@NonNull
|
||||
static TransitionInfo calculateTransitionInfo(@TransitionType int type, int flags,
|
||||
ArrayList<ChangeInfo> sortedTargets,
|
||||
@Nullable SurfaceControl.Transaction startT) {
|
||||
@NonNull SurfaceControl.Transaction startT) {
|
||||
final TransitionInfo out = new TransitionInfo(type, flags);
|
||||
|
||||
WindowContainer<?> topApp = null;
|
||||
for (int i = 0; i < sortedTargets.size(); i++) {
|
||||
final WindowContainer<?> wc = sortedTargets.get(i).mContainer;
|
||||
if (!isWallpaper(wc)) {
|
||||
topApp = wc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (topApp == null) {
|
||||
out.setRootLeash(new SurfaceControl(), 0, 0);
|
||||
calculateTransitionRoots(out, sortedTargets, startT);
|
||||
if (out.getRootCount() == 0) {
|
||||
return out;
|
||||
}
|
||||
|
||||
WindowContainer<?> ancestor = findCommonAncestor(sortedTargets, topApp);
|
||||
|
||||
// Make leash based on highest (z-order) direct child of ancestor with a participant.
|
||||
// TODO(b/261418859): Handle the case when the target contains window containers which
|
||||
// belong to a different display. As a workaround we use topApp, from which wallpaper
|
||||
// window container is removed, instead of sortedTargets here.
|
||||
WindowContainer leashReference = topApp;
|
||||
while (leashReference.getParent() != ancestor) {
|
||||
leashReference = leashReference.getParent();
|
||||
}
|
||||
final SurfaceControl rootLeash = leashReference.makeAnimationLeash().setName(
|
||||
"Transition Root: " + leashReference.getName()).build();
|
||||
startT.setLayer(rootLeash, leashReference.getLastLayer());
|
||||
out.setRootLeash(rootLeash, ancestor.getBounds().left, ancestor.getBounds().top);
|
||||
|
||||
// Convert all the resolved ChangeInfos into TransactionInfo.Change objects in order.
|
||||
final int count = sortedTargets.size();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
@@ -1861,6 +1890,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
|
||||
change.setMode(info.getTransitMode(target));
|
||||
change.setStartAbsBounds(info.mAbsoluteBounds);
|
||||
change.setFlags(info.getChangeFlags(target));
|
||||
change.setDisplayId(info.mDisplayId, getDisplayId(target));
|
||||
|
||||
final Task task = target.asTask();
|
||||
final TaskFragment taskFragment = target.asTaskFragment();
|
||||
@@ -1947,6 +1977,15 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
|
||||
}
|
||||
|
||||
TransitionInfo.AnimationOptions animOptions = null;
|
||||
|
||||
// Check if the top-most app is an activity (ie. activity->activity). If so, make sure to
|
||||
// honor its custom transition options.
|
||||
WindowContainer<?> topApp = null;
|
||||
for (int i = 0; i < sortedTargets.size(); i++) {
|
||||
if (isWallpaper(sortedTargets.get(i).mContainer)) continue;
|
||||
topApp = sortedTargets.get(i).mContainer;
|
||||
break;
|
||||
}
|
||||
if (topApp.asActivityRecord() != null) {
|
||||
final ActivityRecord topActivity = topApp.asActivityRecord();
|
||||
animOptions = addCustomActivityTransition(topActivity, true/* open */, null);
|
||||
@@ -1997,14 +2036,15 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
|
||||
private static WindowContainer<?> findCommonAncestor(
|
||||
@NonNull ArrayList<ChangeInfo> targets,
|
||||
@NonNull WindowContainer<?> topApp) {
|
||||
final int displayId = getDisplayId(topApp);
|
||||
WindowContainer<?> ancestor = topApp.getParent();
|
||||
// Go up ancestor parent chain until all targets are descendants. Ancestor should never be
|
||||
// null because all targets are attached.
|
||||
for (int i = targets.size() - 1; i >= 0; i--) {
|
||||
final ChangeInfo change = targets.get(i);
|
||||
final WindowContainer wc = change.mContainer;
|
||||
if (isWallpaper(wc)) {
|
||||
// Skip the non-app window.
|
||||
if (isWallpaper(wc) || getDisplayId(wc) != displayId) {
|
||||
// Skip the non-app window or windows on a different display
|
||||
continue;
|
||||
}
|
||||
while (!wc.isDescendantOf(ancestor)) {
|
||||
@@ -2180,6 +2220,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
|
||||
final Rect mAbsoluteBounds = new Rect();
|
||||
boolean mShowWallpaper;
|
||||
int mRotation = ROTATION_UNDEFINED;
|
||||
int mDisplayId = -1;
|
||||
@ActivityInfo.Config int mKnownConfigChanges;
|
||||
|
||||
/** These are just extra info. They aren't used for change-detection. */
|
||||
@@ -2197,6 +2238,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
|
||||
mShowWallpaper = origState.showWallpaper();
|
||||
mRotation = origState.getWindowConfiguration().getRotation();
|
||||
mStartParent = origState.getParent();
|
||||
mDisplayId = getDisplayId(origState);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -2228,7 +2270,8 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
|
||||
// assume no change in windowing-mode.
|
||||
|| (mWindowingMode != 0 && mContainer.getWindowingMode() != mWindowingMode)
|
||||
|| !mContainer.getBounds().equals(mAbsoluteBounds)
|
||||
|| mRotation != mContainer.getWindowConfiguration().getRotation();
|
||||
|| mRotation != mContainer.getWindowConfiguration().getRotation()
|
||||
|| mDisplayId != getDisplayId(mContainer);
|
||||
}
|
||||
|
||||
@TransitionInfo.TransitionMode
|
||||
|
||||
@@ -519,6 +519,47 @@ public class TransitionTests extends WindowTestsBase {
|
||||
.hasFlags(TransitionInfo.FLAG_NO_ANIMATION));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateInfo_MultiDisplay() {
|
||||
DisplayContent otherDisplay = createNewDisplay();
|
||||
final Transition transition = createTestTransition(TRANSIT_OPEN);
|
||||
ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
|
||||
ArraySet<WindowContainer> participants = transition.mParticipants;
|
||||
|
||||
final Task display0Task = createTask(mDisplayContent);
|
||||
final Task display1Task = createTask(otherDisplay);
|
||||
// Start states.
|
||||
changes.put(display0Task,
|
||||
new Transition.ChangeInfo(display0Task, false /* vis */, true /* exChg */));
|
||||
changes.put(display1Task,
|
||||
new Transition.ChangeInfo(display1Task, false /* vis */, true /* exChg */));
|
||||
fillChangeMap(changes, display0Task);
|
||||
fillChangeMap(changes, display1Task);
|
||||
// End states.
|
||||
display0Task.setVisibleRequested(true);
|
||||
display1Task.setVisibleRequested(true);
|
||||
|
||||
final int transit = transition.mType;
|
||||
int flags = 0;
|
||||
|
||||
participants.add(display0Task);
|
||||
participants.add(display1Task);
|
||||
ArrayList<Transition.ChangeInfo> targets =
|
||||
Transition.calculateTargets(participants, changes);
|
||||
TransitionInfo info = Transition.calculateTransitionInfo(transit, flags, targets, mMockT);
|
||||
assertEquals(2, info.getRootCount());
|
||||
// Check that the changes are assigned to the correct display
|
||||
assertEquals(mDisplayContent.getDisplayId(), info.getChange(
|
||||
display0Task.mRemoteToken.toWindowContainerToken()).getEndDisplayId());
|
||||
assertEquals(otherDisplay.getDisplayId(), info.getChange(
|
||||
display1Task.mRemoteToken.toWindowContainerToken()).getEndDisplayId());
|
||||
// Check that roots can be found by display and have the correct display
|
||||
assertEquals(mDisplayContent.getDisplayId(),
|
||||
info.getRoot(info.findRootIndex(mDisplayContent.getDisplayId())).getDisplayId());
|
||||
assertEquals(otherDisplay.getDisplayId(),
|
||||
info.getRoot(info.findRootIndex(otherDisplay.getDisplayId())).getDisplayId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTargets_noIntermediatesToWallpaper() {
|
||||
final Transition transition = createTestTransition(TRANSIT_OPEN);
|
||||
|
||||
Reference in New Issue
Block a user