1409 lines
52 KiB
Java
1409 lines
52 KiB
Java
![]() |
/*
|
||
|
* Copyright (C) 2020 The Android Open Source Project
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
package android.window;
|
||
|
|
||
|
import static android.app.ActivityOptions.ANIM_CLIP_REVEAL;
|
||
|
import static android.app.ActivityOptions.ANIM_CUSTOM;
|
||
|
import static android.app.ActivityOptions.ANIM_FROM_STYLE;
|
||
|
import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS;
|
||
|
import static android.app.ActivityOptions.ANIM_SCALE_UP;
|
||
|
import static android.app.ActivityOptions.ANIM_SCENE_TRANSITION;
|
||
|
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;
|
||
|
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_APPEARING;
|
||
|
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
|
||
|
import static android.view.WindowManager.TRANSIT_NONE;
|
||
|
import static android.view.WindowManager.TRANSIT_OPEN;
|
||
|
import static android.view.WindowManager.TRANSIT_TO_BACK;
|
||
|
import static android.view.WindowManager.TRANSIT_TO_FRONT;
|
||
|
import static android.view.WindowManager.TransitionFlags;
|
||
|
import static android.view.WindowManager.TransitionType;
|
||
|
import static android.view.WindowManager.transitTypeToString;
|
||
|
|
||
|
import android.annotation.ColorInt;
|
||
|
import android.annotation.IntDef;
|
||
|
import android.annotation.NonNull;
|
||
|
import android.annotation.Nullable;
|
||
|
import android.app.ActivityManager;
|
||
|
import android.content.ComponentName;
|
||
|
import android.graphics.Point;
|
||
|
import android.graphics.Rect;
|
||
|
import android.hardware.HardwareBuffer;
|
||
|
import android.os.Parcel;
|
||
|
import android.os.Parcelable;
|
||
|
import android.view.Surface;
|
||
|
import android.view.SurfaceControl;
|
||
|
import android.view.WindowManager;
|
||
|
|
||
|
import java.util.ArrayList;
|
||
|
import java.util.List;
|
||
|
import java.util.Objects;
|
||
|
|
||
|
/**
|
||
|
* Used to communicate information about what is changing during a transition to a TransitionPlayer.
|
||
|
* @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
|
||
|
* @hide
|
||
|
*/
|
||
|
@IntDef(prefix = { "TRANSIT_" }, value = {
|
||
|
TRANSIT_NONE,
|
||
|
TRANSIT_OPEN,
|
||
|
TRANSIT_CLOSE,
|
||
|
// Note: to_front/to_back really mean show/hide respectively at the container level.
|
||
|
TRANSIT_TO_FRONT,
|
||
|
TRANSIT_TO_BACK,
|
||
|
TRANSIT_CHANGE
|
||
|
})
|
||
|
public @interface TransitionMode {}
|
||
|
|
||
|
/** No flags */
|
||
|
public static final int FLAG_NONE = 0;
|
||
|
|
||
|
/** The container shows the wallpaper behind it. */
|
||
|
public static final int FLAG_SHOW_WALLPAPER = 1;
|
||
|
|
||
|
/** The container IS the wallpaper. */
|
||
|
public static final int FLAG_IS_WALLPAPER = 1 << 1;
|
||
|
|
||
|
/** The container is translucent. */
|
||
|
public static final int FLAG_TRANSLUCENT = 1 << 2;
|
||
|
|
||
|
// TODO: remove when starting-window is moved to Task
|
||
|
/** The container is the recipient of a transferred starting-window */
|
||
|
public static final int FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT = 1 << 3;
|
||
|
|
||
|
/** The container has voice session. */
|
||
|
public static final int FLAG_IS_VOICE_INTERACTION = 1 << 4;
|
||
|
|
||
|
/** The container is the display. */
|
||
|
public static final int FLAG_IS_DISPLAY = 1 << 5;
|
||
|
|
||
|
/**
|
||
|
* Only for IS_DISPLAY containers. Is set if the display has system alert windows. This is
|
||
|
* used to prevent seamless rotation.
|
||
|
* TODO(b/194540864): Once we can include all windows in transition, then replace this with
|
||
|
* something like FLAG_IS_SYSTEM_ALERT instead. Then we can do mixed rotations.
|
||
|
*/
|
||
|
public static final int FLAG_DISPLAY_HAS_ALERT_WINDOWS = 1 << 7;
|
||
|
|
||
|
/** The container is an input-method window. */
|
||
|
public static final int FLAG_IS_INPUT_METHOD = 1 << 8;
|
||
|
|
||
|
/** The container is in a Task with embedded activity. */
|
||
|
public static final int FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY = 1 << 9;
|
||
|
|
||
|
/** The container fills its parent Task before and after the transition. */
|
||
|
public static final int FLAG_FILLS_TASK = 1 << 10;
|
||
|
|
||
|
/** The container is going to show IME on its task after the transition. */
|
||
|
public static final int FLAG_WILL_IME_SHOWN = 1 << 11;
|
||
|
|
||
|
/** The container attaches owner profile thumbnail for cross profile animation. */
|
||
|
public static final int FLAG_CROSS_PROFILE_OWNER_THUMBNAIL = 1 << 12;
|
||
|
|
||
|
/** The container attaches work profile thumbnail for cross profile animation. */
|
||
|
public static final int FLAG_CROSS_PROFILE_WORK_THUMBNAIL = 1 << 13;
|
||
|
|
||
|
/**
|
||
|
* Whether the window is covered by an app starting window. This is different from
|
||
|
* {@link #FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT} which is only set on the Activity window
|
||
|
* that contains the starting window.
|
||
|
*/
|
||
|
public static final int FLAG_IS_BEHIND_STARTING_WINDOW = 1 << 14;
|
||
|
|
||
|
/** This change happened underneath something else. */
|
||
|
public static final int FLAG_IS_OCCLUDED = 1 << 15;
|
||
|
|
||
|
/** The container is a system window, excluding wallpaper and input-method. */
|
||
|
public static final int FLAG_IS_SYSTEM_WINDOW = 1 << 16;
|
||
|
|
||
|
/** The window was animated by back gesture. */
|
||
|
public static final int FLAG_BACK_GESTURE_ANIMATED = 1 << 17;
|
||
|
|
||
|
/** The window should have no animation (by policy). */
|
||
|
public static final int FLAG_NO_ANIMATION = 1 << 18;
|
||
|
|
||
|
/** The task is launching behind home. */
|
||
|
public static final int FLAG_TASK_LAUNCHING_BEHIND = 1 << 19;
|
||
|
|
||
|
/** The task became the top-most task even if it didn't change visibility. */
|
||
|
public static final int FLAG_MOVED_TO_TOP = 1 << 20;
|
||
|
|
||
|
/**
|
||
|
* This transition must be the only transition when it starts (ie. it must wait for all other
|
||
|
* transition animations to finish).
|
||
|
*/
|
||
|
public static final int FLAG_SYNC = 1 << 21;
|
||
|
|
||
|
/** This change represents its start configuration for the duration of the animation. */
|
||
|
public static final int FLAG_CONFIG_AT_END = 1 << 22;
|
||
|
|
||
|
/** The first unused bit. This can be used by remotes to attach custom flags to this change. */
|
||
|
public static final int FLAG_FIRST_CUSTOM = 1 << 23;
|
||
|
|
||
|
/** The change belongs to a window that won't contain activities. */
|
||
|
public static final int FLAGS_IS_NON_APP_WINDOW =
|
||
|
FLAG_IS_WALLPAPER | FLAG_IS_INPUT_METHOD | FLAG_IS_SYSTEM_WINDOW;
|
||
|
|
||
|
/** The change will not participate in the animation. */
|
||
|
public static final int FLAGS_IS_OCCLUDED_NO_ANIMATION = FLAG_IS_OCCLUDED | FLAG_NO_ANIMATION;
|
||
|
|
||
|
/** @hide */
|
||
|
@IntDef(prefix = { "FLAG_" }, value = {
|
||
|
FLAG_NONE,
|
||
|
FLAG_SHOW_WALLPAPER,
|
||
|
FLAG_IS_WALLPAPER,
|
||
|
FLAG_TRANSLUCENT,
|
||
|
FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT,
|
||
|
FLAG_IS_VOICE_INTERACTION,
|
||
|
FLAG_IS_DISPLAY,
|
||
|
FLAG_DISPLAY_HAS_ALERT_WINDOWS,
|
||
|
FLAG_IS_INPUT_METHOD,
|
||
|
FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY,
|
||
|
FLAG_FILLS_TASK,
|
||
|
FLAG_WILL_IME_SHOWN,
|
||
|
FLAG_CROSS_PROFILE_OWNER_THUMBNAIL,
|
||
|
FLAG_CROSS_PROFILE_WORK_THUMBNAIL,
|
||
|
FLAG_IS_BEHIND_STARTING_WINDOW,
|
||
|
FLAG_IS_OCCLUDED,
|
||
|
FLAG_IS_SYSTEM_WINDOW,
|
||
|
FLAG_BACK_GESTURE_ANIMATED,
|
||
|
FLAG_NO_ANIMATION,
|
||
|
FLAG_TASK_LAUNCHING_BEHIND,
|
||
|
FLAG_MOVED_TO_TOP,
|
||
|
FLAG_SYNC,
|
||
|
FLAG_CONFIG_AT_END,
|
||
|
FLAG_FIRST_CUSTOM
|
||
|
})
|
||
|
public @interface ChangeFlags {}
|
||
|
|
||
|
private final @TransitionType int mType;
|
||
|
private @TransitionFlags int mFlags;
|
||
|
private int mTrack = 0;
|
||
|
private final ArrayList<Change> mChanges = new ArrayList<>();
|
||
|
private final ArrayList<Root> mRoots = new ArrayList<>();
|
||
|
|
||
|
private AnimationOptions mOptions;
|
||
|
|
||
|
/** This is only a BEST-EFFORT id used for log correlation. DO NOT USE for any real work! */
|
||
|
private int mDebugId = -1;
|
||
|
|
||
|
/** @hide */
|
||
|
public TransitionInfo(@TransitionType int type, @TransitionFlags int flags) {
|
||
|
mType = type;
|
||
|
mFlags = flags;
|
||
|
}
|
||
|
|
||
|
private TransitionInfo(Parcel in) {
|
||
|
mType = in.readInt();
|
||
|
mFlags = in.readInt();
|
||
|
in.readTypedList(mChanges, Change.CREATOR);
|
||
|
in.readTypedList(mRoots, Root.CREATOR);
|
||
|
mOptions = in.readTypedObject(AnimationOptions.CREATOR);
|
||
|
mDebugId = in.readInt();
|
||
|
mTrack = in.readInt();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
/** @hide */
|
||
|
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||
|
dest.writeInt(mType);
|
||
|
dest.writeInt(mFlags);
|
||
|
dest.writeTypedList(mChanges);
|
||
|
dest.writeTypedList(mRoots, flags);
|
||
|
dest.writeTypedObject(mOptions, flags);
|
||
|
dest.writeInt(mDebugId);
|
||
|
dest.writeInt(mTrack);
|
||
|
}
|
||
|
|
||
|
@NonNull
|
||
|
public static final Creator<TransitionInfo> CREATOR =
|
||
|
new Creator<TransitionInfo>() {
|
||
|
@Override
|
||
|
public TransitionInfo createFromParcel(Parcel in) {
|
||
|
return new TransitionInfo(in);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public TransitionInfo[] newArray(int size) {
|
||
|
return new TransitionInfo[size];
|
||
|
}
|
||
|
};
|
||
|
|
||
|
@Override
|
||
|
/** @hide */
|
||
|
public int describeContents() {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/** @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) {
|
||
|
mOptions = options;
|
||
|
}
|
||
|
|
||
|
public @TransitionType int getType() {
|
||
|
return mType;
|
||
|
}
|
||
|
|
||
|
public void setFlags(int flags) {
|
||
|
mFlags = flags;
|
||
|
}
|
||
|
|
||
|
public int getFlags() {
|
||
|
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 (mRoots.isEmpty()) {
|
||
|
throw new IllegalStateException("Trying to get a root leash from a no-op transition.");
|
||
|
}
|
||
|
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() {
|
||
|
return mOptions;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return the list of {@link Change}s in this transition. The list is sorted top-to-bottom
|
||
|
* in Z (meaning index 0 is the top-most container).
|
||
|
*/
|
||
|
@NonNull
|
||
|
public List<Change> getChanges() {
|
||
|
return mChanges;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return the Change that a window is undergoing or {@code null} if not directly
|
||
|
* represented.
|
||
|
*/
|
||
|
@Nullable
|
||
|
public Change getChange(@NonNull WindowContainerToken token) {
|
||
|
for (int i = mChanges.size() - 1; i >= 0; --i) {
|
||
|
if (token.equals(mChanges.get(i).mContainer)) {
|
||
|
return mChanges.get(i);
|
||
|
}
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Add a {@link Change} to this transition.
|
||
|
*/
|
||
|
public void addChange(@NonNull Change change) {
|
||
|
mChanges.add(change);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Whether this transition contains any changes to the window hierarchy,
|
||
|
* including keyguard visibility.
|
||
|
*/
|
||
|
public boolean hasChangesOrSideEffects() {
|
||
|
return !mChanges.isEmpty() || isKeyguardGoingAway()
|
||
|
|| (mFlags & TRANSIT_FLAG_KEYGUARD_APPEARING) != 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Whether this transition includes keyguard going away.
|
||
|
*/
|
||
|
public boolean isKeyguardGoingAway() {
|
||
|
return (mFlags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY) != 0;
|
||
|
}
|
||
|
|
||
|
/** Gets which animation track this transition should run on. */
|
||
|
public int getTrack() {
|
||
|
return mTrack;
|
||
|
}
|
||
|
|
||
|
/** Sets which animation track this transition should run on. */
|
||
|
public void setTrack(int track) {
|
||
|
mTrack = track;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set an arbitrary "debug" id for this info. This id will not be used for any "real work",
|
||
|
* it is just for debugging and logging.
|
||
|
*/
|
||
|
public void setDebugId(int id) {
|
||
|
mDebugId = id;
|
||
|
}
|
||
|
|
||
|
/** Get the "debug" id of this info. Do NOT use this for real work, only use for debugging. */
|
||
|
public int getDebugId() {
|
||
|
return mDebugId;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public String toString() {
|
||
|
return toString("");
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns a string representation of this transition info.
|
||
|
* @hide
|
||
|
*/
|
||
|
public String toString(@NonNull String prefix) {
|
||
|
final boolean shouldPrettyPrint = !prefix.isEmpty() && !mChanges.isEmpty();
|
||
|
final String innerPrefix = shouldPrettyPrint ? prefix + " " : "";
|
||
|
final String changesLineStart = shouldPrettyPrint ? "\n" + prefix : "";
|
||
|
final String perChangeLineStart = shouldPrettyPrint ? "\n" + innerPrefix : "";
|
||
|
StringBuilder sb = new StringBuilder();
|
||
|
sb.append("{id=").append(mDebugId).append(" t=").append(transitTypeToString(mType))
|
||
|
.append(" f=0x").append(Integer.toHexString(mFlags)).append(" trk=").append(mTrack);
|
||
|
if (mOptions != null) {
|
||
|
sb.append(" opt=").append(mOptions);
|
||
|
}
|
||
|
sb.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=[");
|
||
|
sb.append(perChangeLineStart);
|
||
|
for (int i = 0; i < mChanges.size(); ++i) {
|
||
|
if (i > 0) {
|
||
|
sb.append(',');
|
||
|
sb.append(perChangeLineStart);
|
||
|
}
|
||
|
sb.append(mChanges.get(i));
|
||
|
}
|
||
|
sb.append(changesLineStart);
|
||
|
sb.append("]}");
|
||
|
return sb.toString();
|
||
|
}
|
||
|
|
||
|
/** Converts a transition mode/action to its string representation. */
|
||
|
@NonNull
|
||
|
public static String modeToString(@TransitionMode int mode) {
|
||
|
switch(mode) {
|
||
|
case TRANSIT_NONE: return "NONE";
|
||
|
case TRANSIT_OPEN: return "OPEN";
|
||
|
case TRANSIT_CLOSE: return "CLOSE";
|
||
|
case TRANSIT_TO_FRONT: return "TO_FRONT";
|
||
|
case TRANSIT_TO_BACK: return "TO_BACK";
|
||
|
case TRANSIT_CHANGE: return "CHANGE";
|
||
|
default: return "<unknown:" + mode + ">";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** Converts change flags into a string representation. */
|
||
|
@NonNull
|
||
|
public static String flagsToString(@ChangeFlags int flags) {
|
||
|
if (flags == 0) return "NONE";
|
||
|
final StringBuilder sb = new StringBuilder();
|
||
|
if ((flags & FLAG_SHOW_WALLPAPER) != 0) {
|
||
|
sb.append("SHOW_WALLPAPER");
|
||
|
}
|
||
|
if ((flags & FLAG_IS_WALLPAPER) != 0) {
|
||
|
sb.append("IS_WALLPAPER");
|
||
|
}
|
||
|
if ((flags & FLAG_IS_INPUT_METHOD) != 0) {
|
||
|
sb.append("IS_INPUT_METHOD");
|
||
|
}
|
||
|
if ((flags & FLAG_TRANSLUCENT) != 0) {
|
||
|
sb.append(sb.length() == 0 ? "" : "|").append("TRANSLUCENT");
|
||
|
}
|
||
|
if ((flags & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0) {
|
||
|
sb.append(sb.length() == 0 ? "" : "|").append("STARTING_WINDOW_TRANSFER");
|
||
|
}
|
||
|
if ((flags & FLAG_IS_VOICE_INTERACTION) != 0) {
|
||
|
sb.append(sb.length() == 0 ? "" : "|").append("IS_VOICE_INTERACTION");
|
||
|
}
|
||
|
if ((flags & FLAG_IS_DISPLAY) != 0) {
|
||
|
sb.append(sb.length() == 0 ? "" : "|").append("IS_DISPLAY");
|
||
|
}
|
||
|
if ((flags & FLAG_DISPLAY_HAS_ALERT_WINDOWS) != 0) {
|
||
|
sb.append(sb.length() == 0 ? "" : "|").append("DISPLAY_HAS_ALERT_WINDOWS");
|
||
|
}
|
||
|
if ((flags & FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY) != 0) {
|
||
|
sb.append(sb.length() == 0 ? "" : "|").append("IN_TASK_WITH_EMBEDDED_ACTIVITY");
|
||
|
}
|
||
|
if ((flags & FLAG_FILLS_TASK) != 0) {
|
||
|
sb.append(sb.length() == 0 ? "" : "|").append("FILLS_TASK");
|
||
|
}
|
||
|
if ((flags & FLAG_IS_BEHIND_STARTING_WINDOW) != 0) {
|
||
|
sb.append(sb.length() == 0 ? "" : "|").append("IS_BEHIND_STARTING_WINDOW");
|
||
|
}
|
||
|
if ((flags & FLAG_IS_OCCLUDED) != 0) {
|
||
|
sb.append(sb.length() == 0 ? "" : "|").append("IS_OCCLUDED");
|
||
|
}
|
||
|
if ((flags & FLAG_IS_SYSTEM_WINDOW) != 0) {
|
||
|
sb.append(sb.length() == 0 ? "" : "|").append("FLAG_IS_SYSTEM_WINDOW");
|
||
|
}
|
||
|
if ((flags & FLAG_BACK_GESTURE_ANIMATED) != 0) {
|
||
|
sb.append(sb.length() == 0 ? "" : "|").append("FLAG_BACK_GESTURE_ANIMATED");
|
||
|
}
|
||
|
if ((flags & FLAG_NO_ANIMATION) != 0) {
|
||
|
sb.append(sb.length() == 0 ? "" : "|").append("NO_ANIMATION");
|
||
|
}
|
||
|
if ((flags & FLAG_TASK_LAUNCHING_BEHIND) != 0) {
|
||
|
sb.append((sb.length() == 0 ? "" : "|") + "TASK_LAUNCHING_BEHIND");
|
||
|
}
|
||
|
if ((flags & FLAG_SYNC) != 0) {
|
||
|
sb.append((sb.length() == 0 ? "" : "|") + "SYNC");
|
||
|
}
|
||
|
if ((flags & FLAG_FIRST_CUSTOM) != 0) {
|
||
|
sb.append(sb.length() == 0 ? "" : "|").append("FIRST_CUSTOM");
|
||
|
}
|
||
|
if ((flags & FLAG_CONFIG_AT_END) != 0) {
|
||
|
sb.append(sb.length() == 0 ? "" : "|").append("CONFIG_AT_END");
|
||
|
}
|
||
|
if ((flags & FLAG_MOVED_TO_TOP) != 0) {
|
||
|
sb.append(sb.length() == 0 ? "" : "|").append("MOVE_TO_TOP");
|
||
|
}
|
||
|
return sb.toString();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Indication that `change` is independent of parents (ie. it has a different type of
|
||
|
* transition vs. "going along for the ride")
|
||
|
*/
|
||
|
public static boolean isIndependent(@NonNull TransitionInfo.Change change,
|
||
|
@NonNull TransitionInfo info) {
|
||
|
// If the change has no parent (it is root), then it is independent
|
||
|
if (change.getParent() == null) return true;
|
||
|
|
||
|
if (change.getLastParent() != null && !change.getLastParent().equals(change.getParent())) {
|
||
|
// If the change has been reparented, then it's independent.
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// non-visibility changes will just be folded into the parent change, so they aren't
|
||
|
// independent either.
|
||
|
if (change.getMode() == TRANSIT_CHANGE) return false;
|
||
|
|
||
|
// Always fold the activity embedding change into the parent change.
|
||
|
if (change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY)) return false;
|
||
|
|
||
|
TransitionInfo.Change parentChg = info.getChange(change.getParent());
|
||
|
while (parentChg != null) {
|
||
|
// If the parent is a visibility change, it will include the results of all child
|
||
|
// changes into itself, so none of its children can be independent.
|
||
|
if (parentChg.getMode() != TRANSIT_CHANGE) return false;
|
||
|
|
||
|
// If there are no more parents left, then all the parents, so far, have not been
|
||
|
// visibility changes which means this change is independent.
|
||
|
if (parentChg.getParent() == null) return true;
|
||
|
|
||
|
parentChg = info.getChange(parentChg.getParent());
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Releases temporary-for-animation surfaces referenced by this to potentially free up memory.
|
||
|
* This includes root-leash and snapshots.
|
||
|
*/
|
||
|
public void releaseAnimSurfaces() {
|
||
|
for (int i = mChanges.size() - 1; i >= 0; --i) {
|
||
|
final Change c = mChanges.get(i);
|
||
|
if (c.mSnapshot != null) {
|
||
|
c.mSnapshot.release();
|
||
|
c.mSnapshot = null;
|
||
|
}
|
||
|
}
|
||
|
for (int i = 0; i < mRoots.size(); ++i) {
|
||
|
mRoots.get(i).mLeash.release();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Releases ALL the surfaces referenced by this to potentially free up memory. Do NOT use this
|
||
|
* if the surface-controls get stored and used elsewhere in the process. To just release
|
||
|
* temporary-for-animation surfaces, use {@link #releaseAnimSurfaces}.
|
||
|
*/
|
||
|
public void releaseAllSurfaces() {
|
||
|
releaseAnimSurfaces();
|
||
|
for (int i = mChanges.size() - 1; i >= 0; --i) {
|
||
|
mChanges.get(i).getLeash().release();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Updates the callsites of all the surfaces in this transition, which aids in the debugging of
|
||
|
* lingering surfaces.
|
||
|
*/
|
||
|
public void setUnreleasedWarningCallSiteForAllSurfaces(String callsite) {
|
||
|
for (int i = mChanges.size() - 1; i >= 0; --i) {
|
||
|
mChanges.get(i).getLeash().setUnreleasedWarningCallSite(callsite);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Makes a copy of this as if it were parcel'd and unparcel'd. This implies that surfacecontrol
|
||
|
* refcounts are incremented which allows the "remote" receiver to release them without breaking
|
||
|
* the caller's references. Use this only if you need to "send" this to a local function which
|
||
|
* assumes it is being called from a remote caller.
|
||
|
*/
|
||
|
public TransitionInfo localRemoteCopy() {
|
||
|
final TransitionInfo out = new TransitionInfo(mType, mFlags);
|
||
|
out.mTrack = mTrack;
|
||
|
out.mDebugId = mDebugId;
|
||
|
for (int i = 0; i < mChanges.size(); ++i) {
|
||
|
out.mChanges.add(mChanges.get(i).localRemoteCopy());
|
||
|
}
|
||
|
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;
|
||
|
return out;
|
||
|
}
|
||
|
|
||
|
/** Represents the change a WindowContainer undergoes during a transition */
|
||
|
public static final class Change implements Parcelable {
|
||
|
private final WindowContainerToken mContainer;
|
||
|
private WindowContainerToken mParent;
|
||
|
private WindowContainerToken mLastParent;
|
||
|
private SurfaceControl mLeash;
|
||
|
private @TransitionMode int mMode = TRANSIT_NONE;
|
||
|
private @ChangeFlags int mFlags = FLAG_NONE;
|
||
|
private final Rect mStartAbsBounds = new Rect();
|
||
|
private final Rect mEndAbsBounds = new Rect();
|
||
|
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;
|
||
|
/**
|
||
|
* The end rotation of the top activity after fixed rotation is finished. If the top
|
||
|
* activity is not in fixed rotation, it will be {@link ROTATION_UNDEFINED}.
|
||
|
*/
|
||
|
private @Surface.Rotation int mEndFixedRotation = ROTATION_UNDEFINED;
|
||
|
private int mRotationAnimation = ROTATION_ANIMATION_UNSPECIFIED;
|
||
|
private @ColorInt int mBackgroundColor;
|
||
|
private SurfaceControl mSnapshot = null;
|
||
|
private float mSnapshotLuma;
|
||
|
private ComponentName mActivityComponent = null;
|
||
|
|
||
|
public Change(@Nullable WindowContainerToken container, @NonNull SurfaceControl leash) {
|
||
|
mContainer = container;
|
||
|
mLeash = leash;
|
||
|
}
|
||
|
|
||
|
private Change(Parcel in) {
|
||
|
mContainer = in.readTypedObject(WindowContainerToken.CREATOR);
|
||
|
mParent = in.readTypedObject(WindowContainerToken.CREATOR);
|
||
|
mLastParent = in.readTypedObject(WindowContainerToken.CREATOR);
|
||
|
mLeash = new SurfaceControl();
|
||
|
mLeash.readFromParcel(in);
|
||
|
mMode = in.readInt();
|
||
|
mFlags = in.readInt();
|
||
|
mStartAbsBounds.readFromParcel(in);
|
||
|
mEndAbsBounds.readFromParcel(in);
|
||
|
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();
|
||
|
mRotationAnimation = in.readInt();
|
||
|
mBackgroundColor = in.readInt();
|
||
|
mSnapshot = in.readTypedObject(SurfaceControl.CREATOR);
|
||
|
mSnapshotLuma = in.readFloat();
|
||
|
mActivityComponent = in.readTypedObject(ComponentName.CREATOR);
|
||
|
}
|
||
|
|
||
|
private Change localRemoteCopy() {
|
||
|
final Change out = new Change(mContainer, new SurfaceControl(mLeash, "localRemote"));
|
||
|
out.mParent = mParent;
|
||
|
out.mLastParent = mLastParent;
|
||
|
out.mMode = mMode;
|
||
|
out.mFlags = mFlags;
|
||
|
out.mStartAbsBounds.set(mStartAbsBounds);
|
||
|
out.mEndAbsBounds.set(mEndAbsBounds);
|
||
|
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;
|
||
|
out.mRotationAnimation = mRotationAnimation;
|
||
|
out.mBackgroundColor = mBackgroundColor;
|
||
|
out.mSnapshot = mSnapshot != null ? new SurfaceControl(mSnapshot, "localRemote") : null;
|
||
|
out.mSnapshotLuma = mSnapshotLuma;
|
||
|
out.mActivityComponent = mActivityComponent;
|
||
|
return out;
|
||
|
}
|
||
|
|
||
|
/** Sets the parent of this change's container. The parent must be a participant or null. */
|
||
|
public void setParent(@Nullable WindowContainerToken parent) {
|
||
|
mParent = parent;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the parent of this change's container before the transition if this change's
|
||
|
* container is reparented in the transition.
|
||
|
*/
|
||
|
public void setLastParent(@Nullable WindowContainerToken lastParent) {
|
||
|
mLastParent = lastParent;
|
||
|
}
|
||
|
|
||
|
/** Sets the animation leash for controlling this change's container */
|
||
|
public void setLeash(@NonNull SurfaceControl leash) {
|
||
|
mLeash = Objects.requireNonNull(leash);
|
||
|
}
|
||
|
|
||
|
/** Sets the transition mode for this change */
|
||
|
public void setMode(@TransitionMode int mode) {
|
||
|
mMode = mode;
|
||
|
}
|
||
|
|
||
|
/** Sets the flags for this change */
|
||
|
public void setFlags(@ChangeFlags int flags) {
|
||
|
mFlags = flags;
|
||
|
}
|
||
|
|
||
|
/** Sets the bounds this container occupied before the change in screen space */
|
||
|
public void setStartAbsBounds(@Nullable Rect rect) {
|
||
|
mStartAbsBounds.set(rect);
|
||
|
}
|
||
|
|
||
|
/** Sets the bounds this container will occupy after the change in screen space */
|
||
|
public void setEndAbsBounds(@Nullable Rect rect) {
|
||
|
mEndAbsBounds.set(rect);
|
||
|
}
|
||
|
|
||
|
/** Sets the offset of this container from its parent surface */
|
||
|
public void setEndRelOffset(int left, int top) {
|
||
|
mEndRelOffset.set(left, top);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the taskinfo of this container if this is a task. WARNING: this takes the
|
||
|
* reference, so don't modify it afterwards.
|
||
|
*/
|
||
|
public void setTaskInfo(@Nullable ActivityManager.RunningTaskInfo taskInfo) {
|
||
|
mTaskInfo = taskInfo;
|
||
|
}
|
||
|
|
||
|
/** Sets the allowEnterPip flag which represents AppOpsManager check on PiP permission */
|
||
|
public void setAllowEnterPip(boolean allowEnterPip) {
|
||
|
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;
|
||
|
mEndRotation = end;
|
||
|
}
|
||
|
|
||
|
/** Sets end rotation that top activity will be launched to after fixed rotation. */
|
||
|
public void setEndFixedRotation(@Surface.Rotation int endFixedRotation) {
|
||
|
mEndFixedRotation = endFixedRotation;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the app-requested animation type for rotation. Will be one of the
|
||
|
* ROTATION_ANIMATION_ values in {@link android.view.WindowManager.LayoutParams};
|
||
|
*/
|
||
|
public void setRotationAnimation(int anim) {
|
||
|
mRotationAnimation = anim;
|
||
|
}
|
||
|
|
||
|
/** Sets the background color of this change's container. */
|
||
|
public void setBackgroundColor(@ColorInt int 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;
|
||
|
}
|
||
|
|
||
|
/** Sets the component-name of the container. Container must be an Activity. */
|
||
|
public void setActivityComponent(@Nullable ComponentName component) {
|
||
|
mActivityComponent = component;
|
||
|
}
|
||
|
|
||
|
/** @return the container that is changing. May be null if non-remotable (eg. activity) */
|
||
|
@Nullable
|
||
|
public WindowContainerToken getContainer() {
|
||
|
return mContainer;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return the parent of the changing container. This is the parent within the participants,
|
||
|
* not necessarily the actual parent.
|
||
|
*/
|
||
|
@Nullable
|
||
|
public WindowContainerToken getParent() {
|
||
|
return mParent;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return the parent of the changing container before the transition if it is reparented
|
||
|
* in the transition. The parent window may not be collected in the transition as a
|
||
|
* participant, and it may have been detached from the display. {@code null} if the changing
|
||
|
* container has not been reparented in the transition, or if the parent is not organizable.
|
||
|
*/
|
||
|
@Nullable
|
||
|
public WindowContainerToken getLastParent() {
|
||
|
return mLastParent;
|
||
|
}
|
||
|
|
||
|
/** @return which action this change represents. */
|
||
|
public @TransitionMode int getMode() {
|
||
|
return mMode;
|
||
|
}
|
||
|
|
||
|
/** @return the flags for this change. */
|
||
|
public @ChangeFlags int getFlags() {
|
||
|
return mFlags;
|
||
|
}
|
||
|
|
||
|
/** Whether this change contains any of the given change flags. */
|
||
|
public boolean hasFlags(@ChangeFlags int flags) {
|
||
|
return (mFlags & flags) != 0;
|
||
|
}
|
||
|
|
||
|
/** Whether this change contains all of the given change flags. */
|
||
|
public boolean hasAllFlags(@ChangeFlags int flags) {
|
||
|
return (mFlags & flags) == flags;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return the bounds of the container before the change. It may be empty if the container
|
||
|
* is coming into existence.
|
||
|
*/
|
||
|
@NonNull
|
||
|
public Rect getStartAbsBounds() {
|
||
|
return mStartAbsBounds;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return the bounds of the container after the change. It may be empty if the container
|
||
|
* is disappearing.
|
||
|
*/
|
||
|
@NonNull
|
||
|
public Rect getEndAbsBounds() {
|
||
|
return mEndAbsBounds;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return the offset of the container's surface from its parent surface after the change.
|
||
|
*/
|
||
|
@NonNull
|
||
|
public Point getEndRelOffset() {
|
||
|
return mEndRelOffset;
|
||
|
}
|
||
|
|
||
|
/** @return the leash or surface to animate for this container */
|
||
|
@NonNull
|
||
|
public SurfaceControl getLeash() {
|
||
|
return mLeash;
|
||
|
}
|
||
|
|
||
|
/** @return the task info or null if this isn't a task */
|
||
|
@Nullable
|
||
|
public ActivityManager.RunningTaskInfo getTaskInfo() {
|
||
|
return mTaskInfo;
|
||
|
}
|
||
|
|
||
|
public boolean getAllowEnterPip() {
|
||
|
return mAllowEnterPip;
|
||
|
}
|
||
|
|
||
|
public int getStartDisplayId() {
|
||
|
return mStartDisplayId;
|
||
|
}
|
||
|
|
||
|
public int getEndDisplayId() {
|
||
|
return mEndDisplayId;
|
||
|
}
|
||
|
|
||
|
@Surface.Rotation
|
||
|
public int getStartRotation() {
|
||
|
return mStartRotation;
|
||
|
}
|
||
|
|
||
|
@Surface.Rotation
|
||
|
public int getEndRotation() {
|
||
|
return mEndRotation;
|
||
|
}
|
||
|
|
||
|
@Surface.Rotation
|
||
|
public int getEndFixedRotation() {
|
||
|
return mEndFixedRotation;
|
||
|
}
|
||
|
|
||
|
/** @return the rotation animation. */
|
||
|
public int getRotationAnimation() {
|
||
|
return mRotationAnimation;
|
||
|
}
|
||
|
|
||
|
/** @return get the background color of this change's container. */
|
||
|
@ColorInt
|
||
|
public int getBackgroundColor() {
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
/** @return the component-name of this container (if it is an activity). */
|
||
|
@Nullable
|
||
|
public ComponentName getActivityComponent() {
|
||
|
return mActivityComponent;
|
||
|
}
|
||
|
|
||
|
/** @hide */
|
||
|
@Override
|
||
|
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||
|
dest.writeTypedObject(mContainer, flags);
|
||
|
dest.writeTypedObject(mParent, flags);
|
||
|
dest.writeTypedObject(mLastParent, flags);
|
||
|
mLeash.writeToParcel(dest, flags);
|
||
|
dest.writeInt(mMode);
|
||
|
dest.writeInt(mFlags);
|
||
|
mStartAbsBounds.writeToParcel(dest, flags);
|
||
|
mEndAbsBounds.writeToParcel(dest, flags);
|
||
|
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);
|
||
|
dest.writeInt(mRotationAnimation);
|
||
|
dest.writeInt(mBackgroundColor);
|
||
|
dest.writeTypedObject(mSnapshot, flags);
|
||
|
dest.writeFloat(mSnapshotLuma);
|
||
|
dest.writeTypedObject(mActivityComponent, flags);
|
||
|
}
|
||
|
|
||
|
@NonNull
|
||
|
public static final Creator<Change> CREATOR =
|
||
|
new Creator<Change>() {
|
||
|
@Override
|
||
|
public Change createFromParcel(Parcel in) {
|
||
|
return new Change(in);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public Change[] newArray(int size) {
|
||
|
return new Change[size];
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/** @hide */
|
||
|
@Override
|
||
|
public int describeContents() {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public String toString() {
|
||
|
final StringBuilder sb = new StringBuilder();
|
||
|
sb.append('{'); sb.append(mContainer);
|
||
|
sb.append(" m="); sb.append(modeToString(mMode));
|
||
|
sb.append(" f="); sb.append(flagsToString(mFlags));
|
||
|
if (mParent != null) {
|
||
|
sb.append(" p="); sb.append(mParent);
|
||
|
}
|
||
|
if (mLeash != null) {
|
||
|
sb.append(" leash="); sb.append(mLeash);
|
||
|
}
|
||
|
sb.append(" sb="); sb.append(mStartAbsBounds);
|
||
|
sb.append(" eb="); sb.append(mEndAbsBounds);
|
||
|
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);
|
||
|
sb.append(':'); sb.append(mRotationAnimation);
|
||
|
}
|
||
|
if (mEndFixedRotation != ROTATION_UNDEFINED) {
|
||
|
sb.append(" endFixedRotation="); sb.append(mEndFixedRotation);
|
||
|
}
|
||
|
if (mSnapshot != null) {
|
||
|
sb.append(" snapshot="); sb.append(mSnapshot);
|
||
|
}
|
||
|
if (mLastParent != null) {
|
||
|
sb.append(" lastParent="); sb.append(mLastParent);
|
||
|
}
|
||
|
if (mActivityComponent != null) {
|
||
|
sb.append(" component=");
|
||
|
sb.append(mActivityComponent.flattenToShortString());
|
||
|
}
|
||
|
if (mTaskInfo != null) {
|
||
|
sb.append(" taskParent=");
|
||
|
sb.append(mTaskInfo.parentTaskId);
|
||
|
}
|
||
|
sb.append('}');
|
||
|
return sb.toString();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** Represents animation options during a transition */
|
||
|
public static final class AnimationOptions implements Parcelable {
|
||
|
|
||
|
private int mType;
|
||
|
private int mEnterResId;
|
||
|
private int mExitResId;
|
||
|
private boolean mOverrideTaskTransition;
|
||
|
private String mPackageName;
|
||
|
private final Rect mTransitionBounds = new Rect();
|
||
|
private HardwareBuffer mThumbnail;
|
||
|
private int mAnimations;
|
||
|
private @ColorInt int mBackgroundColor;
|
||
|
// Customize activity transition animation
|
||
|
private CustomActivityTransition mCustomActivityOpenTransition;
|
||
|
private CustomActivityTransition mCustomActivityCloseTransition;
|
||
|
|
||
|
private AnimationOptions(int type) {
|
||
|
mType = type;
|
||
|
}
|
||
|
|
||
|
public AnimationOptions(Parcel in) {
|
||
|
mType = in.readInt();
|
||
|
mEnterResId = in.readInt();
|
||
|
mExitResId = in.readInt();
|
||
|
mBackgroundColor = in.readInt();
|
||
|
mOverrideTaskTransition = in.readBoolean();
|
||
|
mPackageName = in.readString();
|
||
|
mTransitionBounds.readFromParcel(in);
|
||
|
mThumbnail = in.readTypedObject(HardwareBuffer.CREATOR);
|
||
|
mAnimations = in.readInt();
|
||
|
mCustomActivityOpenTransition = in.readTypedObject(CustomActivityTransition.CREATOR);
|
||
|
mCustomActivityCloseTransition = in.readTypedObject(CustomActivityTransition.CREATOR);
|
||
|
}
|
||
|
|
||
|
/** Make basic customized animation for a package */
|
||
|
public static AnimationOptions makeCommonAnimOptions(String packageName) {
|
||
|
AnimationOptions options = new AnimationOptions(ANIM_FROM_STYLE);
|
||
|
options.mPackageName = packageName;
|
||
|
return options;
|
||
|
}
|
||
|
|
||
|
public static AnimationOptions makeAnimOptionsFromLayoutParameters(
|
||
|
WindowManager.LayoutParams lp) {
|
||
|
AnimationOptions options = new AnimationOptions(ANIM_FROM_STYLE);
|
||
|
options.mPackageName = lp.packageName;
|
||
|
options.mAnimations = lp.windowAnimations;
|
||
|
return options;
|
||
|
}
|
||
|
|
||
|
/** Add customized window animations */
|
||
|
public void addOptionsFromLayoutParameters(WindowManager.LayoutParams lp) {
|
||
|
mAnimations = lp.windowAnimations;
|
||
|
}
|
||
|
|
||
|
/** Add customized activity animation attributes */
|
||
|
public void addCustomActivityTransition(boolean isOpen,
|
||
|
int enterResId, int exitResId, int backgroundColor) {
|
||
|
CustomActivityTransition customTransition = isOpen
|
||
|
? mCustomActivityOpenTransition : mCustomActivityCloseTransition;
|
||
|
if (customTransition == null) {
|
||
|
customTransition = new CustomActivityTransition();
|
||
|
if (isOpen) {
|
||
|
mCustomActivityOpenTransition = customTransition;
|
||
|
} else {
|
||
|
mCustomActivityCloseTransition = customTransition;
|
||
|
}
|
||
|
}
|
||
|
customTransition.addCustomActivityTransition(enterResId, exitResId, backgroundColor);
|
||
|
}
|
||
|
|
||
|
public static AnimationOptions makeCustomAnimOptions(String packageName, int enterResId,
|
||
|
int exitResId, @ColorInt int backgroundColor, boolean overrideTaskTransition) {
|
||
|
AnimationOptions options = new AnimationOptions(ANIM_CUSTOM);
|
||
|
options.mPackageName = packageName;
|
||
|
options.mEnterResId = enterResId;
|
||
|
options.mExitResId = exitResId;
|
||
|
options.mBackgroundColor = backgroundColor;
|
||
|
options.mOverrideTaskTransition = overrideTaskTransition;
|
||
|
return options;
|
||
|
}
|
||
|
|
||
|
public static AnimationOptions makeClipRevealAnimOptions(int startX, int startY, int width,
|
||
|
int height) {
|
||
|
AnimationOptions options = new AnimationOptions(ANIM_CLIP_REVEAL);
|
||
|
options.mTransitionBounds.set(startX, startY, startX + width, startY + height);
|
||
|
return options;
|
||
|
}
|
||
|
|
||
|
public static AnimationOptions makeScaleUpAnimOptions(int startX, int startY, int width,
|
||
|
int height) {
|
||
|
AnimationOptions options = new AnimationOptions(ANIM_SCALE_UP);
|
||
|
options.mTransitionBounds.set(startX, startY, startX + width, startY + height);
|
||
|
return options;
|
||
|
}
|
||
|
|
||
|
public static AnimationOptions makeThumbnailAnimOptions(HardwareBuffer srcThumb,
|
||
|
int startX, int startY, boolean scaleUp) {
|
||
|
AnimationOptions options = new AnimationOptions(
|
||
|
scaleUp ? ANIM_THUMBNAIL_SCALE_UP : ANIM_THUMBNAIL_SCALE_DOWN);
|
||
|
options.mTransitionBounds.set(startX, startY, startX, startY);
|
||
|
options.mThumbnail = srcThumb;
|
||
|
return options;
|
||
|
}
|
||
|
|
||
|
public static AnimationOptions makeCrossProfileAnimOptions() {
|
||
|
AnimationOptions options = new AnimationOptions(ANIM_OPEN_CROSS_PROFILE_APPS);
|
||
|
return options;
|
||
|
}
|
||
|
|
||
|
public static AnimationOptions makeSceneTransitionAnimOptions() {
|
||
|
AnimationOptions options = new AnimationOptions(ANIM_SCENE_TRANSITION);
|
||
|
return options;
|
||
|
}
|
||
|
|
||
|
public int getType() {
|
||
|
return mType;
|
||
|
}
|
||
|
|
||
|
public int getEnterResId() {
|
||
|
return mEnterResId;
|
||
|
}
|
||
|
|
||
|
public int getExitResId() {
|
||
|
return mExitResId;
|
||
|
}
|
||
|
|
||
|
public @ColorInt int getBackgroundColor() {
|
||
|
return mBackgroundColor;
|
||
|
}
|
||
|
|
||
|
public boolean getOverrideTaskTransition() {
|
||
|
return mOverrideTaskTransition;
|
||
|
}
|
||
|
|
||
|
public String getPackageName() {
|
||
|
return mPackageName;
|
||
|
}
|
||
|
|
||
|
public Rect getTransitionBounds() {
|
||
|
return mTransitionBounds;
|
||
|
}
|
||
|
|
||
|
public HardwareBuffer getThumbnail() {
|
||
|
return mThumbnail;
|
||
|
}
|
||
|
|
||
|
public int getAnimations() {
|
||
|
return mAnimations;
|
||
|
}
|
||
|
|
||
|
/** Return customized activity transition if existed. */
|
||
|
public CustomActivityTransition getCustomActivityTransition(boolean open) {
|
||
|
return open ? mCustomActivityOpenTransition : mCustomActivityCloseTransition;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void writeToParcel(Parcel dest, int flags) {
|
||
|
dest.writeInt(mType);
|
||
|
dest.writeInt(mEnterResId);
|
||
|
dest.writeInt(mExitResId);
|
||
|
dest.writeInt(mBackgroundColor);
|
||
|
dest.writeBoolean(mOverrideTaskTransition);
|
||
|
dest.writeString(mPackageName);
|
||
|
mTransitionBounds.writeToParcel(dest, flags);
|
||
|
dest.writeTypedObject(mThumbnail, flags);
|
||
|
dest.writeInt(mAnimations);
|
||
|
dest.writeTypedObject(mCustomActivityOpenTransition, flags);
|
||
|
dest.writeTypedObject(mCustomActivityCloseTransition, flags);
|
||
|
}
|
||
|
|
||
|
@NonNull
|
||
|
public static final Creator<AnimationOptions> CREATOR =
|
||
|
new Creator<AnimationOptions>() {
|
||
|
@Override
|
||
|
public AnimationOptions createFromParcel(Parcel in) {
|
||
|
return new AnimationOptions(in);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public AnimationOptions[] newArray(int size) {
|
||
|
return new AnimationOptions[size];
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/** @hide */
|
||
|
@Override
|
||
|
public int describeContents() {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@NonNull
|
||
|
private static String typeToString(int mode) {
|
||
|
return switch (mode) {
|
||
|
case ANIM_CUSTOM -> "CUSTOM";
|
||
|
case ANIM_SCALE_UP -> "SCALE_UP";
|
||
|
case ANIM_THUMBNAIL_SCALE_UP -> "THUMBNAIL_SCALE_UP";
|
||
|
case ANIM_THUMBNAIL_SCALE_DOWN -> "THUMBNAIL_SCALE_DOWN";
|
||
|
case ANIM_SCENE_TRANSITION -> "SCENE_TRANSITION";
|
||
|
case ANIM_CLIP_REVEAL -> "CLIP_REVEAL";
|
||
|
case ANIM_OPEN_CROSS_PROFILE_APPS -> "OPEN_CROSS_PROFILE_APPS";
|
||
|
case ANIM_FROM_STYLE -> "FROM_STYLE";
|
||
|
default -> "<" + mode + ">";
|
||
|
};
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public String toString() {
|
||
|
final StringBuilder sb = new StringBuilder(32);
|
||
|
sb.append("{t=").append(typeToString(mType));
|
||
|
if (mOverrideTaskTransition) {
|
||
|
sb.append(" overrideTask=true");
|
||
|
}
|
||
|
if (!mTransitionBounds.isEmpty()) {
|
||
|
sb.append(" bounds=").append(mTransitionBounds);
|
||
|
}
|
||
|
sb.append('}');
|
||
|
return sb.toString();
|
||
|
}
|
||
|
|
||
|
/** Customized activity transition. */
|
||
|
public static class CustomActivityTransition implements Parcelable {
|
||
|
private int mCustomEnterResId;
|
||
|
private int mCustomExitResId;
|
||
|
private int mCustomBackgroundColor;
|
||
|
|
||
|
/** Returns customize activity animation enter resource id */
|
||
|
public int getCustomEnterResId() {
|
||
|
return mCustomEnterResId;
|
||
|
}
|
||
|
|
||
|
/** Returns customize activity animation exit resource id */
|
||
|
public int getCustomExitResId() {
|
||
|
return mCustomExitResId;
|
||
|
}
|
||
|
|
||
|
/** Returns customize activity animation background color */
|
||
|
public int getCustomBackgroundColor() {
|
||
|
return mCustomBackgroundColor;
|
||
|
}
|
||
|
CustomActivityTransition() {}
|
||
|
|
||
|
CustomActivityTransition(Parcel in) {
|
||
|
mCustomEnterResId = in.readInt();
|
||
|
mCustomExitResId = in.readInt();
|
||
|
mCustomBackgroundColor = in.readInt();
|
||
|
}
|
||
|
|
||
|
/** Add customized activity animation attributes */
|
||
|
public void addCustomActivityTransition(
|
||
|
int enterResId, int exitResId, int backgroundColor) {
|
||
|
mCustomEnterResId = enterResId;
|
||
|
mCustomExitResId = exitResId;
|
||
|
mCustomBackgroundColor = backgroundColor;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int describeContents() {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void writeToParcel(Parcel dest, int flags) {
|
||
|
dest.writeInt(mCustomEnterResId);
|
||
|
dest.writeInt(mCustomExitResId);
|
||
|
dest.writeInt(mCustomBackgroundColor);
|
||
|
}
|
||
|
|
||
|
@NonNull
|
||
|
public static final Creator<CustomActivityTransition> CREATOR =
|
||
|
new Creator<CustomActivityTransition>() {
|
||
|
@Override
|
||
|
public CustomActivityTransition createFromParcel(Parcel in) {
|
||
|
return new CustomActivityTransition(in);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public CustomActivityTransition[] newArray(int size) {
|
||
|
return new CustomActivityTransition[size];
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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;
|
||
|
}
|
||
|
}
|
||
|
}
|