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

Commit 202014db authored by Tracy Zhou's avatar Tracy Zhou
Browse files

App icon transitions with app window in overview

Fixes: 123641382
Test: Swipe up and hold from app when SWIPE_HOME is enabled or swipe up from app when it's not
Change-Id: I1bd35b1b96d66a3996f9b24c9a7e896535fa1ca0
parent 40e06932
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -415,6 +415,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
        });
        mRecentsView.setRecentsAnimationWrapper(mRecentsAnimationWrapper);
        mRecentsView.setClipAnimationHelper(mClipAnimationHelper);
        mRecentsView.setLiveTileOverlay(mLiveTileOverlay);
        mActivity.getRootView().getOverlay().add(mLiveTileOverlay);

        mStateCallback.setState(STATE_LAUNCHER_PRESENT);
@@ -822,6 +823,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
            setShelfState(ShelfAnimState.CANCEL, LINEAR, 0);
            duration = Math.max(MIN_OVERSHOOT_DURATION, duration);
        } else if (endTarget == RECENTS) {
            mLiveTileOverlay.startIconAnimation();
            mRecentsAnimationWrapper.enableInputProxy();
            if (mRecentsView != null) {
                duration = Math.max(duration, mRecentsView.getScroller().getDuration());
@@ -1172,7 +1174,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
        mActivityControlHelper.onSwipeUpComplete(mActivity);

        // Animate the first icon.
        mRecentsView.animateUpRunningTaskIconScale();
        mRecentsView.animateUpRunningTaskIconScale(mLiveTileOverlay.cancelIconAnimation());
        mRecentsView.setSwipeDownShouldLaunchApp(true);

        RecentsModel.INSTANCE.get(mContext).onOverviewShown(false, TAG);
+69 −0
Original line number Diff line number Diff line
package com.android.quickstep.views;

import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.anim.Interpolators.LINEAR;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
@@ -9,16 +15,37 @@ import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.FloatProperty;

import com.android.launcher3.anim.Interpolators;

public class LiveTileOverlay extends Drawable {

    private static final long ICON_ANIM_DURATION = 120;

    private static final FloatProperty<LiveTileOverlay> PROGRESS =
            new FloatProperty<LiveTileOverlay>("progress") {
                @Override
                public void setValue(LiveTileOverlay liveTileOverlay, float progress) {
                    liveTileOverlay.setIconAnimationProgress(progress);
                }

                @Override
                public Float get(LiveTileOverlay liveTileOverlay) {
                    return liveTileOverlay.mIconAnimationProgress;
                }
            };

    private final Paint mPaint = new Paint();

    private Rect mBoundsRect = new Rect();
    private RectF mCurrentRect;
    private float mCornerRadius;
    private Drawable mIcon;
    private Animator mIconAnimator;

    private boolean mDrawEnabled = true;
    private float mIconAnimationProgress = 0f;

    public LiveTileOverlay() {
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
@@ -35,6 +62,33 @@ public class LiveTileOverlay extends Drawable {
        invalidateSelf();
    }

    public void setIcon(Drawable icon) {
        mIcon = icon;
    }

    public void startIconAnimation() {
        if (mIconAnimator != null) {
            mIconAnimator.cancel();
        }
        // This animator must match the icon part of {@link TaskView#FOCUS_TRANSITION} animation.
        mIconAnimator = ObjectAnimator.ofFloat(this, PROGRESS, 1);
        mIconAnimator.setDuration(ICON_ANIM_DURATION).setInterpolator(LINEAR);
        mIconAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                mIconAnimator = null;
            }
        });
        mIconAnimator.start();
    }

    public float cancelIconAnimation() {
        if (mIconAnimator != null) {
            mIconAnimator.cancel();
        }
        return mIconAnimationProgress;
    }

    public void setDrawEnabled(boolean drawEnabled) {
        if (mDrawEnabled != drawEnabled) {
            mDrawEnabled = drawEnabled;
@@ -46,6 +100,16 @@ public class LiveTileOverlay extends Drawable {
    public void draw(Canvas canvas) {
        if (mCurrentRect != null && mDrawEnabled) {
            canvas.drawRoundRect(mCurrentRect, mCornerRadius, mCornerRadius, mPaint);
            if (mIcon != null && mIconAnimationProgress > 0f) {
                canvas.save();
                float scale = Interpolators.clampToProgress(FAST_OUT_SLOW_IN, 0f,
                        1f).getInterpolation(mIconAnimationProgress);
                canvas.translate(mCurrentRect.centerX() - mIcon.getBounds().width() / 2 * scale,
                        mCurrentRect.top - mIcon.getBounds().height() / 2 * scale);
                canvas.scale(scale, scale);
                mIcon.draw(canvas);
                canvas.restore();
            }
        }
    }

@@ -59,4 +123,9 @@ public class LiveTileOverlay extends Drawable {
    public int getOpacity() {
        return PixelFormat.TRANSLUCENT;
    }

    private void setIconAnimationProgress(float progress) {
        mIconAnimationProgress = progress;
        invalidateSelf();
    }
}
+14 −0
Original line number Diff line number Diff line
@@ -278,6 +278,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
    private final int mEmptyMessagePadding;
    private boolean mShowEmptyMessage;
    private Layout mEmptyTextLayout;
    private LiveTileOverlay mLiveTileOverlay;

    private BaseActivity.MultiWindowModeChangedListener mMultiWindowModeChangedListener =
            (inMultiWindowMode) -> {
@@ -855,10 +856,15 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
    }

    public void animateUpRunningTaskIconScale() {
        animateUpRunningTaskIconScale(0);
    }

    public void animateUpRunningTaskIconScale(float startProgress) {
        mRunningTaskIconScaledDown = false;
        TaskView firstTask = getRunningTaskView();
        if (firstTask != null) {
            firstTask.animateIconScaleAndDimIntoView();
            firstTask.setIconScaleAnimStartProgress(startProgress);
        }
    }

@@ -1567,6 +1573,14 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
        mClipAnimationHelper = clipAnimationHelper;
    }

    public void setLiveTileOverlay(LiveTileOverlay liveTileOverlay) {
        mLiveTileOverlay = liveTileOverlay;
    }

    public void updateLiveTileIcon(Drawable icon) {
        mLiveTileOverlay.setIcon(icon);
    }

    public void finishRecentsAnimation(boolean toRecents, Runnable onFinishComplete) {
        if (mRecentsAnimationWrapper == null) {
            if (onFinishComplete != null) {
+10 −1
Original line number Diff line number Diff line
@@ -156,7 +156,8 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
    private float mZoomScale;
    private float mFullscreenProgress;

    private Animator mIconAndDimAnimator;
    private ObjectAnimator mIconAndDimAnimator;
    private float mIconScaleAnimStartProgress = 0;
    private float mFocusTransitionProgress = 1;

    private boolean mShowScreenshot;
@@ -317,6 +318,9 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
            mIconLoadRequest = iconCache.updateIconInBackground(mTask,
                    (task) -> {
                        setIcon(task.icon);
                        if (isRunningTask()) {
                            getRecentsView().updateLiveTileIcon(task.icon);
                        }
                        mDigitalWellBeingToast.initialize(
                                mTask,
                                (saturation, contentDescription) -> {
@@ -380,11 +384,16 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
        mIconView.setScaleY(scale);
    }

    public void setIconScaleAnimStartProgress(float startProgress) {
        mIconScaleAnimStartProgress = startProgress;
    }

    public void animateIconScaleAndDimIntoView() {
        if (mIconAndDimAnimator != null) {
            mIconAndDimAnimator.cancel();
        }
        mIconAndDimAnimator = ObjectAnimator.ofFloat(this, FOCUS_TRANSITION, 1);
        mIconAndDimAnimator.setCurrentFraction(mIconScaleAnimStartProgress);
        mIconAndDimAnimator.setDuration(DIM_ANIM_DURATION).setInterpolator(LINEAR);
        mIconAndDimAnimator.addListener(new AnimatorListenerAdapter() {
            @Override