Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a2c4a757 authored by Tony Huang's avatar Tony Huang
Browse files

Make AppTransition animations sharable (4/n)

Migrate ActivityOptions transition animation to shell transition.

Bug: 178678389
Test: manual
Change-Id: Iac219a8eabab7ac7fac73a47e97ec003bbf2d366
parent 15676878
Loading
Loading
Loading
Loading
+161 −0
Original line number Diff line number Diff line
@@ -16,6 +16,12 @@

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.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
@@ -31,6 +37,7 @@ 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;
@@ -102,6 +109,8 @@ public final class TransitionInfo implements Parcelable {
    private SurfaceControl mRootLeash;
    private final Point mRootOffset = new Point();

    private AnimationOptions mOptions;

    /** @hide */
    public TransitionInfo(@WindowManager.TransitionOldType int type,
            @WindowManager.TransitionFlags int flags) {
@@ -116,6 +125,7 @@ public final class TransitionInfo implements Parcelable {
        mRootLeash = new SurfaceControl();
        mRootLeash.readFromParcel(in);
        mRootOffset.readFromParcel(in);
        mOptions = in.readTypedObject(AnimationOptions.CREATOR);
    }

    @Override
@@ -126,6 +136,7 @@ public final class TransitionInfo implements Parcelable {
        dest.writeList(mChanges);
        mRootLeash.writeToParcel(dest, flags);
        mRootOffset.writeToParcel(dest, flags);
        dest.writeTypedObject(mOptions, flags);
    }

    @NonNull
@@ -154,6 +165,10 @@ public final class TransitionInfo implements Parcelable {
        mRootOffset.set(offsetLeft, offsetTop);
    }

    public void setAnimationOptions(AnimationOptions options) {
        mOptions = options;
    }

    public int getType() {
        return mType;
    }
@@ -182,6 +197,10 @@ public final class TransitionInfo implements Parcelable {
        return mRootOffset;
    }

    public AnimationOptions getAnimationOptions() {
        return mOptions;
    }

    @NonNull
    public List<Change> getChanges() {
        return mChanges;
@@ -484,4 +503,146 @@ public final class TransitionInfo implements Parcelable {
                    + mStartRotation + "->" + mEndRotation + "}";
        }
    }

    /** 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 + "}";
        }
    }
}
+24 −4
Original line number Diff line number Diff line
@@ -518,7 +518,7 @@ public class TransitionAnimation {
     * This animation is created when we are doing a thumbnail transition, for the activity that is
     * leaving, and the activity that is entering.
     */
    public Animation createThumbnailEnterExitAnimationLocked(int thumbTransitState,
    public Animation createThumbnailEnterExitAnimationLocked(boolean enter, boolean scaleUp,
            Rect containingFrame, int transit, HardwareBuffer thumbnailHeader,
            Rect startRect) {
        final int appWidth = containingFrame.width();
@@ -529,6 +529,7 @@ public class TransitionAnimation {
        final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
        final int thumbHeightI = thumbnailHeader != null ? thumbnailHeader.getHeight() : appHeight;
        final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
        final int thumbTransitState = getThumbnailTransitionState(enter, scaleUp);

        switch (thumbTransitState) {
            case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: {
@@ -587,8 +588,8 @@ public class TransitionAnimation {
     * This alternate animation is created when we are doing a thumbnail transition, for the
     * activity that is leaving, and the activity that is entering.
     */
    public Animation createAspectScaledThumbnailEnterExitAnimationLocked(int thumbTransitState,
            int orientation, int transit, Rect containingFrame, Rect contentInsets,
    public Animation createAspectScaledThumbnailEnterExitAnimationLocked(boolean enter,
            boolean scaleUp, int orientation, int transit, Rect containingFrame, Rect contentInsets,
            @Nullable Rect surfaceInsets, @Nullable Rect stableInsets, boolean freeform,
            Rect startRect, Rect defaultStartRect) {
        Animation a;
@@ -601,11 +602,11 @@ public class TransitionAnimation {
        final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
        final int thumbStartX = mTmpRect.left - containingFrame.left - contentInsets.left;
        final int thumbStartY = mTmpRect.top - containingFrame.top;
        final int thumbTransitState = getThumbnailTransitionState(enter, scaleUp);

        switch (thumbTransitState) {
            case THUMBNAIL_TRANSITION_ENTER_SCALE_UP:
            case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
                final boolean scaleUp = thumbTransitState == THUMBNAIL_TRANSITION_ENTER_SCALE_UP;
                if (freeform && scaleUp) {
                    a = createAspectScaledThumbnailEnterFreeformAnimationLocked(
                            containingFrame, surfaceInsets, startRect, defaultStartRect);
@@ -842,6 +843,25 @@ public class TransitionAnimation {
                * (MAX_CLIP_REVEAL_TRANSITION_DURATION - DEFAULT_APP_TRANSITION_DURATION));
    }

    /**
     * Return the current thumbnail transition state.
     */
    private int getThumbnailTransitionState(boolean enter, boolean scaleUp) {
        if (enter) {
            if (scaleUp) {
                return THUMBNAIL_TRANSITION_ENTER_SCALE_UP;
            } else {
                return THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN;
            }
        } else {
            if (scaleUp) {
                return THUMBNAIL_TRANSITION_EXIT_SCALE_UP;
            } else {
                return THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN;
            }
        }
    }

    /**
     * Prepares the specified animation with a standard duration, interpolator, etc.
     */
+53 −4
Original line number Diff line number Diff line
@@ -16,6 +16,13 @@

package com.android.wm.shell.transition;

import static android.app.ActivityOptions.ANIM_CLIP_REVEAL;
import static android.app.ActivityOptions.ANIM_CUSTOM;
import static android.app.ActivityOptions.ANIM_NONE;
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.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
@@ -37,6 +44,7 @@ import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Rect;
import android.os.IBinder;
import android.os.SystemProperties;
import android.util.ArrayMap;
import android.view.Choreographer;
import android.view.SurfaceControl;
@@ -61,6 +69,21 @@ import java.util.ArrayList;
public class DefaultTransitionHandler implements Transitions.TransitionHandler {
    private static final int MAX_ANIMATION_DURATION = 3000;

    /**
     * Restrict ability of activities overriding transition animation in a way such that
     * an activity can do it only when the transition happens within a same task.
     *
     * @see android.app.Activity#overridePendingTransition(int, int)
     */
    private static final String DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY =
            "persist.wm.disable_custom_task_animation";

    /**
     * @see #DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY
     */
    static boolean sDisableCustomTaskAnimationProperty =
            SystemProperties.getBoolean(DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY, true);

    private final TransactionPool mTransactionPool;
    private final ShellExecutor mMainExecutor;
    private final ShellExecutor mAnimExecutor;
@@ -117,7 +140,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
            // Don't animate anything that isn't independent.
            if (!TransitionInfo.isIndependent(change, info)) continue;

            Animation a = loadAnimation(info.getType(), info.getFlags(), change);
            Animation a = loadAnimation(info, change);
            if (a != null) {
                startAnimInternal(animations, a, change.getLeash(), onAnimFinish);
            }
@@ -141,13 +164,20 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
    }

    @Nullable
    private Animation loadAnimation(int type, int flags, TransitionInfo.Change change) {
    private Animation loadAnimation(TransitionInfo info, TransitionInfo.Change change) {
        // TODO(b/178678389): It should handle more type animation here
        Animation a = null;

        final int type = info.getType();
        final int flags = info.getFlags();
        final boolean isOpening = Transitions.isOpeningType(type);
        final int changeMode = change.getMode();
        final int changeFlags = change.getFlags();
        final boolean enter = Transitions.isOpeningType(changeMode);
        final boolean isTask = change.getTaskInfo() != null;
        final TransitionInfo.AnimationOptions options = info.getAnimationOptions();
        final int overrideType = options != null ? options.getType() : ANIM_NONE;
        final boolean canCustomContainer = isTask ? !sDisableCustomTaskAnimationProperty : true;

        if (type == TRANSIT_RELAUNCH) {
            a = mTransitionAnimation.createRelaunchAnimation(
@@ -157,6 +187,25 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
                    (changeFlags & FLAG_SHOW_WALLPAPER) != 0);
        } else if (type == TRANSIT_KEYGUARD_UNOCCLUDE) {
            a = mTransitionAnimation.loadKeyguardUnoccludeAnimation();
        } else if (overrideType == ANIM_CUSTOM
                && (canCustomContainer || options.getOverrideTaskTransition())) {
            a = mTransitionAnimation.loadAnimationRes(options.getPackageName(), enter
                    ? options.getEnterResId() : options.getExitResId());
        } else if (overrideType == ANIM_OPEN_CROSS_PROFILE_APPS && enter) {
            a = mTransitionAnimation.loadCrossProfileAppEnterAnimation();
        } else if (overrideType == ANIM_CLIP_REVEAL) {
            a = mTransitionAnimation.createClipRevealAnimationLocked(changeMode, enter,
                    change.getEndAbsBounds(), change.getEndAbsBounds(),
                    options.getTransitionBounds());
        } else if (overrideType == ANIM_SCALE_UP) {
            a = mTransitionAnimation.createScaleUpAnimationLocked(changeMode, enter,
                    change.getEndAbsBounds(), options.getTransitionBounds());
        } else if (overrideType == ANIM_THUMBNAIL_SCALE_UP
                || overrideType == ANIM_THUMBNAIL_SCALE_DOWN) {
            final boolean scaleUp = overrideType == ANIM_THUMBNAIL_SCALE_UP;
            a = mTransitionAnimation.createThumbnailEnterExitAnimationLocked(enter, scaleUp,
                    change.getEndAbsBounds(), changeMode, options.getThumbnail(),
                    options.getTransitionBounds());
        } else if (changeMode == TRANSIT_OPEN && isOpening) {
            if ((changeFlags & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0) {
                // This received a transferred starting window, so don't animate
@@ -165,7 +214,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {

            if ((changeFlags & FLAG_IS_VOICE_INTERACTION) != 0) {
                a = mTransitionAnimation.loadVoiceActivityOpenAnimation(true /** enter */);
            } else if (change.getTaskInfo() != null) {
            } else if (isTask) {
                a = mTransitionAnimation.loadDefaultAnimationAttr(
                        R.styleable.WindowAnimation_taskOpenEnterAnimation);
            } else {
@@ -188,7 +237,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
        } else if (changeMode == TRANSIT_CLOSE && !isOpening) {
            if ((changeFlags & FLAG_IS_VOICE_INTERACTION) != 0) {
                a = mTransitionAnimation.loadVoiceActivityExitAnimation(false /** enter */);
            } else if (change.getTaskInfo() != null) {
            } else if (isTask) {
                a = mTransitionAnimation.loadDefaultAnimationAttr(
                        R.styleable.WindowAnimation_taskCloseExitAnimation);
            } else {
+4 −0
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@ import android.service.voice.VoiceInteractionManagerInternal;
import android.util.Slog;
import android.view.RemoteAnimationDefinition;
import android.window.SizeConfigurationBuckets;
import android.window.TransitionInfo;

import com.android.internal.app.AssistUtils;
import com.android.internal.policy.IKeyguardDismissCallback;
@@ -1014,6 +1015,9 @@ class ActivityClientController extends IActivityClientController.Stub {
                r.mDisplayContent.mAppTransition.overridePendingAppTransition(
                        packageName, enterAnim, exitAnim, null, null,
                        r.mOverrideTaskTransition);
                mService.getTransitionController().setOverrideAnimation(
                        TransitionInfo.AnimationOptions.makeCustomAnimOptions(packageName,
                                enterAnim, exitAnim, r.mOverrideTaskTransition));
            }
        }
        Binder.restoreCallingIdentity(origId);
+18 −0
Original line number Diff line number Diff line
@@ -313,6 +313,7 @@ import android.window.IRemoteTransition;
import android.window.SizeConfigurationBuckets;
import android.window.SplashScreenView.SplashScreenViewParcelable;
import android.window.TaskSnapshot;
import android.window.TransitionInfo.AnimationOptions;
import android.window.WindowContainerToken;

import com.android.internal.R;
@@ -4122,6 +4123,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
    private void applyOptionsAnimation(ActivityOptions pendingOptions, Intent intent) {
        final int animationType = pendingOptions.getAnimationType();
        final DisplayContent displayContent = getDisplayContent();
        AnimationOptions options = null;
        switch (animationType) {
            case ANIM_CUSTOM:
                displayContent.mAppTransition.overridePendingAppTransition(
@@ -4131,11 +4133,17 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
                        pendingOptions.getAnimationStartedListener(),
                        pendingOptions.getAnimationFinishedListener(),
                        pendingOptions.getOverrideTaskTransition());
                options = AnimationOptions.makeCustomAnimOptions(pendingOptions.getPackageName(),
                        pendingOptions.getCustomEnterResId(), pendingOptions.getCustomExitResId(),
                        pendingOptions.getOverrideTaskTransition());
                break;
            case ANIM_CLIP_REVEAL:
                displayContent.mAppTransition.overridePendingAppTransitionClipReveal(
                        pendingOptions.getStartX(), pendingOptions.getStartY(),
                        pendingOptions.getWidth(), pendingOptions.getHeight());
                options = AnimationOptions.makeClipRevealAnimOptions(
                        pendingOptions.getStartX(), pendingOptions.getStartY(),
                        pendingOptions.getWidth(), pendingOptions.getHeight());
                if (intent.getSourceBounds() == null) {
                    intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
                            pendingOptions.getStartY(),
@@ -4147,6 +4155,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
                displayContent.mAppTransition.overridePendingAppTransitionScaleUp(
                        pendingOptions.getStartX(), pendingOptions.getStartY(),
                        pendingOptions.getWidth(), pendingOptions.getHeight());
                options = AnimationOptions.makeScaleUpAnimOptions(
                        pendingOptions.getStartX(), pendingOptions.getStartY(),
                        pendingOptions.getWidth(), pendingOptions.getHeight());
                if (intent.getSourceBounds() == null) {
                    intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
                            pendingOptions.getStartY(),
@@ -4162,6 +4173,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
                        pendingOptions.getStartX(), pendingOptions.getStartY(),
                        pendingOptions.getAnimationStartedListener(),
                        scaleUp);
                options = AnimationOptions.makeThumnbnailAnimOptions(buffer,
                        pendingOptions.getStartX(), pendingOptions.getStartY(), scaleUp);
                if (intent.getSourceBounds() == null && buffer != null) {
                    intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
                            pendingOptions.getStartY(),
@@ -4201,6 +4214,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
            case ANIM_OPEN_CROSS_PROFILE_APPS:
                displayContent.mAppTransition
                        .overridePendingAppTransitionStartCrossProfileApps();
                options = AnimationOptions.makeCrossProfileAnimOptions();
                break;
            case ANIM_NONE:
            case ANIM_UNDEFINED:
@@ -4209,6 +4223,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
                Slog.e(TAG_WM, "applyOptionsLocked: Unknown animationType=" + animationType);
                break;
        }

        if (options != null) {
            mAtmService.getTransitionController().setOverrideAnimation(options);
        }
    }

    void clearAllDrawn() {
Loading