Merge "Track OverviewToHomeAnim with StateManager" into ub-launcher3-rvc-qpr-dev
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
index 0ee5d04..7bae2e5 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
@@ -25,6 +25,7 @@
 import android.animation.AnimatorListenerAdapter;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.animation.Interpolator;
 
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.BaseDraggingActivity;
@@ -206,14 +207,19 @@
         long maxDuration = 2 * secondaryLayerDimension;
         int verticalFactor = orientationHandler.getTaskDragDisplacementFactor(mIsRtl);
         int secondaryTaskDimension = orientationHandler.getSecondaryDimension(mTaskBeingDragged);
+        // The interpolator controlling the most prominent visual movement. We use this to determine
+        // whether we passed SUCCESS_TRANSITION_PROGRESS.
+        final Interpolator currentInterpolator;
         if (goingUp) {
+            currentInterpolator = Interpolators.LINEAR;
             mPendingAnimation = mRecentsView.createTaskDismissAnimation(mTaskBeingDragged,
                     true /* animateTaskView */, true /* removeTask */, maxDuration);
 
             mEndDisplacement = -secondaryTaskDimension;
         } else {
+            currentInterpolator = Interpolators.ZOOM_IN;
             mPendingAnimation = mRecentsView.createTaskLaunchAnimation(
-                    mTaskBeingDragged, maxDuration, Interpolators.ZOOM_IN);
+                    mTaskBeingDragged, maxDuration, currentInterpolator);
 
             // Since the thumbnail is what is filling the screen, based the end displacement on it.
             View thumbnailView = mTaskBeingDragged.getThumbnail();
@@ -228,6 +234,9 @@
         }
         mCurrentAnimation = mPendingAnimation.createPlaybackController()
                 .setOnCancelRunnable(this::clearState);
+        // Setting this interpolator doesn't affect the visual motion, but is used to determine
+        // whether we successfully reached the target state in onDragEnd().
+        mCurrentAnimation.getTarget().setInterpolator(currentInterpolator);
         onUserControlledAnimationCreated(mCurrentAnimation);
         mCurrentAnimation.getTarget().addListener(this);
         mCurrentAnimation.dispatchOnStart();
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java
index ed33532..0aa1486 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java
@@ -493,7 +493,11 @@
         // much the window is bound by overscroll (vs moving freely).
         if (animate) {
             ValueAnimator reapplyWindowTransformAnim = ValueAnimator.ofFloat(0, 1);
-            reapplyWindowTransformAnim.addUpdateListener(anim -> applyWindowTransform());
+            reapplyWindowTransformAnim.addUpdateListener(anim -> {
+                if (mRunningWindowAnim == null) {
+                    applyWindowTransform();
+                }
+            });
             reapplyWindowTransformAnim.setDuration(RECENTS_ATTACH_DURATION).start();
         } else {
             applyWindowTransform();
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverscrollPluginFactory.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverscrollPluginFactory.java
new file mode 100644
index 0000000..4c261ab
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverscrollPluginFactory.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep;
+
+import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
+
+import com.android.launcher3.R;
+import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.ResourceBasedOverride;
+import com.android.systemui.plugins.OverscrollPlugin;
+
+/**
+ * Resource overrideable factory for forcing a local overscroll plugin.
+ * Override {@link R.string#overscroll_plugin_factory_class} to set a different class.
+ */
+public class OverscrollPluginFactory implements ResourceBasedOverride {
+    public static final MainThreadInitializedObject<OverscrollPluginFactory> INSTANCE = forOverride(
+            OverscrollPluginFactory.class,
+            R.string.overscroll_plugin_factory_class);
+
+    /**
+     * Get the plugin that is defined locally in launcher, as opposed to a dynamic side loaded one.
+     */
+    public OverscrollPlugin getLocalOverscrollPlugin() {
+        return null;
+    }
+}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java
index db512fa..36579ec 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java
@@ -18,7 +18,6 @@
 
 import static android.view.Surface.ROTATION_0;
 
-import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
 import static com.android.quickstep.views.OverviewActionsView.DISABLED_NO_THUMBNAIL;
 import static com.android.quickstep.views.OverviewActionsView.DISABLED_ROTATED;
 
@@ -39,13 +38,11 @@
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.popup.SystemShortcut;
-import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.ResourceBasedOverride;
 import com.android.quickstep.util.RecentsOrientedState;
 import com.android.quickstep.views.OverviewActionsView;
 import com.android.quickstep.views.TaskThumbnailView;
 import com.android.quickstep.views.TaskView;
-import com.android.systemui.plugins.OverscrollPlugin;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 
@@ -91,20 +88,22 @@
         return shortcuts;
     }
 
-    public static final MainThreadInitializedObject<TaskOverlayFactory> INSTANCE =
-            forOverride(TaskOverlayFactory.class, R.string.task_overlay_factory_class);
-
-    /**
-     * @return a launcher-provided OverscrollPlugin if available, otherwise null
-     */
-    public OverscrollPlugin getLocalOverscrollPlugin() {
-        return null;
-    }
-
     public TaskOverlay createOverlay(TaskThumbnailView thumbnailView) {
         return new TaskOverlay(thumbnailView);
     }
 
+    /**
+     * Subclasses can attach any system listeners in this method, must be paired with
+     * {@link #removeListeners()}
+     */
+    public void initListeners() { }
+
+    /**
+     * Subclasses should remove any system listeners in this method, must be paired with
+     * {@link #initListeners()}
+     */
+    public void removeListeners() { }
+
     /** Note that these will be shown in order from top to bottom, if available for the task. */
     private static final TaskShortcutFactory[] MENU_OPTIONS = new TaskShortcutFactory[]{
             TaskShortcutFactory.APP_INFO,
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 13adff5..7b91001 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -597,9 +597,8 @@
             if (FeatureFlags.ENABLE_QUICK_CAPTURE_GESTURE.get()) {
                 OverscrollPlugin plugin = null;
                 if (FeatureFlags.FORCE_LOCAL_OVERSCROLL_PLUGIN.get()) {
-                    TaskOverlayFactory factory =
-                            TaskOverlayFactory.INSTANCE.get(getApplicationContext());
-                    plugin = factory.getLocalOverscrollPlugin();  // may be null
+                    plugin = OverscrollPluginFactory.INSTANCE.get(
+                            getApplicationContext()).getLocalOverscrollPlugin();
                 }
 
                 // If not local plugin was forced, use the actual overscroll plugin if available.
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 217997d..1d17f5a 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
@@ -24,6 +24,7 @@
 import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_ICON_PARAMS;
 import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
 import static com.android.launcher3.LauncherState.BACKGROUND_APP;
+import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK;
 import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
 import static com.android.launcher3.Utilities.mapToRange;
 import static com.android.launcher3.Utilities.squaredHypot;
@@ -93,6 +94,7 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Insettable;
 import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.LauncherState;
 import com.android.launcher3.PagedView;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
@@ -115,6 +117,7 @@
 import com.android.launcher3.util.DynamicResource;
 import com.android.launcher3.util.MultiValueAlpha;
 import com.android.launcher3.util.OverScroller;
+import com.android.launcher3.util.ResourceBasedOverride.Overrides;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.util.ViewPool;
 import com.android.quickstep.BaseActivityInterface;
@@ -123,6 +126,7 @@
 import com.android.quickstep.RecentsModel;
 import com.android.quickstep.RecentsModel.TaskVisualsChangeListener;
 import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.TaskOverlayFactory;
 import com.android.quickstep.TaskThumbnailCache;
 import com.android.quickstep.TaskUtils;
 import com.android.quickstep.ViewUtils;
@@ -277,6 +281,8 @@
 
     private final ViewPool<TaskView> mTaskViewPool;
 
+    private final TaskOverlayFactory mTaskOverlayFactory;
+
     private boolean mDwbToastShown;
     protected boolean mDisallowScrollToClearAll;
     private boolean mOverlayEnabled;
@@ -464,6 +470,11 @@
         updateEmptyMessage();
         mOrientationHandler = mOrientationState.getOrientationHandler();
 
+        mTaskOverlayFactory = Overrides.getObject(
+                TaskOverlayFactory.class,
+                context.getApplicationContext(),
+                R.string.task_overlay_factory_class);
+
         // Initialize quickstep specific cache params here, as this is constructed only once
         mActivity.getViewCache().setCacheSize(R.layout.digital_wellbeing_toast, 5);
     }
@@ -557,6 +568,7 @@
                 mIPinnedStackAnimationListener);
         mOrientationState.initListeners();
         SplitScreenBounds.INSTANCE.addOnChangeListener(this);
