Merge "Fix wrong labeling of app launch session type (HOME vs OVERVIEW)" into ub-launcher3-edmonton-polish
diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
index 52a6dd5..202d8fc 100644
--- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java
+++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
@@ -243,9 +243,8 @@
             if (wasVisible) {
                 DeviceProfile dp = activity.getDeviceProfile();
                 long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx);
-                activity.getStateManager().goToState(startState, false);
                 callback.accept(activity.getStateManager()
-                        .createAnimationToNewWorkspace(endState, accuracy));
+                        .createAnimationToNewWorkspace(startState, endState, accuracy));
                 return;
             }
 
diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
index c94174b..cb13625 100644
--- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -589,7 +589,15 @@
                     new Point(minimizedHomeBounds.width(), minimizedHomeBounds.height()));
             dp.updateInsets(homeContentInsets);
         } else {
-            overviewStackBounds = new Rect(0, 0, dp.widthPx, dp.heightPx);
+            if (mActivity != null) {
+                int loc[] = new int[2];
+                View rootView = mActivity.getRootView();
+                rootView.getLocationOnScreen(loc);
+                overviewStackBounds = new Rect(loc[0], loc[1], loc[0] + rootView.getWidth(),
+                        loc[1] + rootView.getHeight());
+            } else {
+                overviewStackBounds = new Rect(0, 0, dp.widthPx, dp.heightPx);
+            }
             // If we are not in multi-window mode, home insets should be same as system insets.
             Rect insets = new Rect();
             WindowManagerWrapper.getInstance().getStableInsets(insets);
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java
index 05c515b..0df9d97 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/LauncherStateManager.java
@@ -298,6 +298,24 @@
 
     /**
      * Creates a {@link AnimatorPlaybackController} that can be used for a controlled
+     * state transition. The UI is force-set to fromState before creating the controller.
+     * @param fromState the initial state for the transition.
+     * @param state the final state for the transition.
+     * @param duration intended duration for normal playback. Use higher duration for better
+     *                accuracy.
+     */
+    public AnimatorPlaybackController createAnimationToNewWorkspace(
+            LauncherState fromState, LauncherState state, long duration) {
+        mConfig.reset();
+        for (StateHandler handler : getStateHandlers()) {
+            handler.setState(fromState);
+        }
+
+        return createAnimationToNewWorkspace(state, duration);
+    }
+
+    /**
+     * Creates a {@link AnimatorPlaybackController} that can be used for a controlled
      * state transition.
      * @param state the final state for the transition.
      * @param duration intended duration for normal playback. Use higher duration for better
@@ -538,6 +556,9 @@
 
         @Override
         public void onAnimationEnd(Animator animation) {
+            if (playbackController != null && playbackController.getTarget() == animation) {
+                playbackController = null;
+            }
             if (mCurrentAnimation == animation) {
                 mCurrentAnimation = null;
             }
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index 453810c..898b1b7 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -86,6 +86,9 @@
     private FlingBlockCheck mFlingBlockCheck = new FlingBlockCheck();
 
     private AnimatorSet mAtomicAnim;
+    // True if we want to resume playing atomic components when mAtomicAnim completes.
+    private boolean mScheduleResumeAtomicComponent;
+
     private boolean mPassedOverviewAtomicThreshold;
     // mAtomicAnim plays the atomic components of the state animations when we pass the threshold.
     // However, if we reinit to transition to a new state (e.g. OVERVIEW -> ALL_APPS) before the
@@ -93,6 +96,8 @@
     // interfere with the atomic animation. When the atomic animation ends, we start controlling
     // the atomic components as well, using this controller.
     private AnimatorPlaybackController mAtomicComponentsController;
+    private LauncherState mAtomicComponentsTargetState = NORMAL;
+
     private float mAtomicComponentsStartProgress;
 
     public AbstractStateChangeTouchController(Launcher l, SwipeDetector.Direction dir) {
@@ -191,27 +196,21 @@
         }
         int animComponents = goingBetweenNormalAndOverview(mFromState, mToState)
                 ? NON_ATOMIC_COMPONENT : ANIM_ALL;
+        mScheduleResumeAtomicComponent = false;
         if (mAtomicAnim != null) {
+            animComponents = NON_ATOMIC_COMPONENT;
             // Control the non-atomic components until the atomic animation finishes, then control
             // the atomic components as well.
-            animComponents = NON_ATOMIC_COMPONENT;
-            mAtomicAnim.addListener(new AnimationSuccessListener() {
-                @Override
-                public void onAnimationSuccess(Animator animation) {
-                    cancelAtomicComponentsController();
-                    if (mCurrentAnimation != null) {
-                        mAtomicComponentsStartProgress = mCurrentAnimation.getProgressFraction();
-                        long duration = (long) (getShiftRange() * 2);
-                        mAtomicComponentsController = AnimatorPlaybackController.wrap(
-                                createAtomicAnimForState(mFromState, mToState, duration), duration);
-                        mAtomicComponentsController.dispatchOnStart();
-                    }
-                }
-            });
+            mScheduleResumeAtomicComponent = true;
         }
-        if (goingBetweenNormalAndOverview(mFromState, mToState)) {
+        if (goingBetweenNormalAndOverview(mFromState, mToState)
+                || mAtomicComponentsTargetState != mToState) {
             cancelAtomicComponentsController();
         }
+
+        if (mAtomicComponentsController != null) {
+            animComponents &= ~ATOMIC_COMPONENT;
+        }
         mProgressMultiplier = initCurrentAnimation(animComponents);
         mCurrentAnimation.dispatchOnStart();
         return true;
@@ -302,10 +301,28 @@
                 mAtomicAnim.cancel();
             }
             mAtomicAnim = createAtomicAnimForState(atomicFromState, atomicToState, ATOMIC_DURATION);
-            mAtomicAnim.addListener(new AnimatorListenerAdapter() {
+            mAtomicAnim.addListener(new AnimationSuccessListener() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
+                    super.onAnimationEnd(animation);
                     mAtomicAnim = null;
+                    mScheduleResumeAtomicComponent = false;
+                }
+
+                @Override
+                public void onAnimationSuccess(Animator animator) {
+                    if (!mScheduleResumeAtomicComponent) {
+                        return;
+                    }
+                    cancelAtomicComponentsController();
+                    if (mCurrentAnimation != null) {
+                        mAtomicComponentsStartProgress = mCurrentAnimation.getProgressFraction();
+                        long duration = (long) (getShiftRange() * 2);
+                        mAtomicComponentsController = AnimatorPlaybackController.wrap(
+                                createAtomicAnimForState(mFromState, mToState, duration), duration);
+                        mAtomicComponentsController.dispatchOnStart();
+                        mAtomicComponentsTargetState = mToState;
+                    }
                 }
             });
             mAtomicAnim.start();
@@ -457,7 +474,7 @@
     }
 
     protected void onSwipeInteractionCompleted(LauncherState targetState, int logAction) {
-        clearState();
+        cancelAnimationControllers();
         boolean shouldGoToTargetState = true;
         if (mPendingAnimation != null) {
             boolean reachedTarget = mToState == targetState;
@@ -484,6 +501,15 @@
     }
 
     protected void clearState() {
+        cancelAnimationControllers();
+        if (mAtomicAnim != null) {
+            mAtomicAnim.cancel();
+            mAtomicAnim = null;
+        }
+        mScheduleResumeAtomicComponent = false;
+    }
+
+    private void cancelAnimationControllers() {
         mCurrentAnimation = null;
         cancelAtomicComponentsController();
         mDetector.finishedScrolling();