Merge "Removing some properties out of AnimationBuilder" into ub-launcher3-master
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
index 9f19bb3..f390d0f 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
@@ -79,6 +79,7 @@
     private static final String TAG = "BaseSwipeUpHandler";
     protected static final Rect TEMP_RECT = new Rect();
 
+    public static final float MIN_PROGRESS_FOR_OVERVIEW = 0.7f;
     private static final Interpolator PULLBACK_INTERPOLATOR = DEACCEL;
 
     // The distance needed to drag to reach the task size in recents.
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java
index ce67457..ea5561b 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java
@@ -21,7 +21,6 @@
 import static com.android.quickstep.GestureState.GestureEndTarget.LAST_TASK;
 import static com.android.quickstep.GestureState.GestureEndTarget.NEW_TASK;
 import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
-import static com.android.quickstep.LauncherSwipeHandler.MIN_PROGRESS_FOR_OVERVIEW;
 import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
 import static com.android.quickstep.RecentsActivity.EXTRA_TASK_ID;
 import static com.android.quickstep.RecentsActivity.EXTRA_THUMBNAIL;
@@ -97,7 +96,7 @@
 
     private final AnimatedFloat mLauncherAlpha = new AnimatedFloat(this::onLauncherAlphaChanged);
 
-    private boolean mIsMotionPaused = false;
+    private boolean mOverviewThresholdPassed = false;
 
     private final boolean mInQuickSwitchMode;
     private final boolean mContinuingLastGesture;
