| /* |
| * 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_OPEN_CROSS_PROFILE_APPS; |
| 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.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_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.IntDef; |
| import android.annotation.NonNull; |
| import android.annotation.Nullable; |
| import android.app.ActivityManager; |
| 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 java.util.ArrayList; |
| import java.util.List; |
| |
| /** |
| * Used to communicate information about what is changing during a transition to a TransitionPlayer. |
| * @hide |
| */ |
| public final class TransitionInfo implements Parcelable { |
| |
| /** |
| * 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; |
| |
| /** The container can show on top of lock screen. */ |
| public static final int FLAG_OCCLUDES_KEYGUARD = 1 << 6; |
| |
| /** |
| * 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 first unused bit. This can be used by remotes to attach custom flags to this change. */ |
| public static final int FLAG_FIRST_CUSTOM = 1 << 8; |
| |
| /** @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_OCCLUDES_KEYGUARD, |
| FLAG_DISPLAY_HAS_ALERT_WINDOWS, |
| FLAG_FIRST_CUSTOM |
| }) |
| public @interface ChangeFlags {} |
| |
| 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 AnimationOptions mOptions; |
| |
| /** @hide */ |
| public TransitionInfo(@TransitionType int type, @TransitionFlags int flags) { |
| mType = type; |
| mFlags = flags; |
| } |
| |
| private TransitionInfo(Parcel in) { |
| mType = in.readInt(); |
| mFlags = in.readInt(); |
| in.readList(mChanges, null /* classLoader */); |
| mRootLeash = new SurfaceControl(); |
| mRootLeash.readFromParcel(in); |
| mRootOffset.readFromParcel(in); |
| mOptions = in.readTypedObject(AnimationOptions.CREATOR); |
| } |
| |
| @Override |
| /** @hide */ |
| public void writeToParcel(@NonNull Parcel dest, int flags) { |
| dest.writeInt(mType); |
| dest.writeInt(mFlags); |
| dest.writeList(mChanges); |
| mRootLeash.writeToParcel(dest, flags); |
| mRootOffset.writeToParcel(dest, flags); |
| dest.writeTypedObject(mOptions, flags); |
| } |
| |
| @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 #getRootLeash() */ |
| public void setRootLeash(@NonNull SurfaceControl leash, int offsetLeft, int offsetTop) { |
| mRootLeash = leash; |
| mRootOffset.set(offsetLeft, offsetTop); |
| } |
| |
| public void setAnimationOptions(AnimationOptions options) { |
| mOptions = options; |
| } |
| |
| public @TransitionType int getType() { |
| return mType; |
| } |
| |
| public int getFlags() { |
| return mFlags; |
| } |
| |
| /** |
| * @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. |
| */ |
| @NonNull |
| public SurfaceControl getRootLeash() { |
| if (mRootLeash == null) { |
| throw new IllegalStateException("Trying to get a leash which wasn't set"); |
| } |
| return mRootLeash; |
| } |
| |
| /** @return the offset (relative to the screen) of the root leash. */ |
| @NonNull |
| public Point getRootOffset() { |
| return mRootOffset; |
| } |
| |
| 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 includes keyguard going away. |
| */ |
| public boolean isKeyguardGoingAway() { |
| return (mFlags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY) != 0; |
| } |
| |
| @Override |
| public String toString() { |
| StringBuilder sb = new StringBuilder(); |
| sb.append("{t=" + transitTypeToString(mType) + " f=0x" + Integer.toHexString(mFlags) |
| + " ro=" + mRootOffset + " c=["); |
| for (int i = 0; i < mChanges.size(); ++i) { |
| if (i > 0) { |
| sb.append(','); |
| } |
| sb.append(mChanges.get(i)); |
| } |
| 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 "SHOW"; |
| case TRANSIT_TO_BACK: return "HIDE"; |
| 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_TRANSLUCENT) != 0) { |
| sb.append((sb.length() == 0 ? "" : "|") + "TRANSLUCENT"); |
| } |
| if ((flags & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0) { |
| sb.append((sb.length() == 0 ? "" : "|") + "STARTING_WINDOW_TRANSFER"); |
| } |
| if ((flags & FLAG_IS_VOICE_INTERACTION) != 0) { |
| sb.append((sb.length() == 0 ? "" : "|") + "IS_VOICE_INTERACTION"); |
| } |
| if ((flags & FLAG_IS_DISPLAY) != 0) { |
| sb.append((sb.length() == 0 ? "" : "|") + "IS_DISPLAY"); |
| } |
| if ((flags & FLAG_OCCLUDES_KEYGUARD) != 0) { |
| sb.append((sb.length() == 0 ? "" : "|") + "OCCLUDES_KEYGUARD"); |
| } |
| if ((flags & FLAG_DISPLAY_HAS_ALERT_WINDOWS) != 0) { |
| sb.append((sb.length() == 0 ? "" : "|") + "DISPLAY_HAS_ALERT_WINDOWS"); |
| } |
| if ((flags & FLAG_FIRST_CUSTOM) != 0) { |
| sb.append((sb.length() == 0 ? "" : "|") + "FIRST_CUSTOM"); |
| } |
| 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; |
| |
| // non-visibility changes will just be folded into the parent change, so they aren't |
| // independent either. |
| if (change.getMode() == TRANSIT_CHANGE) 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 indpendent. |
| if (parentChg.getParent() == null) return true; |
| |
| parentChg = info.getChange(parentChg.getParent()); |
| } |
| return false; |
| } |
| |
| /** Represents the change a WindowContainer undergoes during a transition */ |
| public static final class Change implements Parcelable { |
| private final WindowContainerToken mContainer; |
| private WindowContainerToken mParent; |
| private final 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 mStartRotation = ROTATION_UNDEFINED; |
| private int mEndRotation = ROTATION_UNDEFINED; |
| private int mRotationAnimation = ROTATION_ANIMATION_UNSPECIFIED; |
| |
| 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); |
| 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(); |
| mStartRotation = in.readInt(); |
| mEndRotation = in.readInt(); |
| mRotationAnimation = in.readInt(); |
| } |
| |
| /** 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 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 setRotation(@Surface.Rotation int start, @Surface.Rotation int end) { |
| mStartRotation = start; |
| mEndRotation = end; |
| } |
| |
| /** |
| * 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; |
| } |
| |
| /** @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 which action this change represents. */ |
| public @TransitionMode int getMode() { |
| return mMode; |
| } |
| |
| /** @return the flags for this change. */ |
| public @ChangeFlags int getFlags() { |
| return mFlags; |
| } |
| |
| /** |
| * @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 */ |
| @NonNull |
| public ActivityManager.RunningTaskInfo getTaskInfo() { |
| return mTaskInfo; |
| } |
| |
| public boolean getAllowEnterPip() { |
| return mAllowEnterPip; |
| } |
| |
| public int getStartRotation() { |
| return mStartRotation; |
| } |
| |
| public int getEndRotation() { |
| return mEndRotation; |
| } |
| |
| /** @return the rotation animation. */ |
| public int getRotationAnimation() { |
| return mRotationAnimation; |
| } |
| |
| /** @hide */ |
| @Override |
| public void writeToParcel(@NonNull Parcel dest, int flags) { |
| dest.writeTypedObject(mContainer, flags); |
| dest.writeTypedObject(mParent, 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(mStartRotation); |
| dest.writeInt(mEndRotation); |
| dest.writeInt(mRotationAnimation); |
| } |
| |
| @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() { |
| return "{" + mContainer + "(" + mParent + ") leash=" + mLeash |
| + " m=" + modeToString(mMode) + " f=" + flagsToString(mFlags) + " sb=" |
| + mStartAbsBounds + " eb=" + mEndAbsBounds + " eo=" + mEndRelOffset + " r=" |
| + mStartRotation + "->" + mEndRotation + ":" + mRotationAnimation + "}"; |
| } |
| } |
| |
| /** 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 AnimationOptions(int type) { |
| mType = type; |
| } |
| |
| public AnimationOptions(Parcel in) { |
| mType = in.readInt(); |
| mEnterResId = in.readInt(); |
| mExitResId = in.readInt(); |
| mOverrideTaskTransition = in.readBoolean(); |
| mPackageName = in.readString(); |
| mTransitionBounds.readFromParcel(in); |
| mThumbnail = in.readTypedObject(HardwareBuffer.CREATOR); |
| } |
| |
| public static AnimationOptions makeCustomAnimOptions(String packageName, int enterResId, |
| int exitResId, boolean overrideTaskTransition) { |
| AnimationOptions options = new AnimationOptions(ANIM_CUSTOM); |
| options.mPackageName = packageName; |
| options.mEnterResId = enterResId; |
| options.mExitResId = exitResId; |
| 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 makeThumnbnailAnimOptions(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 int getType() { |
| return mType; |
| } |
| |
| public int getEnterResId() { |
| return mEnterResId; |
| } |
| |
| public int getExitResId() { |
| return mExitResId; |
| } |
| |
| public boolean getOverrideTaskTransition() { |
| return mOverrideTaskTransition; |
| } |
| |
| public String getPackageName() { |
| return mPackageName; |
| } |
| |
| public Rect getTransitionBounds() { |
| return mTransitionBounds; |
| } |
| |
| public HardwareBuffer getThumbnail() { |
| return mThumbnail; |
| } |
| |
| @Override |
| public void writeToParcel(Parcel dest, int flags) { |
| dest.writeInt(mType); |
| dest.writeInt(mEnterResId); |
| dest.writeInt(mExitResId); |
| dest.writeBoolean(mOverrideTaskTransition); |
| dest.writeString(mPackageName); |
| mTransitionBounds.writeToParcel(dest, flags); |
| dest.writeTypedObject(mThumbnail, 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) { |
| switch(mode) { |
| case ANIM_CUSTOM: return "ANIM_CUSTOM"; |
| case ANIM_CLIP_REVEAL: return "ANIM_CLIP_REVEAL"; |
| case ANIM_SCALE_UP: return "ANIM_SCALE_UP"; |
| case ANIM_THUMBNAIL_SCALE_UP: return "ANIM_THUMBNAIL_SCALE_UP"; |
| case ANIM_THUMBNAIL_SCALE_DOWN: return "ANIM_THUMBNAIL_SCALE_DOWN"; |
| case ANIM_OPEN_CROSS_PROFILE_APPS: return "ANIM_OPEN_CROSS_PROFILE_APPS"; |
| default: return "<unknown:" + mode + ">"; |
| } |
| } |
| |
| @Override |
| public String toString() { |
| return "{ AnimationOtions type= " + typeToString(mType) + " package=" + mPackageName |
| + " override=" + mOverrideTaskTransition + " b=" + mTransitionBounds + "}"; |
| } |
| } |
| } |