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

Commit e5900148 authored by Kevin's avatar Kevin
Browse files

Polish app => recents animation (3/N)

This CL takes the current scale down animation and updates its
interpolators and durations to match the UX spec. In addition, we move
the core logic to a helper method as the whole remote animation will
have other animations as well in the future.

Bug: 132112131
Test: Manual
Change-Id: I68b1d623b1b2c980dc34e41bbb5460cc021b5887
parent 1b4b960f
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -23,7 +23,6 @@ import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MOD
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.util.Log;
import android.view.View;

import com.android.launcher3.BaseDraggingActivity;
import com.android.quickstep.util.RemoteAnimationProvider;
@@ -119,7 +118,7 @@ final class AppToOverviewAnimationProvider<T extends BaseDraggingActivity> imple
            return anim;
        }

        mRecentsView.playAppScaleDownAnim(anim, closingAppTarget, recentsTarget);
        mRecentsView.playRemoteAppToRecentsAnimation(anim, closingAppTarget, recentsTarget);

        return anim;
    }
+45 −33
Original line number Diff line number Diff line
@@ -20,7 +20,6 @@ import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static androidx.recyclerview.widget.LinearLayoutManager.VERTICAL;

import static com.android.launcher3.anim.Interpolators.ACCEL_2;
import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
import static com.android.quickstep.TaskAdapter.CHANGE_EVENT_TYPE_EMPTY_TO_CONTENT;
import static com.android.quickstep.TaskAdapter.ITEM_TYPE_CLEAR_ALL;
import static com.android.quickstep.TaskAdapter.ITEM_TYPE_TASK;
@@ -45,6 +44,7 @@ import android.util.FloatProperty;
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewTreeObserver;
import android.view.animation.PathInterpolator;
import android.widget.FrameLayout;

