Merge "Animate launcher when launching recent tasks" into ub-launcher3-master
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index d8504f1..0956048 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -37,4 +37,7 @@
     <!-- Launcher app transition -->
     <dimen name="content_trans_y">25dp</dimen>
     <dimen name="workspace_trans_y">80dp</dimen>
+    <dimen name="recents_adjacent_trans_x">120dp</dimen>
+    <dimen name="recents_adjacent_trans_y">80dp</dimen>
+    <fraction name="recents_adjacent_scale">150%</fraction>
 </resources>
diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
index adea1f2..8f498d2 100644
--- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
@@ -16,6 +16,7 @@
 
 package com.android.launcher3;
 
+import static com.android.launcher3.LauncherAnimUtils.DRAWABLE_ALPHA;
 import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
 import static com.android.systemui.shared.recents.utilities.Utilities.getNextFrameNumber;
 import static com.android.systemui.shared.recents.utilities.Utilities.getSurface;
@@ -28,13 +29,13 @@
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.annotation.TargetApi;
+import android.app.ActivityOptions;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.os.Build;
-import android.os.Bundle;
 import android.os.Handler;
 import android.util.Log;
 import android.view.Surface;
@@ -46,6 +47,7 @@
 import com.android.launcher3.InsettableFrameLayout.LayoutParams;
 import com.android.launcher3.allapps.AllAppsTransitionController;
 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.quickstep.RecentsAnimationInterpolator;
@@ -80,8 +82,8 @@
     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_START = 1.3059858f;
-    private static final float ALL_APPS_PROGRESS_SLIDE_END = 0.99581414f;
+    private static final float ALL_APPS_PROGRESS_OFF_SCREEN = 1.3059858f;
+    private static final float ALL_APPS_PROGRESS_OVERSHOOT = 0.99581414f;
 
     private final DragLayer mDragLayer;
     private final Launcher mLauncher;
@@ -89,6 +91,9 @@
 
     private final float mContentTransY;
     private final float mWorkspaceTransY;
+    private final float mRecentsTransX;
+    private final float mRecentsTransY;
+    private final float mRecentsScale;
 
     private View mFloatingView;
     private boolean mIsRtl;
@@ -105,6 +110,9 @@
         Resources res = mLauncher.getResources();
         mContentTransY = res.getDimensionPixelSize(R.dimen.content_trans_y);
         mWorkspaceTransY = res.getDimensionPixelSize(R.dimen.workspace_trans_y);
+        mRecentsTransX = res.getDimensionPixelSize(R.dimen.recents_adjacent_trans_x);
+        mRecentsTransY = res.getDimensionPixelSize(R.dimen.recents_adjacent_trans_y);
+        mRecentsScale = res.getFraction(R.fraction.recents_adjacent_scale, 1, 1);
 
         mLauncher.addOnDeviceProfileChangeListener(this);
         registerRemoteAnimations();
