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

Commit 1c939d4f authored by Chris Li's avatar Chris Li
Browse files

Implement ActivityEmbedding Shell transition animation with showBackdrop

Refactor background color handling from DefaultTransitionHandler to a
helper class, so that we can reuse it for ActivityEmbedding as well.

Bug: 207070762
Test: manual
Change-Id: I6034ddd1928184a969848f0be496247032763b40
parent d316c7d4
Loading
Loading
Loading
Loading
+41 −19
Original line number Diff line number Diff line
@@ -20,6 +20,9 @@ import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET;
import static android.window.TransitionInfo.FLAG_IS_BEHIND_STARTING_WINDOW;

import static com.android.wm.shell.transition.TransitionAnimationHelper.addBackgroundToTransition;
import static com.android.wm.shell.transition.TransitionAnimationHelper.getTransitionBackgroundColorIfSet;

import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
@@ -42,7 +45,6 @@ import com.android.wm.shell.transition.Transitions;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.function.BiFunction;

/** To run the ActivityEmbedding animations. */
class ActivityEmbeddingAnimationRunner {
@@ -85,7 +87,7 @@ class ActivityEmbeddingAnimationRunner {
            @NonNull SurfaceControl.Transaction finishTransaction,
            @NonNull Runnable animationFinishCallback) {
        final List<ActivityEmbeddingAnimationAdapter> adapters =
                createAnimationAdapters(info, startTransaction);
                createAnimationAdapters(info, startTransaction, finishTransaction);
        long duration = 0;
        for (ActivityEmbeddingAnimationAdapter adapter : adapters) {
            duration = Math.max(duration, adapter.getDurationHint());
@@ -129,7 +131,8 @@ class ActivityEmbeddingAnimationRunner {
     */
    @NonNull
    private List<ActivityEmbeddingAnimationAdapter> createAnimationAdapters(
            @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction) {
            @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction,
            @NonNull SurfaceControl.Transaction finishTransaction) {
        boolean isChangeTransition = false;
        for (TransitionInfo.Change change : info.getChanges()) {
            if (change.hasFlags(FLAG_IS_BEHIND_STARTING_WINDOW)) {
@@ -145,23 +148,25 @@ class ActivityEmbeddingAnimationRunner {
            return createChangeAnimationAdapters(info, startTransaction);
        }
        if (Transitions.isClosingType(info.getType())) {
            return createCloseAnimationAdapters(info);
            return createCloseAnimationAdapters(info, startTransaction, finishTransaction);
        }
        return createOpenAnimationAdapters(info);
        return createOpenAnimationAdapters(info, startTransaction, finishTransaction);
    }

    @NonNull
    private List<ActivityEmbeddingAnimationAdapter> createOpenAnimationAdapters(
            @NonNull TransitionInfo info) {
        return createOpenCloseAnimationAdapters(info, true /* isOpening */,
                mAnimationSpec::loadOpenAnimation);
            @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction,
            @NonNull SurfaceControl.Transaction finishTransaction) {
        return createOpenCloseAnimationAdapters(info, startTransaction, finishTransaction,
                true /* isOpening */, mAnimationSpec::loadOpenAnimation);
    }

    @NonNull
    private List<ActivityEmbeddingAnimationAdapter> createCloseAnimationAdapters(
            @NonNull TransitionInfo info) {
        return createOpenCloseAnimationAdapters(info, false /* isOpening */,
                mAnimationSpec::loadCloseAnimation);
            @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction,
            @NonNull SurfaceControl.Transaction finishTransaction) {
        return createOpenCloseAnimationAdapters(info, startTransaction, finishTransaction,
                false /* isOpening */, mAnimationSpec::loadCloseAnimation);
    }

    /**
@@ -170,8 +175,9 @@ class ActivityEmbeddingAnimationRunner {
     */
    @NonNull
    private List<ActivityEmbeddingAnimationAdapter> createOpenCloseAnimationAdapters(
            @NonNull TransitionInfo info, boolean isOpening,
            @NonNull BiFunction<TransitionInfo.Change, Rect, Animation> animationProvider) {
            @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction,
            @NonNull SurfaceControl.Transaction finishTransaction, boolean isOpening,
            @NonNull AnimationProvider animationProvider) {
        // We need to know if the change window is only a partial of the whole animation screen.
        // If so, we will need to adjust it to make the whole animation screen looks like one.
        final List<TransitionInfo.Change> openingChanges = new ArrayList<>();
@@ -194,7 +200,8 @@ class ActivityEmbeddingAnimationRunner {
        final List<ActivityEmbeddingAnimationAdapter> adapters = new ArrayList<>();
        for (TransitionInfo.Change change : openingChanges) {
            final ActivityEmbeddingAnimationAdapter adapter = createOpenCloseAnimationAdapter(
                    change, animationProvider, openingWholeScreenBounds);
                    info, change, startTransaction, finishTransaction, animationProvider,
                    openingWholeScreenBounds);
            if (isOpening) {
                adapter.overrideLayer(offsetLayer++);
            }
@@ -202,7 +209,8 @@ class ActivityEmbeddingAnimationRunner {
        }
        for (TransitionInfo.Change change : closingChanges) {
            final ActivityEmbeddingAnimationAdapter adapter = createOpenCloseAnimationAdapter(
                    change, animationProvider, closingWholeScreenBounds);
                    info, change, startTransaction, finishTransaction, animationProvider,
                    closingWholeScreenBounds);
            if (!isOpening) {
                adapter.overrideLayer(offsetLayer++);
            }
@@ -213,10 +221,18 @@ class ActivityEmbeddingAnimationRunner {

    @NonNull
    private ActivityEmbeddingAnimationAdapter createOpenCloseAnimationAdapter(
            @NonNull TransitionInfo.Change change,
            @NonNull BiFunction<TransitionInfo.Change, Rect, Animation> animationProvider,
            @NonNull Rect wholeAnimationBounds) {
        final Animation animation = animationProvider.apply(change, wholeAnimationBounds);
            @NonNull TransitionInfo info, @NonNull TransitionInfo.Change change,
            @NonNull SurfaceControl.Transaction startTransaction,
            @NonNull SurfaceControl.Transaction finishTransaction,
            @NonNull AnimationProvider animationProvider, @NonNull Rect wholeAnimationBounds) {
        final Animation animation = animationProvider.get(info, change, wholeAnimationBounds);
        // We may want to show a background color for open/close transition.
        final int backgroundColor = getTransitionBackgroundColorIfSet(info, change, animation,
                0 /* defaultColor */);
        if (backgroundColor != 0) {
            addBackgroundToTransition(info.getRootLeash(), backgroundColor, startTransaction,
                    finishTransaction);
        }
        return new ActivityEmbeddingAnimationAdapter(animation, change, change.getLeash(),
                wholeAnimationBounds);
    }
@@ -322,4 +338,10 @@ class ActivityEmbeddingAnimationRunner {
        return ScreenshotUtils.takeScreenshot(t, screenshotChange.getLeash(),
                animationChange.getLeash(), cropBounds, Integer.MAX_VALUE);
    }

    /** To provide an {@link Animation} based on the transition infos. */
    private interface AnimationProvider {
        Animation get(@NonNull TransitionInfo info, @NonNull TransitionInfo.Change change,
                @NonNull Rect animationBounds);
    }
}
+34 −17
Original line number Diff line number Diff line
@@ -17,6 +17,9 @@
package com.android.wm.shell.activityembedding;


import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_NONE;
import static com.android.wm.shell.transition.TransitionAnimationHelper.loadAttributeAnimation;

import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
@@ -33,7 +36,6 @@ import android.window.TransitionInfo;

import androidx.annotation.NonNull;

import com.android.internal.R;
import com.android.internal.policy.TransitionAnimation;
import com.android.wm.shell.transition.Transitions;

@@ -175,16 +177,20 @@ class ActivityEmbeddingAnimationSpec {
    }

    @NonNull
    Animation loadOpenAnimation(@NonNull TransitionInfo.Change change,
            @NonNull Rect wholeAnimationBounds) {
    Animation loadOpenAnimation(@NonNull TransitionInfo info,
            @NonNull TransitionInfo.Change change, @NonNull Rect wholeAnimationBounds) {
        final boolean isEnter = Transitions.isOpeningType(change.getMode());
        final Animation animation;
        // TODO(b/207070762):
        // 1. Implement clearTop version: R.anim.task_fragment_clear_top_close_enter/exit
        // 2. Implement edgeExtension version
        // TODO(b/207070762): Implement edgeExtension version
        if (shouldShowBackdrop(info, change)) {
            animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
                    ? com.android.internal.R.anim.task_fragment_clear_top_open_enter
                    : com.android.internal.R.anim.task_fragment_clear_top_open_exit);
        } else {
            animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
                ? R.anim.task_fragment_open_enter
                : R.anim.task_fragment_open_exit);
                    ? com.android.internal.R.anim.task_fragment_open_enter
                    : com.android.internal.R.anim.task_fragment_open_exit);
        }
        // Use the whole animation bounds instead of the change bounds, so that when multiple change
        // targets are opening at the same time, the animation applied to each will be the same.
        // Otherwise, we may see gap between the activities that are launching together.
@@ -195,16 +201,20 @@ class ActivityEmbeddingAnimationSpec {
    }

    @NonNull
    Animation loadCloseAnimation(@NonNull TransitionInfo.Change change,
            @NonNull Rect wholeAnimationBounds) {
    Animation loadCloseAnimation(@NonNull TransitionInfo info,
            @NonNull TransitionInfo.Change change, @NonNull Rect wholeAnimationBounds) {
        final boolean isEnter = Transitions.isOpeningType(change.getMode());
        final Animation animation;
        // TODO(b/207070762):
        // 1. Implement clearTop version: R.anim.task_fragment_clear_top_close_enter/exit
        // 2. Implement edgeExtension version
        // TODO(b/207070762): Implement edgeExtension version
        if (shouldShowBackdrop(info, change)) {
            animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
                    ? com.android.internal.R.anim.task_fragment_clear_top_close_enter
                    : com.android.internal.R.anim.task_fragment_clear_top_close_exit);
        } else {
            animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
                ? R.anim.task_fragment_close_enter
                : R.anim.task_fragment_close_exit);
                    ? com.android.internal.R.anim.task_fragment_close_enter
                    : com.android.internal.R.anim.task_fragment_close_exit);
        }
        // Use the whole animation bounds instead of the change bounds, so that when multiple change
        // targets are closing at the same time, the animation applied to each will be the same.
        // Otherwise, we may see gap between the activities that are finishing together.
@@ -213,4 +223,11 @@ class ActivityEmbeddingAnimationSpec {
        animation.scaleCurrentDuration(mTransitionAnimationScaleSetting);
        return animation;
    }

    private boolean shouldShowBackdrop(@NonNull TransitionInfo info,
            @NonNull TransitionInfo.Change change) {
        final Animation a = loadAttributeAnimation(info, change, WALLPAPER_TRANSITION_NONE,
                mTransitionAnimation);
        return a != null && a.getShowBackdrop();
    }
}
+11 −146
Original line number Diff line number Diff line
@@ -18,13 +18,11 @@ 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_FROM_STYLE;
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.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_RESOURCE_UPDATED;
import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_TYPE;
@@ -43,7 +41,6 @@ import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_RELAUNCH;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.view.WindowManager.transitTypeToString;
import static android.window.TransitionInfo.FLAG_CROSS_PROFILE_OWNER_THUMBNAIL;
import static android.window.TransitionInfo.FLAG_CROSS_PROFILE_WORK_THUMBNAIL;
import static android.window.TransitionInfo.FLAG_DISPLAY_HAS_ALERT_WINDOWS;
@@ -59,6 +56,10 @@ import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITI
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_INTRA_OPEN;
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_NONE;
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_OPEN;
import static com.android.wm.shell.transition.TransitionAnimationHelper.addBackgroundToTransition;
import static com.android.wm.shell.transition.TransitionAnimationHelper.getTransitionBackgroundColorIfSet;
import static com.android.wm.shell.transition.TransitionAnimationHelper.loadAttributeAnimation;
import static com.android.wm.shell.transition.TransitionAnimationHelper.sDisableCustomTaskAnimationProperty;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -74,7 +75,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Insets;
import android.graphics.Paint;
import android.graphics.PixelFormat;
@@ -84,7 +84,6 @@ import android.graphics.drawable.Drawable;
import android.hardware.HardwareBuffer;
import android.os.Handler;
import android.os.IBinder;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.view.Choreographer;
@@ -122,21 +121,6 @@ import java.util.function.Consumer;
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 DisplayController mDisplayController;
    private final Context mContext;
@@ -431,22 +415,8 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
                    cornerRadius = 0;
                }

                if (a.getShowBackdrop()) {
                    if (info.getAnimationOptions().getBackgroundColor() != 0) {
                        // If available use the background color provided through AnimationOptions
                        backgroundColorForTransition =
                                info.getAnimationOptions().getBackgroundColor();
                    } else if (a.getBackdropColor() != 0) {
                        // Otherwise fallback on the background color provided through the animation
                        // definition.
                        backgroundColorForTransition = a.getBackdropColor();
                    } else if (change.getBackgroundColor() != 0) {
                        // Otherwise default to the window's background color if provided through
                        // the theme as the background color for the animation - the top most window
                        // with a valid background color and showBackground set takes precedence.
                        backgroundColorForTransition = change.getBackgroundColor();
                    }
                }
                backgroundColorForTransition = getTransitionBackgroundColorIfSet(info, change, a,
                        backgroundColorForTransition);

                boolean delayedEdgeExtension = false;
                if (!isTask && a.hasExtension()) {
@@ -668,29 +638,6 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
        return edgeExtensionLayer;
    }

    private void addBackgroundToTransition(
            @NonNull SurfaceControl rootLeash,
            @ColorInt int color,
            @NonNull SurfaceControl.Transaction startTransaction,
            @NonNull SurfaceControl.Transaction finishTransaction
    ) {
        final Color bgColor = Color.valueOf(color);
        final float[] colorArray = new float[] { bgColor.red(), bgColor.green(), bgColor.blue() };

        final SurfaceControl animationBackgroundSurface = new SurfaceControl.Builder()
                .setName("Animation Background")
                .setParent(rootLeash)
                .setColorLayer()
                .setOpaque(true)
                .build();

        startTransaction
                .setLayer(animationBackgroundSurface, Integer.MIN_VALUE)
                .setColor(animationBackgroundSurface, colorArray)
                .show(animationBackgroundSurface);
        finishTransaction.remove(animationBackgroundSurface);
    }

    @Nullable
    @Override
    public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
@@ -704,9 +651,9 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
    }

    @Nullable
    private Animation loadAnimation(TransitionInfo info, TransitionInfo.Change change,
            int wallpaperTransit) {
        Animation a = null;
    private Animation loadAnimation(@NonNull TransitionInfo info,
            @NonNull TransitionInfo.Change change, int wallpaperTransit) {
        Animation a;

        final int type = info.getType();
        final int flags = info.getFlags();
@@ -717,12 +664,10 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
        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;
        final boolean canCustomContainer = !isTask || !sDisableCustomTaskAnimationProperty;
        final Rect endBounds = Transitions.isClosingType(changeMode)
                ? mRotator.getEndBoundsInStartRotation(change)
                : change.getEndAbsBounds();
        final boolean isDream =
                isTask && change.getTaskInfo().topActivityType == ACTIVITY_TYPE_DREAM;

        if (info.isKeyguardGoingAway()) {
            a = mTransitionAnimation.loadKeyguardExitAnimation(flags,
@@ -763,87 +708,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
            // This received a transferred starting window, so don't animate
            return null;
        } else {
            int animAttr = 0;
            boolean translucent = false;
            if (isDream) {
                if (type == TRANSIT_OPEN) {
                    animAttr = enter
                            ? R.styleable.WindowAnimation_dreamActivityOpenEnterAnimation
                            : R.styleable.WindowAnimation_dreamActivityOpenExitAnimation;
                } else if (type == TRANSIT_CLOSE) {
                    animAttr = enter
                            ? 0
                            : R.styleable.WindowAnimation_dreamActivityCloseExitAnimation;
                }
            } else if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_OPEN) {
                animAttr = enter
                        ? R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation
                        : R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation;
            } else if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_CLOSE) {
                animAttr = enter
                        ? R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation
                        : R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation;
            } else if (wallpaperTransit == WALLPAPER_TRANSITION_OPEN) {
                animAttr = enter
                        ? R.styleable.WindowAnimation_wallpaperOpenEnterAnimation
                        : R.styleable.WindowAnimation_wallpaperOpenExitAnimation;
            } else if (wallpaperTransit == WALLPAPER_TRANSITION_CLOSE) {
                animAttr = enter
                        ? R.styleable.WindowAnimation_wallpaperCloseEnterAnimation
                        : R.styleable.WindowAnimation_wallpaperCloseExitAnimation;
            } else if (type == TRANSIT_OPEN) {
                // We will translucent open animation for translucent activities and tasks. Choose
                // WindowAnimation_activityOpenEnterAnimation and set translucent here, then
                // TransitionAnimation loads appropriate animation later.
                if ((changeFlags & FLAG_TRANSLUCENT) != 0 && enter) {
                    translucent = true;
                }
                if (isTask && !translucent) {
                    animAttr = enter
                            ? R.styleable.WindowAnimation_taskOpenEnterAnimation
                            : R.styleable.WindowAnimation_taskOpenExitAnimation;
                } else {
                    animAttr = enter
                            ? R.styleable.WindowAnimation_activityOpenEnterAnimation
                            : R.styleable.WindowAnimation_activityOpenExitAnimation;
                }
            } else if (type == TRANSIT_TO_FRONT) {
                animAttr = enter
                        ? R.styleable.WindowAnimation_taskToFrontEnterAnimation
                        : R.styleable.WindowAnimation_taskToFrontExitAnimation;
            } else if (type == TRANSIT_CLOSE) {
                if (isTask) {
                    animAttr = enter
                            ? R.styleable.WindowAnimation_taskCloseEnterAnimation
                            : R.styleable.WindowAnimation_taskCloseExitAnimation;
                } else {
                    if ((changeFlags & FLAG_TRANSLUCENT) != 0 && !enter) {
                        translucent = true;
                    }
                    animAttr = enter
                            ? R.styleable.WindowAnimation_activityCloseEnterAnimation
                            : R.styleable.WindowAnimation_activityCloseExitAnimation;
                }
            } else if (type == TRANSIT_TO_BACK) {
                animAttr = enter
                        ? R.styleable.WindowAnimation_taskToBackEnterAnimation
                        : R.styleable.WindowAnimation_taskToBackExitAnimation;
            }

            if (animAttr != 0) {
                if (overrideType == ANIM_FROM_STYLE && canCustomContainer) {
                    a = mTransitionAnimation
                            .loadAnimationAttr(options.getPackageName(), options.getAnimations(),
                                    animAttr, translucent);
                } else {
                    a = mTransitionAnimation.loadDefaultAnimationAttr(animAttr, translucent);
                }
            }

            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
                    "loadAnimation: anim=%s animAttr=0x%x type=%s isEntrance=%b", a, animAttr,
                    transitTypeToString(type),
                    enter);
            a = loadAttributeAnimation(info, change, wallpaperTransit, mTransitionAnimation);
        }

        if (a != null) {
+220 −0

File added.

Preview size limit exceeded, changes collapsed.