+        mTaskOverlayFactory.initListeners();
     }
 
     @Override
@@ -573,6 +585,7 @@
         SplitScreenBounds.INSTANCE.removeOnChangeListener(this);
         mIPinnedStackAnimationListener.setActivity(null);
         mOrientationState.destroyListeners();
+        mTaskOverlayFactory.removeListeners();
     }
 
     @Override
@@ -1712,6 +1725,12 @@
         if (mOrientationState.setRecentsRotation(mActivity.getDisplay().getRotation())) {
             updateOrientationHandler();
         }
+        // If overview is in modal state when rotate, reset it to overview state without running
+        // animation.
+        if (mActivity.isInState(OVERVIEW_MODAL_TASK)) {
+            mActivity.getStateManager().goToState(LauncherState.OVERVIEW, false);
+            resetModalVisuals();
+        }
     }
 
     public void setLayoutRotation(int touchRotation, int displayRotation) {
@@ -2424,6 +2443,10 @@
      */
     public void setModalStateEnabled(boolean isModalState) { }
 
+    public TaskOverlayFactory getTaskOverlayFactory() {
+        return mTaskOverlayFactory;
+    }
+
     public BaseActivityInterface getSizeStrategy() {
         return mSizeStrategy;
     }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java
index fad6427..607672a 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -52,7 +52,6 @@
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.SystemUiController;
 import com.android.launcher3.util.Themes;
-import com.android.quickstep.TaskOverlayFactory;
 import com.android.quickstep.TaskOverlayFactory.TaskOverlay;
 import com.android.quickstep.views.TaskView.FullscreenDrawParams;
 import com.android.systemui.plugins.OverviewScreenshotActions;
@@ -85,7 +84,7 @@
             };
 
     private final BaseActivity mActivity;
-    private final TaskOverlay mOverlay;
+    private TaskOverlay mOverlay;
     private final boolean mIsDarkTextTheme;
     private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
     private final Paint mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
@@ -118,7 +117,6 @@
 
     public TaskThumbnailView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
-        mOverlay = TaskOverlayFactory.INSTANCE.get(context).createOverlay(this);
         mPaint.setFilterBitmap(true);
         mBackgroundPaint.setColor(Color.WHITE);
         mClearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
@@ -134,7 +132,7 @@
      * @param task
      */
     public void bind(Task task) {
-        mOverlay.reset();
+        getTaskOverlay().reset();
         mTask = task;
         int color = task == null ? Color.BLACK : task.colorBackground | 0xFF000000;
         mPaint.setColor(color);
@@ -176,7 +174,7 @@
             mBitmapShader = null;
             mThumbnailData = null;
             mPaint.setShader(null);
-            mOverlay.reset();
+            getTaskOverlay().reset();
         }
         if (mOverviewScreenshotActionsPlugin != null) {
             mOverviewScreenshotActionsPlugin.setupActions(getTaskView(), getThumbnail(), mActivity);
@@ -200,6 +198,9 @@
     }
 
     public TaskOverlay getTaskOverlay() {
+        if (mOverlay == null) {
+            mOverlay = getTaskView().getRecentsView().getTaskOverlayFactory().createOverlay(this);
+        }
         return mOverlay;
     }
 
@@ -357,10 +358,10 @@
 
     private void updateOverlay() {
         if (mOverlayEnabled) {
-            mOverlay.initOverlay(mTask, mThumbnailData, mPreviewPositionHelper.mMatrix,
+            getTaskOverlay().initOverlay(mTask, mThumbnailData, mPreviewPositionHelper.mMatrix,
                     mPreviewPositionHelper.mIsOrientationChanged);
         } else {
-            mOverlay.reset();
+            getTaskOverlay().reset();
         }
     }
 
diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml
index 0f2955b..a57112b 100644
--- a/quickstep/res/values/config.xml
+++ b/quickstep/res/values/config.xml
@@ -16,6 +16,8 @@
 <resources>
     <string name="task_overlay_factory_class" translatable="false"/>
 
+    <string name="overscroll_plugin_factory_class" translatable="false" />
+
     <!-- Activities which block home gesture -->
     <string-array name="gesture_blocking_activities" translatable="false">
         <item>com.android.launcher3/com.android.quickstep.interaction.GestureSandboxActivity</item>
diff --git a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
index 969fa50..f60f7ad 100644
--- a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
+++ b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
@@ -276,7 +276,7 @@
         private static final int HISTORY_SIZE = 20;
 
         // Position history are stored in a circular array
-        private final float[] mHistoricTimes = new float[HISTORY_SIZE];
+        private final long[] mHistoricTimes = new long[HISTORY_SIZE];
         private final float[] mHistoricPos = new float[HISTORY_SIZE];
         private int mHistoryCount = 0;
         private int mHistoryStart = 0;
@@ -292,7 +292,7 @@
             mHistoryCount = mHistoryStart = 0;
         }
 
-        private void addPositionAndTime(float eventTime, float eventPosition) {
+        private void addPositionAndTime(long eventTime, float eventPosition) {
             mHistoricTimes[mHistoryStart] = eventTime;
             mHistoricPos[mHistoryStart] = eventPosition;
             mHistoryStart++;
@@ -322,7 +322,7 @@
          * Based on solveUnweightedLeastSquaresDeg2 in VelocityTracker.cpp
          */
         private Float solveUnweightedLeastSquaresDeg2(final int pointPos) {
-            final float eventTime = mHistoricTimes[pointPos];
+            final long eventTime = mHistoricTimes[pointPos];
 
             float sxi = 0, sxiyi = 0, syi = 0, sxi2 = 0, sxi3 = 0, sxi2yi = 0, sxi4 = 0;
             int count = 0;
@@ -332,8 +332,8 @@
                     index += HISTORY_SIZE;
                 }
 
-                float time = mHistoricTimes[index];
-                float age = eventTime - time;
+                long time = mHistoricTimes[index];
+                long age = eventTime - time;
                 if (age > HORIZON_MS) {
                     break;
                 }
@@ -364,7 +364,7 @@
                         if (endPos < 0) {
                             endPos += HISTORY_SIZE;
                         }
-                        float denominator = eventTime - mHistoricTimes[endPos];
+                        long denominator = eventTime - mHistoricTimes[endPos];
                         if (denominator != 0) {
                             return (mHistoricPos[pointPos] - mHistoricPos[endPos]) / denominator;
                         }
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 45116b6..88a9aba 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -92,7 +92,7 @@
 
     // Keep as DeviceFlag to allow remote disable in emergency.
     public static final BooleanFlag ENABLE_SUGGESTED_ACTIONS_OVERVIEW = new DeviceFlag(
-            "ENABLE_SUGGESTED_ACTIONS_OVERVIEW", false, "Show chip hints on the overview screen");
+            "ENABLE_SUGGESTED_ACTIONS_OVERVIEW", true, "Show chip hints on the overview screen");
 
     public static final BooleanFlag FOLDER_NAME_SUGGEST = new DeviceFlag(
             "FOLDER_NAME_SUGGEST", true,