@@ -116,7 +124,7 @@
     }
 
     private void setCurrentAnimator(LauncherTransitionAnimator animator) {
-        if (mCurrentAnimator != null && mCurrentAnimator.isRunning()) {
+        if (isAnimating()) {
             mCurrentAnimator.cancel();
         }
         mCurrentAnimator = animator;
@@ -124,18 +132,23 @@
 
     @Override
     public void finishLauncherAnimation() {
-        if (mCurrentAnimator != null && mCurrentAnimator.isRunning()) {
+        if (isAnimating()) {
             mCurrentAnimator.finishLauncherAnimation();
         }
         mCurrentAnimator = null;
     }
 
+    @Override
+    public boolean isAnimating() {
+        return mCurrentAnimator != null && mCurrentAnimator.isRunning();
+    }
+
     /**
-     * @return A Bundle with remote animations that controls how the window of the opening
+     * @return ActivityOptions with remote animations that controls how the window of the opening
      *         targets are displayed.
      */
     @Override
-    public Bundle getActivityLaunchOptions(Launcher launcher, View v) {
+    public ActivityOptions getActivityLaunchOptions(Launcher launcher, View v) {
         if (hasControlRemoteAppTransitionPermission()) {
             try {
                 RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mLauncher) {
@@ -188,7 +201,7 @@
                 };
 
                 return ActivityOptionsCompat.makeRemoteAnimation(
-                        new RemoteAnimationAdapterCompat(runner, 500, 380)).toBundle();
+                        new RemoteAnimationAdapterCompat(runner, 500, 380));
             } catch (NoClassDefFoundError e) {
                 // Gracefully fall back to default launch options if the user's platform doesn't
                 // have the latest changes.
@@ -230,7 +243,93 @@
         }
 
         // Found a visible recents task that matches the opening app, lets launch the app from there
-        return new LauncherTransitionAnimator(null, getRecentsWindowAnimator(taskView, targets));
+        return new LauncherTransitionAnimator(getRecentsLauncherAnimator(recentsView, taskView),
+                getRecentsWindowAnimator(taskView, targets));
+    }
+
+    /**
+     * 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) {
+        AnimatorSet launcherAnimator = new AnimatorSet();
+
+        int launchedTaskIndex = recentsView.indexOfChild(v);
+        int centerTaskIndex = recentsView.getCurrentPage();
+        boolean launchingCenterTask = launchedTaskIndex == centerTaskIndex;
+        if (launchingCenterTask) {
+            if (launchedTaskIndex - 1 >= recentsView.getFirstTaskIndex()) {
+                TaskView adjacentPage1 = (TaskView) recentsView.getPageAt(launchedTaskIndex - 1);
+                ObjectAnimator adjacentTask1ScaleAndTranslate =
+                        LauncherAnimUtils.ofPropertyValuesHolder(adjacentPage1,
+                                new PropertyListBuilder()
+                                        .scale(adjacentPage1.getScaleX() * mRecentsScale)
+                                        .translationY(mRecentsTransY)
+                                        .translationX(mIsRtl ? mRecentsTransX : -mRecentsTransX)
+                                        .build());
+                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() * mRecentsScale)
+                                        .translationY(mRecentsTransY)
+                                        .translationX(mIsRtl ? -mRecentsTransX : mRecentsTransX)
+                                        .build());
+                launcherAnimator.play(adjacentTask2ScaleAndTranslate);
+            }
+        } else if (centerTaskIndex >= recentsView.getFirstTaskIndex()) {
+            // We are launching an adjacent task, so parallax the center and other adjacent task.
+            TaskView centerTask = (TaskView) recentsView.getPageAt(centerTaskIndex);
+            float translationX = Math.abs(v.getTranslationX());
+            ObjectAnimator centerTaskParallaxToRight =
+                    LauncherAnimUtils.ofPropertyValuesHolder(centerTask,
+                            new PropertyListBuilder()
+                                    .scale(v.getScaleX())
+                                    .translationX(mIsRtl ? -translationX : translationX)
+                                    .build());
+            launcherAnimator.play(centerTaskParallaxToRight);
+            int otherAdjacentTaskIndex = centerTaskIndex + (centerTaskIndex - launchedTaskIndex);
+            if (otherAdjacentTaskIndex >= recentsView.getFirstTaskIndex()
+                    && otherAdjacentTaskIndex < recentsView.getPageCount()) {
+                TaskView otherAdjacentTask = (TaskView) recentsView.getPageAt(
+                        otherAdjacentTaskIndex);
+                ObjectAnimator otherAdjacentTaskParallaxToRight =
+                        LauncherAnimUtils.ofPropertyValuesHolder(otherAdjacentTask,
+                                new PropertyListBuilder()
+                                        .translationX(otherAdjacentTask.getTranslationX()
+                                                + (mIsRtl ? -translationX : translationX))
+                                        .build());
+                launcherAnimator.play(otherAdjacentTaskParallaxToRight);
+            }
+        }
+
+        Animator allAppsSlideOut = ObjectAnimator.ofFloat(mLauncher.getAllAppsController(),
+                ALL_APPS_PROGRESS, ALL_APPS_PROGRESS_OFF_SCREEN);
+        launcherAnimator.play(allAppsSlideOut);
+
+        Workspace workspace = mLauncher.getWorkspace();
+        float[] workspaceScaleAndTranslation = LauncherState.NORMAL
+                .getWorkspaceScaleAndTranslation(mLauncher);
+        Animator recenterWorkspace = LauncherAnimUtils.ofPropertyValuesHolder(
+                workspace, new PropertyListBuilder()
+                        .translationX(workspaceScaleAndTranslation[1])
+                        .translationY(workspaceScaleAndTranslation[2])
+                        .build());
+        launcherAnimator.play(recenterWorkspace);
+        CellLayout currentWorkspacePage = (CellLayout) workspace.getPageAt(
+                workspace.getCurrentPage());
+        Animator hideWorkspaceScrim = ObjectAnimator.ofInt(
+                currentWorkspacePage.getScrimBackground(), DRAWABLE_ALPHA, 0);
+        launcherAnimator.play(hideWorkspaceScrim);
+
+        launcherAnimator.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR);
+        launcherAnimator.setDuration(RECENTS_LAUNCH_DURATION);
+        return launcherAnimator;
     }
 
     /**
@@ -247,7 +346,10 @@
         RecentsAnimationInterpolator recentsInterpolator = new RecentsAnimationInterpolator(
                 new Rect(0, 0, mDeviceProfile.widthPx, mDeviceProfile.heightPx),
                 v.getThumbnail().getInsets(),
-                taskViewBounds, new Rect(0, v.getThumbnail().getTop(), 0, 0));
+                taskViewBounds,
+                new Rect(0, v.getThumbnail().getTop(), 0, 0),
+                v.getScaleX(),
+                v.getTranslationX());
 
         Rect crop = new Rect();
         Matrix matrix = new Matrix();
@@ -310,6 +412,13 @@
                 isFirstFrame = false;
             }
         });
+        appAnimator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                // Make sure recents gets fixed up by resetting task alphas and scales, etc.
+                mLauncher.getStateManager().reapplyState();
+            }
+        });
         return appAnimator;
     }
 
@@ -708,9 +817,9 @@
             // Animate the shelf in two parts: slide in, and overeshoot.
             AllAppsTransitionController allAppsController = mLauncher.getAllAppsController();
             // The shelf will start offscreen
-            final float startY = ALL_APPS_PROGRESS_START;
+            final float startY = ALL_APPS_PROGRESS_OFF_SCREEN;
             // And will end slightly pulled up, so that there is something to overshoot back to 1f.
-            final float slideEnd = ALL_APPS_PROGRESS_SLIDE_END;
+            final float slideEnd = ALL_APPS_PROGRESS_OVERSHOOT;
 
             allAppsController.setProgress(startY);
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index 57e588b..7d371e9 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -34,6 +34,7 @@
 import com.android.launcher3.anim.Interpolators;
 import com.android.quickstep.AnimatedFloat;
 import com.android.quickstep.RecentsView;
+import com.android.quickstep.TaskView;
 
 public class RecentsViewStateController implements StateHandler {
 
@@ -62,6 +63,12 @@
         mWorkspaceCard.setWorkspaceScrollingEnabled(state == OVERVIEW);
         setVisibility(state == OVERVIEW);
         setTransitionProgress(state == OVERVIEW ? 1 : 0);
+        if (state == OVERVIEW) {
+            for (int i = mRecentsView.getFirstTaskIndex(); i < mRecentsView.getPageCount(); i++) {
+                ((TaskView) mRecentsView.getPageAt(i)).resetVisualProperties();
+            }
+            mRecentsView.updateCurveProperties();
+        }
     }
 
     @Override
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationInterpolator.java b/quickstep/src/com/android/quickstep/RecentsAnimationInterpolator.java
index 9cc038f..1f9c728 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationInterpolator.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationInterpolator.java
@@ -53,12 +53,15 @@
     private Rect mTaskInsets;
     private Rect mThumbnail;
 
-    private float mTaskScale;
+    private float mInitialTaskScale;
+    private float mInitialTaskTranslationX;
+    private float mFinalTaskScale;
     private Rect mScaledTask;
     private Rect mTargetTask;
     private Rect mSrcWindow;
 
-    public RecentsAnimationInterpolator(Rect window, Rect insets, Rect task, Rect taskInsets) {
+    public RecentsAnimationInterpolator(Rect window, Rect insets, Rect task, Rect taskInsets,
+            float taskScale, float taskTranslationX) {
         mWindow = window;
         mInsets = insets;
         mTask = task;
@@ -68,16 +71,18 @@
 
         mThumbnail = new Rect(task);
         Utilities.insetRect(mThumbnail, taskInsets);
-        mTaskScale = (float) mInsetWindow.width() / mThumbnail.width();
+        mInitialTaskScale = taskScale;
+        mInitialTaskTranslationX = taskTranslationX;
+        mFinalTaskScale = (float) mInsetWindow.width() / mThumbnail.width();
         mScaledTask = new Rect(task);
-        Utilities.scaleRectAboutCenter(mScaledTask, mTaskScale);
+        Utilities.scaleRectAboutCenter(mScaledTask, mFinalTaskScale);
         Rect finalScaledTaskInsets = new Rect(taskInsets);
-        Utilities.scaleRect(finalScaledTaskInsets, mTaskScale);
+        Utilities.scaleRect(finalScaledTaskInsets, mFinalTaskScale);
         mTargetTask = new Rect(mInsetWindow);
         mTargetTask.offsetTo(window.top + insets.top - finalScaledTaskInsets.top,
                 window.left + insets.left - finalScaledTaskInsets.left);
 
-        float initialWinScale = 1f / mTaskScale;
+        float initialWinScale = 1f / mFinalTaskScale;
         Rect scaledWindow = new Rect(mInsetWindow);
         Utilities.scaleRectAboutCenter(scaledWindow, initialWinScale);
         Rect scaledInsets = new Rect(insets);
@@ -89,13 +94,14 @@
 
     public TaskWindowBounds interpolate(float t) {
         mTmpTaskWindowBounds.taskScale = Utilities.mapRange(t,
-                1, (float) mInsetWindow.width() / mThumbnail.width());
+                mInitialTaskScale, mFinalTaskScale);
         mTmpTaskWindowBounds.taskX = Utilities.mapRange(t,
-                0, mTargetTask.left - mScaledTask.left);
+                mInitialTaskTranslationX, mTargetTask.left - mScaledTask.left);
         mTmpTaskWindowBounds.taskY = Utilities.mapRange(t,
                 0, mTargetTask.top - mScaledTask.top);
 
-        mTmpTaskWindowBounds.winScale = mTmpTaskWindowBounds.taskScale / mTaskScale;
+        float taskScale = Utilities.mapRange(t, 1, mFinalTaskScale);
+        mTmpTaskWindowBounds.winScale = taskScale / mFinalTaskScale;
         mTmpTaskWindowBounds.winX = Utilities.mapRange(t,
                 mSrcWindow.left, 0);
         mTmpTaskWindowBounds.winY = Utilities.mapRange(t,
diff --git a/quickstep/src/com/android/quickstep/RecentsView.java b/quickstep/src/com/android/quickstep/RecentsView.java
index c8122d2..ec0716c 100644
--- a/quickstep/src/com/android/quickstep/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/RecentsView.java
@@ -17,6 +17,7 @@
 package com.android.quickstep;
 
 import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherState.OVERVIEW;
 import static com.android.quickstep.TaskView.CURVE_FACTOR;
 import static com.android.quickstep.TaskView.CURVE_INTERPOLATOR;
 
@@ -221,8 +222,8 @@
     }
 
     public boolean isTaskViewVisible(TaskView tv) {
-        // For now, just check if it's the active task
-        return indexOfChild(tv) == getNextPage();
+        // For now, just check if it's the active task or an adjacent task
+        return Math.abs(indexOfChild(tv) - getNextPage()) <= 1;
     }
 
     public TaskView getTaskView(int taskId) {
@@ -294,13 +295,10 @@
             final Task task = tasks.get(i);
             final TaskView taskView = (TaskView) getChildAt(tasks.size() - i - 1 + mFirstTaskIndex);
             taskView.bind(task);
-            taskView.setScaleX(1f);
-            taskView.setScaleY(1f);
-            taskView.setTranslationX(0f);
-            taskView.setTranslationY(0f);
-            taskView.setAlpha(1f);
+            taskView.resetVisualProperties();
             loader.loadTaskData(task);
         }
+        updateCurveProperties();
         applyIconScale(false /* animate */);
 
         if (oldChildCount != getChildCount()) {
@@ -402,7 +400,7 @@
     /**
      * Scales and adjusts translation of adjacent pages as if on a curved carousel.
      */
-    private void updateCurveProperties() {
+    public void updateCurveProperties() {
         if (getPageCount() == 0 || getPageAt(0).getMeasuredWidth() == 0) {
             return;
         }
diff --git a/quickstep/src/com/android/quickstep/TaskView.java b/quickstep/src/com/android/quickstep/TaskView.java
index f21742a..b407f75 100644
--- a/quickstep/src/com/android/quickstep/TaskView.java
+++ b/quickstep/src/com/android/quickstep/TaskView.java
@@ -24,7 +24,6 @@
 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;
@@ -32,19 +31,15 @@
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 
+import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.quickstep.RecentsView.PageCallbacks;
 import com.android.quickstep.RecentsView.ScrollState;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.Task.TaskCallbacks;
 import com.android.systemui.shared.recents.model.ThumbnailData;
-import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat;
-import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
-import com.android.systemui.shared.recents.view.RecentsTransition;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 
-import java.util.ArrayList;
-import java.util.List;
 import java.util.function.Consumer;
 
 /**
@@ -120,26 +115,7 @@
         if (mTask != null) {
             final ActivityOptions opts;
             if (animate) {
-                // Calculate the bounds of the thumbnail to animate from
-                final Rect bounds = new Rect();
-                final int[] pos = new int[2];
-                mSnapshotView.getLocationInWindow(pos);
-                bounds.set(pos[0], pos[1],
-                        pos[0] + mSnapshotView.getWidth(),
-                        pos[1] + mSnapshotView.getHeight());
-                AppTransitionAnimationSpecsFuture animFuture =
-                        new AppTransitionAnimationSpecsFuture(getHandler()) {
-                            @Override
-                            public List<AppTransitionAnimationSpecCompat> composeSpecs() {
-                                ArrayList<AppTransitionAnimationSpecCompat> specs =
-                                        new ArrayList<>();
-                                specs.add(new AppTransitionAnimationSpecCompat(mTask.key.id, null,
-                                        bounds));
-                                return specs;
-                            }
-                        };
-                opts = RecentsTransition.createAspectScaleAnimation(
-                        getContext(), getHandler(), true /* scaleUp */, animFuture, null);
+                opts = Launcher.getLauncher(getContext()).getActivityLaunchOptions(this, false);
             } else {
                 opts = ActivityOptions.makeCustomAnimation(getContext(), 0, 0);
             }
@@ -178,6 +154,14 @@
         mIconView.setScaleY(iconScale);
     }
 
+    public void resetVisualProperties() {
+        setScaleX(1f);
+        setScaleY(1f);
+        setTranslationX(0f);
+        setTranslationY(0f);
+        setAlpha(1f);
+    }
+
     @Override
     public int onPageScroll(ScrollState scrollState) {
         float curveInterpolation =
@@ -209,7 +193,6 @@
         return SCROLL_TYPE_TASK;
     }
 
-
     private static final class TaskOutlineProvider extends ViewOutlineProvider {
 
         private final int mMarginTop;
diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
index 134feec..19942c3 100644
--- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -46,9 +46,7 @@
 import android.support.annotation.WorkerThread;
 import android.util.Log;
 import android.view.View;
-import android.view.ViewTreeObserver;
 import android.view.ViewTreeObserver.OnDrawListener;
-import android.view.ViewTreeObserver.OnPreDrawListener;
 
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.DeviceProfile;
@@ -62,11 +60,9 @@
 import com.android.launcher3.anim.AnimationSuccessListener;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.Interpolators;
-
 import com.android.launcher3.logging.UserEventDispatcher;
-import com.android.launcher3.userevent.nano.LauncherLogProto;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
 import com.android.launcher3.util.TraceHelper;
 import com.android.launcher3.util.ViewOnDrawExecutor;
@@ -359,7 +355,7 @@
         AbstractFloatingView.closeAllOpenViews(mLauncher, mWasLauncherAlreadyVisible);
 
 
-        if (mWasLauncherAlreadyVisible) {
+        if (mWasLauncherAlreadyVisible && !mLauncher.getAppTransitionManager().isAnimating()) {
             DeviceProfile dp = mLauncher.getDeviceProfile();
             long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx);
             mLauncherTransitionController = mLauncher.getStateManager()
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 1d474da..55bfef6 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -39,6 +39,7 @@
 import android.animation.ValueAnimator;
 import android.annotation.SuppressLint;
 import android.annotation.TargetApi;
+import android.app.ActivityOptions;
 import android.app.AlertDialog;
 import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetManager;
@@ -1924,7 +1925,7 @@
             intent.setSourceBounds(getViewBounds(v));
             // If there is no target package, use the default intent chooser animation
             launchOptions = hasTargetPackage
-                    ? getActivityLaunchOptions(v, isInMultiWindowModeCompat())
+                    ? getActivityLaunchOptionsAsBundle(v, isInMultiWindowModeCompat())
                     : null;
         } else {
             launchOptions = null;
@@ -1979,8 +1980,13 @@
         }
     }
 
+    public Bundle getActivityLaunchOptionsAsBundle(View v, boolean useDefaultLaunchOptions) {
+        ActivityOptions activityOptions = getActivityLaunchOptions(v, useDefaultLaunchOptions);
+        return activityOptions == null ? null : activityOptions.toBundle();
+    }
+
     @TargetApi(Build.VERSION_CODES.M)
-    public Bundle getActivityLaunchOptions(View v, boolean useDefaultLaunchOptions) {
+    public ActivityOptions getActivityLaunchOptions(View v, boolean useDefaultLaunchOptions) {
         return useDefaultLaunchOptions
                 ? mAppTransitionManager.getDefaultActivityLaunchOptions(this, v)
                 : mAppTransitionManager.getActivityLaunchOptions(this, v);
@@ -2004,7 +2010,7 @@
         boolean useLaunchAnimation = (v != null) &&
                 !intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
         Bundle optsBundle = useLaunchAnimation
-                ? getActivityLaunchOptions(v, isInMultiWindowModeCompat())
+                ? getActivityLaunchOptionsAsBundle(v, isInMultiWindowModeCompat())
                 : null;
 
         UserHandle user = item == null ? null : item.user;
diff --git a/src/com/android/launcher3/LauncherAppTransitionManager.java b/src/com/android/launcher3/LauncherAppTransitionManager.java
index 43d5e62..19fa3d4 100644
--- a/src/com/android/launcher3/LauncherAppTransitionManager.java
+++ b/src/com/android/launcher3/LauncherAppTransitionManager.java
@@ -21,7 +21,6 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
-import android.os.Bundle;
 import android.view.View;
 
 /**
@@ -34,7 +33,7 @@
                 context, R.string.app_transition_manager_class);
     }
 
-    public Bundle getDefaultActivityLaunchOptions(Launcher launcher, View v) {
+    public ActivityOptions getDefaultActivityLaunchOptions(Launcher launcher, View v) {
         if (Utilities.ATLEAST_MARSHMALLOW) {
             int left = 0, top = 0;
             int width = v.getMeasuredWidth(), height = v.getMeasuredHeight();
@@ -49,23 +48,27 @@
                     height = bounds.height();
                 }
             }
-            return ActivityOptions.makeClipRevealAnimation(v, left, top, width, height)
-                    .toBundle();
+            return ActivityOptions.makeClipRevealAnimation(v, left, top, width, height);
         } else if (Utilities.ATLEAST_LOLLIPOP_MR1) {
             // On L devices, we use the device default slide-up transition.
             // On L MR1 devices, we use a custom version of the slide-up transition which
             // doesn't have the delay present in the device default.
             return ActivityOptions.makeCustomAnimation(launcher, R.anim.task_open_enter,
-                    R.anim.no_anim).toBundle();
+                    R.anim.no_anim);
         }
         return null;
     }
 
-    public Bundle getActivityLaunchOptions(Launcher launcher, View v) {
+    public ActivityOptions getActivityLaunchOptions(Launcher launcher, View v) {
         return getDefaultActivityLaunchOptions(launcher, v);
     }
 
     /** Cancels the current Launcher transition animation */
     public void finishLauncherAnimation() {
     }
+
+    public boolean isAnimating() {
+        // We don't know when the activity options are being used.
+        return false;
+    }
 }
diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java
index d2bcd18..32fd063 100644
--- a/src/com/android/launcher3/popup/SystemShortcut.java
+++ b/src/com/android/launcher3/popup/SystemShortcut.java
@@ -82,7 +82,7 @@
                 @Override
                 public void onClick(View view) {
                     Rect sourceBounds = launcher.getViewBounds(view);
-                    Bundle opts = launcher.getActivityLaunchOptions(view, false);
+                    Bundle opts = launcher.getActivityLaunchOptionsAsBundle(view, false);
                     InfoDropTarget.startDetailsActivityForInfo(itemInfo, launcher, sourceBounds, opts);
                     launcher.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
                             ControlType.APPINFO_TARGET, view);
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewPanel.java b/src_ui_overrides/com/android/launcher3/uioverrides/OverviewPanel.java
index 2d39505..4168e11 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewPanel.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/OverviewPanel.java
@@ -159,7 +159,7 @@
                 .setPackage(getContext().getPackageName());
         intent.setSourceBounds(mLauncher.getViewBounds(v));
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        getContext().startActivity(intent, mLauncher.getActivityLaunchOptions(v, false));
+        getContext().startActivity(intent, mLauncher.getActivityLaunchOptionsAsBundle(v, false));
     }
 
     @Override