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
This commit is contained in:
parent
40e0693234
commit
202014db2f
|
@ -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);
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue