From 76e2775bb638757216fcaa96f8a62654fb56b19a Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Thu, 29 Mar 2018 21:25:32 -0700 Subject: [PATCH] Moving some methods related to task launch animation to recents view and related classes. This allows the common animation to be used in fallback activity. Bug: 75979063 Change-Id: I2b5bf5e66406621305b9a076793434f9c5cecdfd --- .../LauncherAppTransitionManagerImpl.java | 219 +++--------------- .../uioverrides/TaskViewTouchController.java | 17 +- .../quickstep/views/LauncherRecentsView.java | 26 +++ .../android/quickstep/views/RecentsView.java | 93 ++++++++ .../com/android/quickstep/views/TaskView.java | 20 ++ .../anim/AnimatorPlaybackController.java | 5 + 6 files changed, 178 insertions(+), 202 deletions(-) diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java index f1471a7d52..8f2e104dab 100644 --- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java @@ -17,7 +17,6 @@ package com.android.launcher3; import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; -import static com.android.launcher3.LauncherState.ALL_APPS_HEADER_EXTRA; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS; import static com.android.systemui.shared.recents.utilities.Utilities.getNextFrameNumber; @@ -53,7 +52,6 @@ import com.android.launcher3.InsettableFrameLayout.LayoutParams; import com.android.launcher3.allapps.AllAppsTransitionController; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.Interpolators; -import com.android.launcher3.anim.PropertyListBuilder; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.graphics.DrawableFactory; import com.android.launcher3.shortcuts.DeepShortcutView; @@ -93,8 +91,8 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag private static final int CLOSING_TRANSITION_DURATION_MS = 350; // Progress = 0: All apps is fully pulled up, Progress = 1: All apps is fully pulled down. - private static final float ALL_APPS_PROGRESS_OFF_SCREEN = 1.3059858f; - private static final float ALL_APPS_PROGRESS_OVERSHOOT = 0.99581414f; + public static final float ALL_APPS_PROGRESS_OFF_SCREEN = 1.3059858f; + public static final float ALL_APPS_PROGRESS_OVERSHOOT = 0.99581414f; private final DragLayer mDragLayer; private final Launcher mLauncher; @@ -148,7 +146,14 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag @Override public AnimatorSet getAnimator(RemoteAnimationTargetCompat[] targetCompats) { - AnimatorSet anim = createLaunchAnimatorForView(v, targetCompats); + Animator[] anims = composeRecentsLaunchAnimator(v, targetCompats); + AnimatorSet anim = new AnimatorSet(); + if (anims != null) { + anim.playTogether(anims); + } else { + anim.play(getLauncherAnimators(v, targetCompats)); + anim.play(getWindowAnimators(v, targetCompats)); + } mLauncher.getStateManager().setCurrentAnimation(anim); return anim; } @@ -167,19 +172,6 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag return getDefaultActivityLaunchOptions(launcher, v); } - private AnimatorSet createLaunchAnimatorForView(View v, RemoteAnimationTargetCompat[] targets) { - Animator[] anims = composeRecentsLaunchAnimator(v, new AnimConfig(targets, - RECENTS_LAUNCH_DURATION, Interpolators.TOUCH_RESPONSE_INTERPOLATOR)); - AnimatorSet anim = new AnimatorSet(); - if (anims != null) { - anim.playTogether(anims); - } else { - anim.play(getLauncherAnimators(v, targets)); - anim.play(getWindowAnimators(v, targets)); - } - return anim; - } - /** * Try to find a TaskView that corresponds with the component of the launched view. * @@ -238,32 +230,21 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag return taskView; } - public AnimatorSet composeUserControlledRecentsLaunchAnimator(TaskView v, AnimConfig config) { - Animator[] anims = composeRecentsLaunchAnimator(v, config); - AnimatorSet anim = new AnimatorSet(); - anim.playTogether(anims); - return anim; - } - /** * Composes the animations for a launch from the recents list if possible. */ - private Animator[] composeRecentsLaunchAnimator(View v, AnimConfig config) { + private Animator[] composeRecentsLaunchAnimator(View v, + RemoteAnimationTargetCompat[] targets) { // Ensure recents is actually visible if (!mLauncher.getStateManager().getState().overviewUi) { return null; } RecentsView recentsView = mLauncher.getOverviewPanel(); - boolean launcherClosing = launcherIsATargetWithMode(config.targets, MODE_CLOSING); - if (config.userControlled) { - // We don't pass any targets when creating a user-controlled animation. In this case, - // assume launcher is closing. - launcherClosing = true; - } + boolean launcherClosing = launcherIsATargetWithMode(targets, MODE_CLOSING); boolean skipLauncherChanges = !launcherClosing; - TaskView taskView = findTaskViewToLaunch(mLauncher, v, config.targets); + TaskView taskView = findTaskViewToLaunch(mLauncher, v, targets); if (taskView == null) { return null; } @@ -272,7 +253,10 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag Animator launcherAnim; final AnimatorListenerAdapter windowAnimEndListener; if (launcherClosing) { - launcherAnim = getRecentsLauncherAnimator(recentsView, taskView, config); + launcherAnim = recentsView.createAdjacentPageAnimForTaskLaunch(taskView); + launcherAnim.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR); + launcherAnim.setDuration(RECENTS_LAUNCH_DURATION); + // Make sure recents gets fixed up by resetting task alphas and scales, etc. windowAnimEndListener = mReapplyStateListener; } else { @@ -289,150 +273,25 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag }; } - Animator windowAnim = getRecentsWindowAnimator(taskView, skipLauncherChanges, config); - if (!config.userControlled) { - // Don't reset properties if the animation is user-controlled, as we will run the - // "real" (not user controlled) animation from where they left off when they let go. - windowAnim.addListener(windowAnimEndListener); - } + Animator windowAnim = getRecentsWindowAnimator(taskView, skipLauncherChanges, targets); + windowAnim.addListener(windowAnimEndListener); return new Animator[] {launcherAnim, windowAnim}; } - /** - * Animate adjacent tasks off screen while scaling up, and translate hotseat off screen as well. - * - * If launching one of the adjacent tasks, parallax the center task and other adjacent task - * to the right. - */ - private Animator getRecentsLauncherAnimator(RecentsView recentsView, TaskView v, - AnimConfig config) { - AnimatorSet launcherAnimator = new AnimatorSet(); - - int launchedTaskIndex = recentsView.indexOfChild(v); - int centerTaskIndex = recentsView.getCurrentPage(); - boolean launchingCenterTask = launchedTaskIndex == centerTaskIndex; - boolean isRtl = recentsView.isRtl(); - - RecentsAnimationInterpolator recentsInterpolator = getRecentsInterpolator(v); - TaskWindowBounds endInterpolation = recentsInterpolator.interpolate(1); - float toScale = endInterpolation.taskScale; - float toTranslationY = endInterpolation.taskY; - float displacementX = v.getWidth() * (toScale - v.getScaleX()); - if (launchingCenterTask) { - - if (launchedTaskIndex - 1 >= 0) { - TaskView adjacentPage1 = (TaskView) recentsView.getPageAt(launchedTaskIndex - 1); - ObjectAnimator adjacentTask1ScaleAndTranslate = - LauncherAnimUtils.ofPropertyValuesHolder(adjacentPage1, - new PropertyListBuilder() - .scale(adjacentPage1.getScaleX() * toScale) - .translationY(toTranslationY) - .translationX(isRtl ? displacementX : -displacementX) - .build()); - adjacentTask1ScaleAndTranslate.setInterpolator(config.interpolator); - adjacentTask1ScaleAndTranslate.setDuration(config.duration); - launcherAnimator.play(adjacentTask1ScaleAndTranslate); - } - if (launchedTaskIndex + 1 < recentsView.getPageCount()) { - TaskView adjacentTask2 = (TaskView) recentsView.getPageAt(launchedTaskIndex + 1); - ObjectAnimator adjacentTask2ScaleAndTranslate = - LauncherAnimUtils.ofPropertyValuesHolder(adjacentTask2, - new PropertyListBuilder() - .scale(adjacentTask2.getScaleX() * toScale) - .translationY(toTranslationY) - .translationX(isRtl ? -displacementX : displacementX) - .build()); - adjacentTask2ScaleAndTranslate.setInterpolator(config.interpolator); - adjacentTask2ScaleAndTranslate.setDuration(config.duration); - launcherAnimator.play(adjacentTask2ScaleAndTranslate); - } - } else { - // We are launching an adjacent task, so parallax the center and other adjacent task. - TaskView centerTask = (TaskView) recentsView.getPageAt(centerTaskIndex); - ObjectAnimator centerTaskParallaxOffscreen = - LauncherAnimUtils.ofPropertyValuesHolder(centerTask, - new PropertyListBuilder() - .translationX(isRtl ? -displacementX : displacementX) - .build()); - centerTaskParallaxOffscreen.setInterpolator(config.interpolator); - centerTaskParallaxOffscreen.setDuration(config.duration); - launcherAnimator.play(centerTaskParallaxOffscreen); - int otherAdjacentTaskIndex = centerTaskIndex + (centerTaskIndex - launchedTaskIndex); - if (otherAdjacentTaskIndex >= 0 - && otherAdjacentTaskIndex < recentsView.getPageCount()) { - TaskView otherAdjacentTask = (TaskView) recentsView.getPageAt( - otherAdjacentTaskIndex); - ObjectAnimator otherAdjacentTaskParallaxOffscreen = - LauncherAnimUtils.ofPropertyValuesHolder(otherAdjacentTask, - new PropertyListBuilder() - .translationX(isRtl ? -displacementX : displacementX) - .scale(1) - .build()); - otherAdjacentTaskParallaxOffscreen.setInterpolator(config.interpolator); - otherAdjacentTaskParallaxOffscreen.setDuration(config.duration); - launcherAnimator.play(otherAdjacentTaskParallaxOffscreen); - } - } - - float allAppsProgressOffscreen = ALL_APPS_PROGRESS_OFF_SCREEN; - LauncherState state = mLauncher.getStateManager().getState(); - if ((state.getVisibleElements(mLauncher) & ALL_APPS_HEADER_EXTRA) != 0) { - float maxShiftRange = mDeviceProfile.heightPx; - float currShiftRange = mLauncher.getAllAppsController().getShiftRange(); - allAppsProgressOffscreen = 1f + (maxShiftRange - currShiftRange) / maxShiftRange; - } - Animator allAppsSlideOut = ObjectAnimator.ofFloat(mLauncher.getAllAppsController(), - ALL_APPS_PROGRESS, allAppsProgressOffscreen); - allAppsSlideOut.setInterpolator(config.interpolator); - allAppsSlideOut.setDuration(config.duration); - launcherAnimator.play(allAppsSlideOut); - - Workspace workspace = mLauncher.getWorkspace(); - float[] workspaceScaleAndTranslation = NORMAL - .getWorkspaceScaleAndTranslation(mLauncher); - Animator recenterWorkspace = LauncherAnimUtils.ofPropertyValuesHolder( - workspace, new PropertyListBuilder() - .translationX(workspaceScaleAndTranslation[1]) - .translationY(workspaceScaleAndTranslation[2]) - .build()); - recenterWorkspace.setInterpolator(config.interpolator); - recenterWorkspace.setDuration(config.duration); - launcherAnimator.play(recenterWorkspace); - CellLayout currentWorkspacePage = (CellLayout) workspace.getPageAt( - workspace.getCurrentPage()); - - return launcherAnimator; - } - - private RecentsAnimationInterpolator getRecentsInterpolator(TaskView v) { - Rect taskViewBounds = new Rect(); - mDragLayer.getDescendantRectRelativeToSelf(v, taskViewBounds); - - // TODO: Use the actual target insets instead of the current thumbnail insets in case the - // device state has changed - return new RecentsAnimationInterpolator( - new Rect(0, 0, mDeviceProfile.widthPx, mDeviceProfile.heightPx), - v.getThumbnail().getInsets(), - taskViewBounds, - new Rect(0, v.getThumbnail().getTop(), 0, 0), - v.getScaleX(), - v.getTranslationX()); - } - /** * @return Animator that controls the window of the opening targets for the recents launch * animation. */ private ValueAnimator getRecentsWindowAnimator(TaskView v, boolean skipLauncherChanges, - AnimConfig config) { - final RecentsAnimationInterpolator recentsInterpolator = getRecentsInterpolator(v); + RemoteAnimationTargetCompat[] targets) { + final RecentsAnimationInterpolator recentsInterpolator = v.getRecentsInterpolator(); Rect crop = new Rect(); Matrix matrix = new Matrix(); ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1); - appAnimator.setDuration(config.duration); - appAnimator.setInterpolator(config.interpolator); + appAnimator.setDuration(RECENTS_LAUNCH_DURATION); + appAnimator.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR); appAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { boolean isFirstFrame = true; @@ -454,11 +313,9 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag v.setScaleY(tw.taskScale); v.setTranslationX(tw.taskX); v.setTranslationY(tw.taskY); - if (!config.userControlled) { - // Defer fading out the view until after the app window gets faded in - v.setAlpha(getValue(1f, 0f, alphaDuration, alphaDuration, - appAnimator.getDuration() * percent, Interpolators.LINEAR)); - } + // Defer fading out the view until after the app window gets faded in + v.setAlpha(getValue(1f, 0f, alphaDuration, alphaDuration, + appAnimator.getDuration() * percent, Interpolators.LINEAR)); } matrix.setScale(tw.winScale, tw.winScale); @@ -470,7 +327,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag appAnimator.getDuration() * percent, Interpolators.LINEAR); TransactionCompat t = new TransactionCompat(); - for (RemoteAnimationTargetCompat target : config.targets) { + for (RemoteAnimationTargetCompat target : targets) { if (target.mode == RemoteAnimationTargetCompat.MODE_OPENING) { t.setAlpha(target.leash, alpha); @@ -967,24 +824,4 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag newPercent = i.getInterpolation(newPercent); return end * newPercent + start * (1 - newPercent); } - - public static class AnimConfig { - public RemoteAnimationTargetCompat[] targets; - public long duration; - public Interpolator interpolator; - - public boolean userControlled = false; - - public AnimConfig(RemoteAnimationTargetCompat[] targets, long duration, - Interpolator interpolator) { - this.targets = targets; - this.duration = duration; - this.interpolator = interpolator; - } - - public AnimConfig(long duration, Interpolator interpolator) { - this(new RemoteAnimationTargetCompat[0], duration, interpolator); - userControlled = true; - } - } } diff --git a/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java index dca0018ece..369ae3ab6c 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java @@ -20,7 +20,6 @@ import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelo import android.animation.Animator; import android.animation.AnimatorListenerAdapter; -import android.animation.AnimatorSet; import android.animation.ValueAnimator; import android.util.Log; import android.view.MotionEvent; @@ -28,8 +27,6 @@ import android.view.View; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.Launcher; -import com.android.launcher3.LauncherAppTransitionManagerImpl; -import com.android.launcher3.LauncherAppTransitionManagerImpl.AnimConfig; import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.Interpolators; @@ -166,21 +163,20 @@ public class TaskViewTouchController extends AnimatorListenerAdapter if (goingUp) { mPendingAnimation = mRecentsView.createTaskDismissAnimation(mTaskBeingDragged, true /* animateTaskView */, true /* removeTask */, maxDuration); - mCurrentAnimation = AnimatorPlaybackController - .wrap(mPendingAnimation.anim, maxDuration); + mEndDisplacement = -mTaskBeingDragged.getHeight(); } else { - LauncherAppTransitionManagerImpl appTransitionManager = - (LauncherAppTransitionManagerImpl) mLauncher.getAppTransitionManager(); - AnimatorSet anim = appTransitionManager.composeUserControlledRecentsLaunchAnimator( - mTaskBeingDragged, new AnimConfig(maxDuration, Interpolators.ZOOM_IN)); - mCurrentAnimation = AnimatorPlaybackController.wrap(anim, maxDuration); + mPendingAnimation = mRecentsView.createTaskLauncherAnimation( + mTaskBeingDragged, maxDuration); + mPendingAnimation.anim.setInterpolator(Interpolators.ZOOM_IN); mTempCords[1] = mTaskBeingDragged.getHeight(); dl.getDescendantCoordRelativeToSelf(mTaskBeingDragged, mTempCords); mEndDisplacement = dl.getHeight() - mTempCords[1]; } + mCurrentAnimation = AnimatorPlaybackController + .wrap(mPendingAnimation.anim, maxDuration); mCurrentAnimation.getTarget().addListener(this); mCurrentAnimation.dispatchOnStart(); mProgressMultiplier = 1 / mEndDisplacement; @@ -258,7 +254,6 @@ public class TaskViewTouchController extends AnimatorListenerAdapter } if (wasSuccess) { if (!mCurrentAnimationIsGoingUp) { - mTaskBeingDragged.launchTask(false); mLauncher.getUserEventDispatcher().logTaskLaunch(logAction, Direction.DOWN, mTaskBeingDragged.getTask().getTopComponent()); } diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java index ad0e2530c2..d428f23dac 100644 --- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java @@ -15,8 +15,14 @@ */ package com.android.quickstep.views; +import static com.android.launcher3.LauncherAppTransitionManagerImpl.ALL_APPS_PROGRESS_OFF_SCREEN; +import static com.android.launcher3.LauncherState.ALL_APPS_HEADER_EXTRA; import static com.android.launcher3.LauncherState.NORMAL; +import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS; +import android.animation.Animator; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; import android.annotation.TargetApi; import android.content.Context; import android.graphics.Canvas; @@ -30,6 +36,7 @@ import android.view.ViewDebug; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Insettable; import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherState; import com.android.launcher3.R; /** @@ -137,4 +144,23 @@ public class LauncherRecentsView extends RecentsView implements Insett // Lazily update the empty message only when the task stack is reapplied updateEmptyMessage(); } + + /** + * Animates adjacent tasks and translate hotseat off screen as well. + */ + @Override + public AnimatorSet createAdjacentPageAnimForTaskLaunch(TaskView tv) { + AnimatorSet anim = super.createAdjacentPageAnimForTaskLaunch(tv); + + float allAppsProgressOffscreen = ALL_APPS_PROGRESS_OFF_SCREEN; + LauncherState state = mActivity.getStateManager().getState(); + if ((state.getVisibleElements(mActivity) & ALL_APPS_HEADER_EXTRA) != 0) { + float maxShiftRange = mActivity.getDeviceProfile().heightPx; + float currShiftRange = mActivity.getAllAppsController().getShiftRange(); + allAppsProgressOffscreen = 1f + (maxShiftRange - currShiftRange) / maxShiftRange; + } + anim.play(ObjectAnimator.ofFloat( + mActivity.getAllAppsController(), ALL_APPS_PROGRESS, allAppsProgressOffscreen)); + return anim; + } } diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 7a5fd2f0fb..bac8fc7461 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -55,10 +55,13 @@ import com.android.launcher3.PagedView; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatorPlaybackController; +import com.android.launcher3.anim.PropertyListBuilder; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.util.Themes; import com.android.quickstep.PendingAnimation; import com.android.quickstep.QuickScrubController; +import com.android.quickstep.RecentsAnimationInterpolator; +import com.android.quickstep.RecentsAnimationInterpolator.TaskWindowBounds; import com.android.quickstep.RecentsModel; import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan; import com.android.systemui.shared.recents.model.RecentsTaskLoader; @@ -839,4 +842,94 @@ public abstract class RecentsView canvas.restore(); } } + + /** + * Animate adjacent tasks off screen while scaling up. + * + * If launching one of the adjacent tasks, parallax the center task and other adjacent task + * to the right. + */ + public AnimatorSet createAdjacentPageAnimForTaskLaunch(TaskView tv) { + AnimatorSet anim = new AnimatorSet(); + + int taskIndex = indexOfChild(tv); + int centerTaskIndex = getCurrentPage(); + boolean launchingCenterTask = taskIndex == centerTaskIndex; + + TaskWindowBounds endInterpolation = tv.getRecentsInterpolator().interpolate(1); + float toScale = endInterpolation.taskScale; + float toTranslationY = endInterpolation.taskY; + + float displacementX = tv.getWidth() * (toScale - tv.getScaleX()); + if (launchingCenterTask) { + if (taskIndex - 1 >= 0) { + anim.play(createAnimForChild( + taskIndex - 1, toScale, displacementX, toTranslationY)); + } + if (taskIndex + 1 < getPageCount()) { + anim.play(createAnimForChild( + taskIndex + 1, toScale, -displacementX, toTranslationY)); + } + } else { + // We are launching an adjacent task, so parallax the center and other adjacent task. + anim.play(ObjectAnimator.ofFloat(getPageAt(centerTaskIndex), TRANSLATION_X, + mIsRtl ? -displacementX : displacementX)); + + int otherAdjacentTaskIndex = centerTaskIndex + (centerTaskIndex - taskIndex); + if (otherAdjacentTaskIndex >= 0 && otherAdjacentTaskIndex < getPageCount()) { + anim.play(ObjectAnimator.ofPropertyValuesHolder(getPageAt(otherAdjacentTaskIndex), + new PropertyListBuilder() + .translationX(mIsRtl ? -displacementX : displacementX) + .scale(1) + .build())); + } + } + return anim; + } + + private ObjectAnimator createAnimForChild(int childIndex, float toScale, float tx, float ty) { + View child = getChildAt(childIndex); + return ObjectAnimator.ofPropertyValuesHolder(child, + new PropertyListBuilder() + .scale(child.getScaleX() * toScale) + .translationY(ty) + .translationX(mIsRtl ? tx : -tx) + .build()); + } + + public PendingAnimation createTaskLauncherAnimation(TaskView tv, long duration) { + if (FeatureFlags.IS_DOGFOOD_BUILD && mPendingAnimation != null) { + throw new IllegalStateException("Another pending animation is still running"); + } + AnimatorSet anim = createAdjacentPageAnimForTaskLaunch(tv); + + int count = getChildCount(); + if (count == 0) { + return new PendingAnimation(anim); + } + + final RecentsAnimationInterpolator recentsInterpolator = tv.getRecentsInterpolator(); + ValueAnimator targetViewAnim = ValueAnimator.ofFloat(0, 1); + targetViewAnim.addUpdateListener((animation) -> { + float percent = animation.getAnimatedFraction(); + TaskWindowBounds tw = recentsInterpolator.interpolate(percent); + tv.setScaleX(tw.taskScale); + tv.setScaleY(tw.taskScale); + tv.setTranslationX(tw.taskX); + tv.setTranslationY(tw.taskY); + }); + anim.play(targetViewAnim); + anim.setDuration(duration); + + mPendingAnimation = new PendingAnimation(anim); + mPendingAnimation.addEndListener((isSuccess) -> { + if (isSuccess) { + tv.launchTask(false); + } else { + resetTaskVisuals(); + } + mPendingAnimation = null; + }); + return mPendingAnimation; + } } diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java index 9884a4858f..a701862a82 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/src/com/android/quickstep/views/TaskView.java @@ -21,6 +21,7 @@ import android.app.ActivityOptions; import android.content.Context; import android.content.res.Resources; import android.graphics.Outline; +import android.graphics.Rect; import android.os.Handler; import android.util.AttributeSet; import android.view.View; @@ -29,7 +30,9 @@ import android.widget.FrameLayout; import android.widget.ImageView; import com.android.launcher3.BaseDraggingActivity; +import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; +import com.android.quickstep.RecentsAnimationInterpolator; import com.android.quickstep.views.RecentsView.PageCallbacks; import com.android.quickstep.views.RecentsView.ScrollState; import com.android.systemui.shared.recents.model.Task; @@ -183,6 +186,23 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback return false; } + public RecentsAnimationInterpolator getRecentsInterpolator() { + Rect taskViewBounds = new Rect(); + BaseDraggingActivity activity = BaseDraggingActivity.fromContext(getContext()); + DeviceProfile dp = activity.getDeviceProfile(); + activity.getDragLayer().getDescendantRectRelativeToSelf(this, taskViewBounds); + + // TODO: Use the actual target insets instead of the current thumbnail insets in case the + // device state has changed + return new RecentsAnimationInterpolator( + new Rect(0, 0, dp.widthPx, dp.heightPx), + getThumbnail().getInsets(), + taskViewBounds, + new Rect(0, getThumbnail().getTop(), 0, 0), + getScaleX(), + getTranslationX()); + } + private static final class TaskOutlineProvider extends ViewOutlineProvider { private final int mMarginTop; diff --git a/src/com/android/launcher3/anim/AnimatorPlaybackController.java b/src/com/android/launcher3/anim/AnimatorPlaybackController.java index 6fea201564..087752df1e 100644 --- a/src/com/android/launcher3/anim/AnimatorPlaybackController.java +++ b/src/com/android/launcher3/anim/AnimatorPlaybackController.java @@ -18,6 +18,7 @@ package com.android.launcher3.anim; import android.animation.Animator; import android.animation.Animator.AnimatorListener; import android.animation.AnimatorSet; +import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import java.util.ArrayList; @@ -184,10 +185,14 @@ public abstract class AnimatorPlaybackController implements ValueAnimator.Animat private void getAnimationsRecur(AnimatorSet anim, ArrayList out) { long forceDuration = anim.getDuration(); + TimeInterpolator forceInterpolator = anim.getInterpolator(); for (Animator child : anim.getChildAnimations()) { if (forceDuration > 0) { child.setDuration(forceDuration); } + if (forceInterpolator != null) { + child.setInterpolator(forceInterpolator); + } if (child instanceof ValueAnimator) { out.add((ValueAnimator) child); } else if (child instanceof AnimatorSet) {