import androidx.annotation.NonNull;
@@ -111,10 +111,15 @@ public final class IconRecentsView extends FrameLayout implements Insettable {
    private static final float ITEM_ANIMATE_OUT_TRANSLATION_X_RATIO = .25f;
    private static final long CLEAR_ALL_FADE_DELAY = 120;

    private static final long APP_TO_THUMBNAIL_FADE_DURATION = 50;
    private static final long APP_SCALE_DOWN_DURATION = 400;
    private static final long REMOTE_TO_RECENTS_APP_SCALE_DOWN_DURATION = 300;

    public static final long REMOTE_APP_TO_OVERVIEW_DURATION = APP_SCALE_DOWN_DURATION;
    private static final PathInterpolator FAST_OUT_SLOW_IN_1 =
            new PathInterpolator(.4f, 0f, 0f, 1f);
    private static final PathInterpolator FAST_OUT_SLOW_IN_2 =
            new PathInterpolator(.5f, 0f, 0f, 1f);

    public static final long REMOTE_APP_TO_OVERVIEW_DURATION =
            REMOTE_TO_RECENTS_APP_SCALE_DOWN_DURATION;

    /**
     * A ratio representing the view's relative placement within its padded space. For example, 0
@@ -397,7 +402,7 @@ public final class IconRecentsView extends FrameLayout implements Insettable {
     *
     * @return the thumbnail view if laid out
     */
    public @Nullable View getBottomThumbnailView() {
    private @Nullable View getBottomThumbnailView() {
        ArrayList<TaskItemView> taskViews = getTaskViews();
        if (taskViews.isEmpty()) {
            return null;
@@ -580,18 +585,17 @@ public final class IconRecentsView extends FrameLayout implements Insettable {
    }

    /**
     * Animate a closing app to scale down to the location of the thumbnail view in recents.
     * Play remote animation from app to recents. This should scale the currently closing app down
     * to the recents thumbnail.
     *
     * @param anim animator set
     * @param appTarget the app surface thats closing
     * @param recentsTarget the surface containing recents
     */
    public void playAppScaleDownAnim(@NonNull AnimatorSet anim,
    public void playRemoteAppToRecentsAnimation(@NonNull AnimatorSet anim,
            @NonNull RemoteAnimationTargetCompat appTarget,
            @NonNull RemoteAnimationTargetCompat recentsTarget) {

        View thumbnailView = getBottomThumbnailView();

        if (thumbnailView == null) {
            // This can be null if there were previously 0 tasks and the recycler view has not had
            // enough time to take in the data change, bind a new view, and lay out the new view.
@@ -599,15 +603,28 @@ public final class IconRecentsView extends FrameLayout implements Insettable {
            anim.play(ValueAnimator.ofInt(0, 1).setDuration(REMOTE_APP_TO_OVERVIEW_DURATION));
        }

        // TODO: Play other animations in app => recents
        playRemoteAppScaleDownAnim(anim, appTarget, recentsTarget, thumbnailView);
    }

    /**
     * Play the scale down animation for the remote app to recents animation where the app surface
     * scales down to where the thumbnail is.
     *
     * @param anim animator set to play on
     * @param appTarget closing app target
     * @param recentsTarget opening recents target
     * @param thumbnailView thumbnail view to animate to
     */
    private void playRemoteAppScaleDownAnim(@NonNull AnimatorSet anim,
            @NonNull RemoteAnimationTargetCompat appTarget,
            @NonNull RemoteAnimationTargetCompat recentsTarget,
            @NonNull View thumbnailView) {
        // Identify where the entering remote app should animate to.
        Rect endRect = new Rect();
        thumbnailView.getGlobalVisibleRect(endRect);

        Rect appBounds = appTarget.sourceContainerBounds;

        ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 1);
        valueAnimator.setDuration(APP_SCALE_DOWN_DURATION);

        SyncRtSurfaceTransactionApplierCompat surfaceApplier =
                new SyncRtSurfaceTransactionApplierCompat(thumbnailView);

@@ -618,7 +635,9 @@ public final class IconRecentsView extends FrameLayout implements Insettable {
        params[0] = new SurfaceParams(recentsTarget.leash, 1f, null /* matrix */,
                null /* windowCrop */, getLayer(recentsTarget, boostedMode), 0 /* cornerRadius */);

        valueAnimator.addUpdateListener(new MultiValueUpdateListener() {
        ValueAnimator remoteAppAnim = ValueAnimator.ofInt(0, 1);
        remoteAppAnim.setDuration(REMOTE_TO_RECENTS_APP_SCALE_DOWN_DURATION);
        remoteAppAnim.addUpdateListener(new MultiValueUpdateListener() {
            private final FloatProp mScaleX;
            private final FloatProp mScaleY;
            private final FloatProp mTranslationX;
@@ -628,30 +647,27 @@ public final class IconRecentsView extends FrameLayout implements Insettable {
            {
                // Scale down and move to view location.
                float endScaleX = ((float) endRect.width()) / appBounds.width();
                mScaleX = new FloatProp(1f, endScaleX, 0, APP_SCALE_DOWN_DURATION,
                        ACCEL_DEACCEL);
                mScaleX = new FloatProp(1f, endScaleX, 0, REMOTE_TO_RECENTS_APP_SCALE_DOWN_DURATION,
                        FAST_OUT_SLOW_IN_1);
                float endScaleY = ((float) endRect.height()) / appBounds.height();
                mScaleY = new FloatProp(1f, endScaleY, 0, APP_SCALE_DOWN_DURATION,
                        ACCEL_DEACCEL);
                mScaleY = new FloatProp(1f, endScaleY, 0, REMOTE_TO_RECENTS_APP_SCALE_DOWN_DURATION,
                        FAST_OUT_SLOW_IN_1);
                float endTranslationX = endRect.left -
                        (appBounds.width() - thumbnailView.getWidth()) / 2.0f;
                mTranslationX = new FloatProp(0, endTranslationX, 0, APP_SCALE_DOWN_DURATION,
                        ACCEL_DEACCEL);
                mTranslationX = new FloatProp(0, endTranslationX, 0,
                        REMOTE_TO_RECENTS_APP_SCALE_DOWN_DURATION, FAST_OUT_SLOW_IN_1);
                float endTranslationY = endRect.top -
                        (appBounds.height() - thumbnailView.getHeight()) / 2.0f;
                mTranslationY = new FloatProp(0, endTranslationY, 0, APP_SCALE_DOWN_DURATION,
                        ACCEL_DEACCEL);

                // Fade out quietly near the end to be replaced by the real view.
                mAlpha = new FloatProp(1.0f, 0,
                        APP_SCALE_DOWN_DURATION - APP_TO_THUMBNAIL_FADE_DURATION,
                        APP_TO_THUMBNAIL_FADE_DURATION, ACCEL_2);
                mTranslationY = new FloatProp(0, endTranslationY, 0,
                        REMOTE_TO_RECENTS_APP_SCALE_DOWN_DURATION, FAST_OUT_SLOW_IN_2);
                mAlpha = new FloatProp(1.0f, 0, 0, REMOTE_TO_RECENTS_APP_SCALE_DOWN_DURATION,
                        ACCEL_2);
            }

            @Override
            public void onUpdate(float percent) {
                Matrix m = new Matrix();
                m.setScale(mScaleX.value, mScaleY.value,
                m.preScale(mScaleX.value, mScaleY.value,
                        appBounds.width() / 2.0f, appBounds.height() / 2.0f);
                m.postTranslate(mTranslationX.value, mTranslationY.value);

@@ -661,11 +677,7 @@ public final class IconRecentsView extends FrameLayout implements Insettable {
                surfaceApplier.scheduleApply(params);
            }
        });
        anim.play(valueAnimator);
    }

    public long getAppToOverviewAnimationDuration() {
        return APP_SCALE_DOWN_DURATION;
        anim.play(remoteAppAnim);
    }

    @Override