@@ -222,10 +221,16 @@
 
     @Override
     public void onMotionPauseChanged(boolean isPaused) {
-        if (!mInQuickSwitchMode) {
-            mIsMotionPaused = isPaused;
+        if (!mInQuickSwitchMode && mDeviceState.isFullyGesturalNavMode()) {
+            updateOverviewThresholdPassed(isPaused);
+        }
+    }
+
+    private void updateOverviewThresholdPassed(boolean passed) {
+        if (passed != mOverviewThresholdPassed) {
+            mOverviewThresholdPassed = passed;
             if (mSwipeUpOverHome) {
-                mLauncherAlpha.animateToValue(mLauncherAlpha.value, isPaused ? 0 : 1)
+                mLauncherAlpha.animateToValue(mLauncherAlpha.value, passed ? 0 : 1)
                         .setDuration(150).start();
             }
             performHapticFeedback();
@@ -234,7 +239,7 @@
 
     @Override
     public Intent getLaunchIntent() {
-        if (mInQuickSwitchMode || mSwipeUpOverHome) {
+        if (mInQuickSwitchMode || mSwipeUpOverHome || !mDeviceState.isFullyGesturalNavMode()) {
             return mGestureState.getOverviewIntent();
         } else {
             return mGestureState.getHomeIntent();
@@ -248,6 +253,11 @@
             mRecentsAnimationController.setWindowThresholdCrossed(!mInQuickSwitchMode
                     && (mCurrentShift.value > 1 - UPDATE_SYSUI_FLAGS_THRESHOLD));
         }
+
+        if (!mInQuickSwitchMode && !mDeviceState.isFullyGesturalNavMode()) {
+            updateOverviewThresholdPassed(mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW);
+        }
+
         if (mRecentsAnimationTargets != null) {
             applyTransformUnchecked();
         }
@@ -271,14 +281,25 @@
                     .getDimension(R.dimen.quickstep_fling_threshold_velocity);
             boolean isFling = Math.abs(endVelocity) > flingThreshold;
 
-            if (isFling) {
-                mGestureState.setEndTarget(endVelocity < 0 ? HOME : LAST_TASK);
-            } else if (mIsMotionPaused) {
-                mGestureState.setEndTarget(RECENTS);
+            if (mDeviceState.isFullyGesturalNavMode()) {
+                if (isFling) {
+                    mGestureState.setEndTarget(endVelocity < 0 ? HOME : LAST_TASK);
+                } else if (mOverviewThresholdPassed) {
+                    mGestureState.setEndTarget(RECENTS);
+                } else {
+                    mGestureState.setEndTarget(mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW
+                            ? HOME
+                            : LAST_TASK);
+                }
             } else {
-                mGestureState.setEndTarget(mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW
-                        ? HOME
-                        : LAST_TASK);
+                GestureEndTarget startState = mSwipeUpOverHome ? HOME : LAST_TASK;
+                if (isFling) {
+                    mGestureState.setEndTarget(endVelocity < 0 ? RECENTS : startState);
+                } else {
+                    mGestureState.setEndTarget(mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW
+                            ? RECENTS
+                            : startState);
+                }
             }
         }
         mStateCallback.setStateOnUiThread(STATE_GESTURE_COMPLETED);
@@ -353,7 +374,7 @@
                 mRecentsAnimationController.finish(false, null, false);
                 break;
             case RECENTS: {
-                if (mSwipeUpOverHome) {
+                if (mSwipeUpOverHome || !mDeviceState.isFullyGesturalNavMode()) {
                     mRecentsAnimationController.finish(true, null, true);
                     break;
                 }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
index 0f63336..63ef766 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -616,11 +616,7 @@
 
         if (!mOverviewComponentObserver.isHomeAndOverviewSame()) {
             shouldDefer = previousGestureState.getFinishingRecentsAnimationTaskId() < 0;
-            if (mDeviceState.isFullyGesturalNavMode()) {
-                factory = mFallbackSwipeHandlerFactory;
-            } else {
-                factory = this::determineFallbackTwoButtonSwipeHandler;
-            }
+            factory = mFallbackSwipeHandlerFactory;
         } else {
             shouldDefer = gestureState.getActivityInterface().deferStartingActivity(mDeviceState,
                     event);
@@ -633,23 +629,6 @@
                 mInputMonitorCompat, disableHorizontalSwipe, factory);
     }
 
-    /**
-     * Determines whether to use the LauncherSwipeHandler or FallbackSwipeHandler at runtime.
-     * We need to use the FallbackSwipeHandler to handle quick switch from home, otherwise the
-     * normal LauncherSwipeHandler works.
-     */
-    private BaseSwipeUpHandler determineFallbackTwoButtonSwipeHandler(GestureState gestureState,
-            long touchTimeMs, boolean continuingLastGesture, boolean isLikelyToStartNewTask) {
-        boolean runningOverHome = gestureState.getRunningTask() == null
-                || ActivityManagerWrapper.isHomeTask(gestureState.getRunningTask());
-        boolean isQuickSwitchMode = isLikelyToStartNewTask || continuingLastGesture;
-        BaseSwipeUpHandler.Factory factory = runningOverHome && isQuickSwitchMode
-                ? mFallbackSwipeHandlerFactory
-                : mLauncherSwipeHandlerFactory;
-        return factory.newHandler(gestureState, touchTimeMs, continuingLastGesture,
-                isLikelyToStartNewTask);
-    }
-
     private InputConsumer createDeviceLockedInputConsumer(GestureState gestureState) {
         if (mDeviceState.isFullyGesturalNavMode() && gestureState.getRunningTask() != null) {
             return new DeviceLockedInputConsumer(this, mDeviceState, mTaskAnimationManager,
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
index f60eaa7..8b0f138 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
@@ -37,7 +37,6 @@
 import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW;
 import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId;
 
-import android.animation.Animator;
 import android.animation.AnimatorSet;
 import android.animation.LayoutTransition;
 import android.animation.LayoutTransition.TransitionListener;
@@ -700,6 +699,21 @@
         return taskViewCount;
     }
 
+    /**
+     * Updates UI for a modal task, including hiding other tasks.
+     */
+    public void updateUiForModalTask(TaskView taskView, boolean isTaskOverlayModal) {
+        int currentIndex = indexOfChild(taskView);
+        TaskView previousTask = getTaskViewAt(currentIndex - 1);
+        TaskView nextTask = getTaskViewAt(currentIndex + 1);
+        if (previousTask != null) {
+            previousTask.setVisibility(isTaskOverlayModal ? View.INVISIBLE : View.VISIBLE);
+        }
+        if (nextTask != null) {
+            nextTask.setVisibility(isTaskOverlayModal ? View.INVISIBLE : View.VISIBLE);
+        }
+    }
+
     protected void onTaskStackUpdated() { }
 
     public void resetTaskVisuals() {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
index abc037e..0e1640e 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
@@ -245,6 +245,13 @@
         return mSnapshotView.getTaskOverlay().isOverlayModal();
     }
 
+    /** Updates UI based on whether the task is modal. */
+    public void updateUiForModalTask() {
+        if (getRecentsView() != null) {
+            getRecentsView().updateUiForModalTask(this, isTaskOverlayModal());
+        }
+    }
+
     public TaskMenuView getMenuView() {
         return mMenuView;
     }
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index 1c2acfd..18bc55a 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -240,6 +240,17 @@
      * and align above if there is enough vertical space.
      */
     protected void orientAboutObject() {
+        orientAboutObject(true /* allowAlignLeft */, true /* allowAlignRight */);
+    }
+
+    /**
+     * @see #orientAboutObject()
+     *
+     * @param allowAlignLeft Set to false if we already tried aligning left and didn't have room.
+     * @param allowAlignRight Set to false if we already tried aligning right and didn't have room.
+     * TODO: Can we test this with all permutations of widths/heights and icon locations + RTL?
+     */
+    private void orientAboutObject(boolean allowAlignLeft, boolean allowAlignRight) {
         measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
         int width = getMeasuredWidth();
         int extraVerticalSpace = mArrow.getLayoutParams().height + mArrowOffset
@@ -253,14 +264,8 @@
         // Align left (right in RTL) if there is room.
         int leftAlignedX = mTempRect.left;
         int rightAlignedX = mTempRect.right - width;
-        int x = leftAlignedX;
-        boolean canBeLeftAligned = leftAlignedX + width + insets.left
-                < dragLayer.getRight() - insets.right;
-        boolean canBeRightAligned = rightAlignedX > dragLayer.getLeft() + insets.left;
-        if (!canBeLeftAligned || (mIsRtl && canBeRightAligned)) {
-            x = rightAlignedX;
-        }
-        mIsLeftAligned = x == leftAlignedX;
+        mIsLeftAligned = !mIsRtl ? allowAlignLeft : !allowAlignRight;
+        int x = mIsLeftAligned ? leftAlignedX : rightAlignedX;
 
         // Offset x so that the arrow and shortcut icons are center-aligned with the original icon.
         int iconWidth = mTempRect.width();
@@ -282,6 +287,24 @@
         }
         x += mIsLeftAligned ? xOffset : -xOffset;
 
+        // Check whether we can still align as we originally wanted, now that we've calculated x.
+        if (!allowAlignLeft && !allowAlignRight) {
+            // We've already tried both ways and couldn't make it fit. onLayout() will set the
+            // gravity to CENTER_HORIZONTAL, but continue below to update y.
+        } else {
+            boolean canBeLeftAligned = x + width + insets.left
+                    < dragLayer.getRight() - insets.right;
+            boolean canBeRightAligned = x > dragLayer.getLeft() + insets.left;
+            boolean alignmentStillValid = mIsLeftAligned && canBeLeftAligned
+                    || !mIsLeftAligned && canBeRightAligned;
+            if (!alignmentStillValid) {
+                // Try again, but don't allow this alignment we already know won't work.
+                orientAboutObject(allowAlignLeft && !mIsLeftAligned /* allowAlignLeft */,
+                        allowAlignRight && mIsLeftAligned /* allowAlignRight */);
+                return;
+            }
+        }
+
         // Open above icon if there is room.
         int iconHeight = mTempRect.height();
         int y = mTempRect.top - height;