Merge "Render user's actual workspace in ThemePicker preview (Part 3)" into ub-launcher3-master
diff --git a/Android.bp b/Android.bp
index cb695df..e132854 100644
--- a/Android.bp
+++ b/Android.bp
@@ -47,3 +47,14 @@
     },
     static_libs: ["libprotobuf-java-lite"],
 }
+
+java_library {
+    name: "LauncherPluginLib",
+
+    static_libs: ["PluginCoreLib"],
+
+    srcs: ["src_plugins/**/*.java"],
+
+    sdk_version: "current",
+    min_sdk_version: "28",
+}
diff --git a/Android.mk b/Android.mk
index c066a12..9cfcf17 100644
--- a/Android.mk
+++ b/Android.mk
@@ -17,24 +17,6 @@
 LOCAL_PATH := $(call my-dir)
 
 #
-# Build rule for plugin lib (needed to write a plugin).
-#
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_AAPT2_ONLY := true
-LOCAL_MODULE_TAGS := optional
-LOCAL_STATIC_JAVA_LIBRARIES:= PluginCoreLib
-
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under, src_plugins)
-
-LOCAL_SDK_VERSION := current
-LOCAL_MIN_SDK_VERSION := 28
-LOCAL_MODULE := LauncherPluginLib
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-#
 # Build rule for Launcher3 dependencies lib.
 #
 include $(CLEAR_VARS)
diff --git a/protos/launcher_log.proto b/protos/launcher_log.proto
index ec1d55b..d08d851 100644
--- a/protos/launcher_log.proto
+++ b/protos/launcher_log.proto
@@ -151,6 +151,10 @@
   DISMISS_PREDICTION = 21;
   HYBRID_HOTSEAT_ACCEPTED = 22;
   HYBRID_HOTSEAT_CANCELED = 23;
+  OVERVIEW_ACTIONS_SHARE_BUTTON = 24;
+  OVERVIEW_ACTIONS_SCREENSHOT_BUTTON = 25;
+  OVERVIEW_ACTIONS_SELECT_BUTTON = 26;
+  SELECT_MODE_CLOSE_BUTTON = 27;
 }
 
 enum TipType {
diff --git a/quickstep/recents_ui_overrides/res/layout/overview_panel.xml b/quickstep/recents_ui_overrides/res/layout/overview_panel.xml
index 7f1425b..a572cad 100644
--- a/quickstep/recents_ui_overrides/res/layout/overview_panel.xml
+++ b/quickstep/recents_ui_overrides/res/layout/overview_panel.xml
@@ -14,12 +14,17 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<com.android.quickstep.views.LauncherRecentsView
+<com.android.launcher3.InsettableFrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:theme="@style/HomeScreenElementTheme"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:clipChildren="false"
-    android:clipToPadding="false"
-    android:accessibilityPaneTitle="@string/accessibility_recent_apps"
-    android:visibility="invisible" />
\ No newline at end of file
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content">
+    <com.android.quickstep.views.LauncherRecentsView
+        android:id="@+id/overview_panel_recents"
+        android:theme="@style/HomeScreenElementTheme"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:clipChildren="false"
+        android:clipToPadding="false"
+        android:accessibilityPaneTitle="@string/accessibility_recent_apps"
+        android:visibility="invisible" />
+</com.android.launcher3.InsettableFrameLayout>
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java
index b71fede..5a9c2fe 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java
@@ -70,9 +70,6 @@
     // if the aspect ratio of the target is smaller than the aspect ratio of the source rect. In
     // app window coordinates.
     private final RectF mSourceWindowClipInsets = new RectF();
-    // The insets to be used for clipping the app window. For live tile, we don't transform the clip
-    // relative to the target rect.
-    private final RectF mSourceWindowClipInsetsForLiveTile = new RectF();
     // The clip rect in source app window coordinates. The app window surface will only be drawn
     // within these bounds. This clip rect starts at the full mSourceStackBounds, and insets by
     // mSourceWindowClipInsets as the transform progress goes to 1.
@@ -149,7 +146,6 @@
                 Math.max(scaledTargetRect.top, 0),
                 Math.max(mSourceStackBounds.width() - scaledTargetRect.right, 0),
                 Math.max(mSourceStackBounds.height() - scaledTargetRect.bottom, 0));
-        mSourceWindowClipInsetsForLiveTile.set(mSourceWindowClipInsets);
         mSourceRect.set(scaledTargetRect);
     }
 
@@ -252,14 +248,12 @@
     private void updateClipRect(TransformParams params) {
         // Don't clip past progress > 1.
         float progress = Math.min(1, params.mProgress);
-        final RectF sourceWindowClipInsets = params.mForLiveTile
-                ? mSourceWindowClipInsetsForLiveTile : mSourceWindowClipInsets;
-        mCurrentClipRectF.left = sourceWindowClipInsets.left * progress;
-        mCurrentClipRectF.top = sourceWindowClipInsets.top * progress;
+        mCurrentClipRectF.left = mSourceWindowClipInsets.left * progress;
+        mCurrentClipRectF.top = mSourceWindowClipInsets.top * progress;
         mCurrentClipRectF.right =
-                mSourceStackBounds.width() - (sourceWindowClipInsets.right * progress);
+                mSourceStackBounds.width() - (mSourceWindowClipInsets.right * progress);
         mCurrentClipRectF.bottom =
-                mSourceStackBounds.height() - (sourceWindowClipInsets.bottom * progress);
+                mSourceStackBounds.height() - (mSourceWindowClipInsets.bottom * progress);
     }
 
     public RectF getCurrentRectWithInsets() {
@@ -400,7 +394,6 @@
         private float mOffsetScale;
         private @Nullable RectF mCurrentRect;
         private float mTargetAlpha;
-        private boolean mForLiveTile;
         private float mCornerRadius;
         private boolean mLauncherOnTop;
         private RemoteAnimationTargets mTargetSet;
@@ -412,7 +405,6 @@
             mOffsetScale = 1;
             mCurrentRect = null;
             mTargetAlpha = 1;
-            mForLiveTile = false;
             mCornerRadius = -1;
             mLauncherOnTop = false;
         }
@@ -477,16 +469,6 @@
         }
 
         /**
-         * Specifies whether we should clip the source window based on
-         * {@link AppWindowAnimationHelper#mSourceWindowClipInsetsForLiveTile} rather than
-         * {@link AppWindowAnimationHelper#mSourceWindowClipInsets} as {@link #mProgress} goes to 1.
-         */
-        public TransformParams setForLiveTile(boolean forLiveTile) {
-            mForLiveTile = forLiveTile;
-            return this;
-        }
-
-        /**
          * If true, sets the crop = null and layer = Integer.MAX_VALUE for targets that don't match
          * {@link #mTargetSet}.targetMode. (Currently only does this when live tiles are enabled.)
          */
@@ -539,10 +521,6 @@
             return mTargetAlpha;
         }
 
-        public boolean isForLiveTile() {
-            return mForLiveTile;
-        }
-
         public float getCornerRadius() {
             return mCornerRadius;
         }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
index d705cc0..3e106aa 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -201,8 +201,7 @@
             if (tv.isRunningTask()) {
                 mTransformParams.setProgress(1 - progress)
                         .setCurrentRect(null)
-                        .setSyncTransactionApplier(mSyncTransactionApplier)
-                        .setForLiveTile(true);
+                        .setSyncTransactionApplier(mSyncTransactionApplier);
                 mAppWindowAnimationHelper.applyTransform(mTransformParams);
             } else {
                 redrawLiveTile(true);
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index 15503b8..07d2381 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -194,7 +194,7 @@
 
         if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(this)) {
             // Overview is above all other launcher elements, including qsb, so move it to the top.
-            getOverviewPanel().bringToFront();
+            getOverviewPanelContainer().bringToFront();
         }
     }
 
diff --git a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
index d8b10b6..7d52571 100644
--- a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
+++ b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
@@ -15,6 +15,8 @@
  */
 package com.android.quickstep.util;
 
+import static com.android.launcher3.config.FeatureFlags.ENABLE_LSQ_VELOCITY_PROVIDER;
+
 import android.content.Context;
 import android.content.res.Resources;
 import android.view.MotionEvent;
@@ -85,7 +87,8 @@
         mForcePauseTimeout = new Alarm();
         mForcePauseTimeout.setOnAlarmListener(alarm -> updatePaused(true /* isPaused */));
         mMakePauseHarderToTrigger = makePauseHarderToTrigger;
-        mVelocityProvider = new LinearVelocityProvider(axis);
+        mVelocityProvider = ENABLE_LSQ_VELOCITY_PROVIDER.get()
+                ? new LSqVelocityProvider(axis) : new LinearVelocityProvider(axis);
     }
 
     /**
@@ -106,8 +109,6 @@
     /**
      * Computes velocity and acceleration to determine whether the motion is paused.
      * @param ev The motion being tracked.
-     *
-     * TODO: Use historical positions as well, e.g. {@link MotionEvent#getHistoricalY(int, int)}.
      */
     public void addPosition(MotionEvent ev) {
         addPosition(ev, 0);
@@ -248,4 +249,137 @@
             mPreviousPosition = null;
         }
     }
+
+    /**
+     * Java implementation of {@link android.view.VelocityTracker} using the Least Square (deg 2)
+     * algorithm.
+     */
+    private static class LSqVelocityProvider implements VelocityProvider {
+
+        // Maximum age of a motion event to be considered when calculating the velocity.
+        private static final long HORIZON_MS = 100;
+        // Number of samples to keep.
+        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 float[] mHistoricPos = new float[HISTORY_SIZE];
+        private int mHistoryCount = 0;
+        private int mHistoryStart = 0;
+
+        private final int mAxis;
+
+        LSqVelocityProvider(int axis) {
+            mAxis = axis;
+        }
+
+        @Override
+        public void clear() {
+            mHistoryCount = mHistoryStart = 0;
+        }
+
+        private void addPositionAndTime(float eventTime, float eventPosition) {
+            mHistoricTimes[mHistoryStart] = eventTime;
+            mHistoricPos[mHistoryStart] = eventPosition;
+            mHistoryStart++;
+            if (mHistoryStart >= HISTORY_SIZE) {
+                mHistoryStart = 0;
+            }
+            mHistoryCount = Math.min(HISTORY_SIZE, mHistoryCount + 1);
+        }
+
+        @Override
+        public Float addMotionEvent(MotionEvent ev, int pointer) {
+            // Add all historic points
+            int historyCount = ev.getHistorySize();
+            for (int i = 0; i < historyCount; i++) {
+                addPositionAndTime(
+                        ev.getHistoricalEventTime(i), ev.getHistoricalAxisValue(mAxis, pointer, i));
+            }
+
+            // Start index for the last position (about to be added)
+            int eventStartIndex = mHistoryStart;
+            addPositionAndTime(ev.getEventTime(), ev.getAxisValue(mAxis, pointer));
+            return solveUnweightedLeastSquaresDeg2(eventStartIndex);
+        }
+
+        /**
+         * Solves the instantaneous velocity.
+         * Based on solveUnweightedLeastSquaresDeg2 in VelocityTracker.cpp
+         */
+        private Float solveUnweightedLeastSquaresDeg2(final int pointPos) {
+            final float eventTime = mHistoricTimes[pointPos];
+
+            float sxi = 0, sxiyi = 0, syi = 0, sxi2 = 0, sxi3 = 0, sxi2yi = 0, sxi4 = 0;
+            int count = 0;
+            for (int i = 0; i < mHistoryCount; i++) {
+                int index = pointPos - i;
+                if (index < 0) {
+                    index += HISTORY_SIZE;
+                }
+
+                float time = mHistoricTimes[index];
+                float age = eventTime - time;
+                if (age > HORIZON_MS) {
+                    break;
+                }
+                count++;
+                float xi = -age;
+
+                float yi = mHistoricPos[index];
+                float xi2 = xi * xi;
+                float xi3 = xi2 * xi;
+                float xi4 = xi3 * xi;
+                float xiyi = xi * yi;
+                float xi2yi = xi2 * yi;
+
+                sxi += xi;
+                sxi2 += xi2;
+                sxiyi += xiyi;
+                sxi2yi += xi2yi;
+                syi += yi;
+                sxi3 += xi3;
+                sxi4 += xi4;
+            }
+
+            if (count < 3) {
+                // Too few samples
+                if (count == 2) {
+                    int endPos = pointPos - 1;
+                    if (endPos < 0) {
+                        endPos += HISTORY_SIZE;
+                    }
+                    float denominator = eventTime - mHistoricTimes[endPos];
+                    if (denominator != 0) {
+                        return (eventTime - mHistoricPos[endPos]) / denominator;
+
+                    }
+                }
+                return null;
+            }
+
+            float Sxx = sxi2 - sxi * sxi / count;
+            float Sxy = sxiyi - sxi * syi / count;
+            float Sxx2 = sxi3 - sxi * sxi2 / count;
+            float Sx2y = sxi2yi - sxi2 * syi / count;
+            float Sx2x2 = sxi4 - sxi2 * sxi2 / count;
+
+            float denominator = Sxx * Sx2x2 - Sxx2 * Sxx2;
+            if (denominator == 0) {
+                // division by 0 when computing velocity
+                return null;
+            }
+            // Compute a
+            // float numerator = Sx2y*Sxx - Sxy*Sxx2;
+
+            // Compute b
+            float numerator = Sxy * Sx2x2 - Sx2y * Sxx2;
+            float b = numerator / denominator;
+
+            // Compute c
+            // float c = syi/count - b * sxi/count - a * sxi2/count;
+
+            return b;
+        }
+    }
 }
diff --git a/res/layout/launcher.xml b/res/layout/launcher.xml
index cca899b..6c66897 100644
--- a/res/layout/launcher.xml
+++ b/res/layout/launcher.xml
@@ -44,9 +44,8 @@
             layout="@layout/hotseat" />
 
         <include
-            android:id="@+id/overview_panel"
-            layout="@layout/overview_panel"
-            android:visibility="gone" />
+            android:id="@+id/overview_panel_container"
+            layout="@layout/overview_panel"/>
 
         <!-- Keep these behind the workspace so that they are not visible when
          we go into AllApps -->
diff --git a/res/layout/overview_panel.xml b/res/layout/overview_panel.xml
index bdd5d23..7fff711 100644
--- a/res/layout/overview_panel.xml
+++ b/res/layout/overview_panel.xml
@@ -14,7 +14,9 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<Space
+<FrameLayout
       xmlns:android="http://schemas.android.com/apk/res/android"
+      android:id="@+id/overview_panel_recents"
       android:layout_width="0dp"
-      android:layout_height="0dp" />
\ No newline at end of file
+      android:layout_height="0dp"
+      android:visibility="gone" />
\ No newline at end of file
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 3fc8de2..33f5a95 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -80,6 +80,7 @@
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.OvershootInterpolator;
+import android.widget.FrameLayout;
 import android.widget.Toast;
 
 import androidx.annotation.Nullable;
@@ -273,6 +274,7 @@
 
     // UI and state for the overview panel
     private View mOverviewPanel;
+    private FrameLayout mOverviewPanelContainer;
 
     @Thunk
     boolean mWorkspaceLoading = true;
@@ -1143,7 +1145,8 @@
         mFocusHandler = mDragLayer.getFocusIndicatorHelper();
         mWorkspace = mDragLayer.findViewById(R.id.workspace);
         mWorkspace.initParentViews(mDragLayer);
-        mOverviewPanel = findViewById(R.id.overview_panel);
+        mOverviewPanel = findViewById(R.id.overview_panel_recents);
+        mOverviewPanelContainer = findViewById(R.id.overview_panel_container);
         mHotseat = findViewById(R.id.hotseat);
 
         mLauncherView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
@@ -1386,6 +1389,10 @@
         return (T) mOverviewPanel;
     }
 
+    public FrameLayout getOverviewPanelContainer() {
+        return mOverviewPanelContainer;
+    }
+
     public DropTargetBar getDropTargetBar() {
         return mDropTargetBar;
     }
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 6413044..3d8a9d7 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -135,6 +135,10 @@
             "ENABLE_UNIVERSAL_SMARTSPACE", false,
             "Replace Smartspace with a version rendered by System UI.");
 
+    public static final BooleanFlag ENABLE_LSQ_VELOCITY_PROVIDER = getDebugFlag(
+            "ENABLE_LSQ_VELOCITY_PROVIDER", false,
+            "Use Least Square algorithm for motion pause detection.");
+
     public static void initialize(Context context) {
         synchronized (sDebugFlags) {
             for (DebugFlag flag : sDebugFlags) {
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index c72509e..e33d89f 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -33,6 +33,7 @@
 
 import static java.util.Arrays.asList;
 import static java.util.Arrays.stream;
+import static java.util.Optional.ofNullable;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -95,6 +96,7 @@
 import com.android.launcher3.userevent.LauncherLogProto.LauncherEvent;
 import com.android.launcher3.userevent.LauncherLogProto.Target;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
+import com.android.launcher3.util.Executors;
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.views.ClipPathView;
 import com.android.launcher3.widget.PendingAddShortcutInfo;
@@ -322,12 +324,11 @@
         post(() -> {
             if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
                 if (isEmpty(mFolderName.getText())) {
-                    FolderNameInfo[] nameInfos =
-                            (FolderNameInfo[]) mInfo.suggestedFolderNames.getParcelableArrayExtra(
-                                    FolderInfo.EXTRA_FOLDER_SUGGESTIONS);
-                    if (nameInfos != null) {
-                        showLabelSuggestion(nameInfos, false);
-                    }
+                    ofNullable(mInfo)
+                            .map(info -> info.suggestedFolderNames)
+                            .map(folderNames -> (FolderNameInfo[]) folderNames
+                                    .getParcelableArrayExtra(FolderInfo.EXTRA_FOLDER_SUGGESTIONS))
+                            .ifPresent(nameInfos -> showLabelSuggestion(nameInfos, false));
                 }
             }
             mFolderName.setHint("");
@@ -345,7 +346,7 @@
         }
 
         mInfo.title = newTitle;
-        mInfo.setOption(FLAG_MANUAL_FOLDER_NAME, mFolderName.isEnteredCompose(),
+        mInfo.setOption(FLAG_MANUAL_FOLDER_NAME, getAcceptedSuggestionIndex() < 0,
                 mLauncher.getModelWriter());
         mFolderIcon.onTitleChanged(newTitle);
         mLauncher.getModelWriter().updateItemInDatabase(mInfo);
@@ -426,7 +427,7 @@
         mInfo = info;
         ArrayList<WorkspaceItemInfo> children = info.contents;
         Collections.sort(children, ITEM_POS_COMPARATOR);
-        updateItemLocationsInDatabaseBatch();
+        updateItemLocationsInDatabaseBatch(true);
 
         DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
         if (lp == null) {
@@ -436,19 +437,15 @@
         }
         mItemsInvalidated = true;
         mInfo.addListener(this);
+        mPreviousLabel = mInfo.title.toString();
+        mIsPreviousLabelSuggested = !mInfo.hasOption(FLAG_MANUAL_FOLDER_NAME);
 
         if (!isEmpty(mInfo.title)) {
             mFolderName.setText(mInfo.title);
-            mPreviousLabel = mInfo.title.toString();
-            mIsPreviousLabelSuggested = !mInfo.hasOption(FLAG_MANUAL_FOLDER_NAME);
             mFolderName.setHint(null);
         } else {
             mFolderName.setText("");
-            if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
-                mFolderName.setHint("");
-            } else {
-                mFolderName.setHint(R.string.folder_hint_text);
-            }
+            mFolderName.setHint(R.string.folder_hint_text);
         }
         // In case any children didn't come across during loading, clean up the folder accordingly
         mFolderIcon.post(() -> {
@@ -464,8 +461,6 @@
      */
     public void showSuggestedTitle(FolderNameInfo[] nameInfos) {
         if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
-            mInfo.suggestedFolderNames = new Intent().putExtra(FolderInfo.EXTRA_FOLDER_SUGGESTIONS,
-                    nameInfos);
             if (isEmpty(mFolderName.getText().toString())
                     && !mInfo.hasOption(FLAG_MANUAL_FOLDER_NAME)) {
                 showLabelSuggestion(nameInfos, true);
@@ -985,7 +980,7 @@
 
         // Reordering may have occured, and we need to save the new item locations. We do this once
         // at the end to prevent unnecessary database operations.
-        updateItemLocationsInDatabaseBatch();
+        updateItemLocationsInDatabaseBatch(false);
         // Use the item count to check for multi-page as the folder UI may not have
         // been refreshed yet.
         if (getItemCount() <= mContent.itemsPerPage()) {
@@ -995,7 +990,7 @@
         }
     }
 
-    private void updateItemLocationsInDatabaseBatch() {
+    private void updateItemLocationsInDatabaseBatch(boolean isBind) {
         FolderGridOrganizer verifier = new FolderGridOrganizer(
                 mLauncher.getDeviceProfile().inv).setFolderInfo(mInfo);
 
@@ -1011,6 +1006,18 @@
         if (!items.isEmpty()) {
             mLauncher.getModelWriter().moveItemsInDatabase(items, mInfo.id, 0);
         }
+        if (FeatureFlags.FOLDER_NAME_SUGGEST.get() && !isBind) {
+            Executors.MODEL_EXECUTOR.post(() -> {
+                FolderNameInfo[] nameInfos =
+                        new FolderNameInfo[FolderNameProvider.SUGGEST_MAX];
+                FolderNameProvider fnp = FolderNameProvider.newInstance(getContext());
+                fnp.getSuggestedFolderName(
+                        getContext(), mInfo.contents, nameInfos);
+                mInfo.suggestedFolderNames = new Intent().putExtra(
+                        FolderInfo.EXTRA_FOLDER_SUGGESTIONS,
+                        nameInfos);
+            });
+        }
     }
 
     public void notifyDrop() {
@@ -1315,7 +1322,7 @@
             // We only need to update the locations if it doesn't get handled in
             // #onDropCompleted.
             if (d.dragSource != this) {
-                updateItemLocationsInDatabaseBatch();
+                updateItemLocationsInDatabaseBatch(false);
             }
         }
 
@@ -1356,7 +1363,7 @@
         verifier.updateRankAndPos(item, rank);
         mLauncher.getModelWriter().addOrMoveItemInDatabase(item, mInfo.id, 0, item.cellX,
                 item.cellY);
-        updateItemLocationsInDatabaseBatch();
+        updateItemLocationsInDatabaseBatch(false);
 
         if (mContent.areViewsBound()) {
             mContent.createAndAddViewForRank(item, rank);
@@ -1647,26 +1654,8 @@
                 checkNotNull(mFolderName.getText().toString(),
                         "Expected valid folder label, but found null");
 
-        Optional<String[]> suggestedLabels = Optional.ofNullable(
-                (FolderNameInfo[]) mInfo.suggestedFolderNames
-                        .getParcelableArrayExtra(FolderInfo.EXTRA_FOLDER_SUGGESTIONS))
-                .map(folderNameInfoArray ->
-                        stream(folderNameInfoArray)
-                                .filter(Objects::nonNull)
-                                .map(FolderNameInfo::getLabel)
-                                .map(CharSequence::toString)
-                                .toArray(String[]::new));
-
-
-        int accepted_suggestion_index = suggestedLabels
-                .map(folderNameInfoArray ->
-                        IntStream.range(0, folderNameInfoArray.length)
-                                .filter(index -> newLabel.equalsIgnoreCase(
-                                        folderNameInfoArray[index]))
-                                .findFirst()
-                                .orElse(-1)
-                ).orElse(-1);
-
+        Optional<String[]> suggestedLabels = getSuggestedLabels();
+        int accepted_suggestion_index = getAcceptedSuggestionIndex();
         boolean hasValidPrimary = suggestedLabels
                 .map(labels -> labels.length > 0 && !isEmpty(labels[0]))
                 .orElse(false);
@@ -1695,6 +1684,39 @@
                         : Target.ToFolderLabelState.valueOf("TO_CUSTOM" + suggestionsSuffix);
     }
 
+    private Optional<String[]> getSuggestedLabels() {
+        return ofNullable(mInfo)
+            .map(info -> info.suggestedFolderNames)
+            .map(
+                folderNames ->
+                    (FolderNameInfo[])
+                        folderNames.getParcelableArrayExtra(FolderInfo.EXTRA_FOLDER_SUGGESTIONS))
+            .map(
+                folderNameInfoArray ->
+                    stream(folderNameInfoArray)
+                        .filter(Objects::nonNull)
+                        .map(FolderNameInfo::getLabel)
+                        .filter(Objects::nonNull)
+                        .map(CharSequence::toString)
+                        .toArray(String[]::new));
+    }
+
+    private int getAcceptedSuggestionIndex() {
+        String newLabel =
+                checkNotNull(mFolderName.getText().toString(),
+                        "Expected valid folder label, but found null");
+
+        return getSuggestedLabels()
+                .map(suggestionsArray ->
+                        IntStream.range(0, suggestionsArray.length)
+                                .filter(index -> newLabel.equalsIgnoreCase(
+                                        suggestionsArray[index]))
+                                .findFirst()
+                                .orElse(-1)
+                ).orElse(-1);
+
+    }
+
 
     private Target.Builder newEditTextTargetBuilder() {
         return Target.newBuilder().setType(Target.Type.ITEM).setItemType(ItemType.EDITTEXT);
diff --git a/src/com/android/launcher3/folder/FolderNameEditText.java b/src/com/android/launcher3/folder/FolderNameEditText.java
index 7e11b18..edf2c70 100644
--- a/src/com/android/launcher3/folder/FolderNameEditText.java
+++ b/src/com/android/launcher3/folder/FolderNameEditText.java
@@ -102,13 +102,6 @@
         mEnteredCompose = value;
     }
 
-    protected boolean isEnteredCompose() {
-        if (DEBUG) {
-            Log.d(TAG, "isEnteredCompose " + mEnteredCompose);
-        }
-        return mEnteredCompose;
-    }
-
     private class FolderNameEditTextInputConnection extends InputConnectionWrapper {
 
         FolderNameEditTextInputConnection(InputConnection target, boolean mutable) {
diff --git a/src/com/android/launcher3/folder/FolderNameInfo.java b/src/com/android/launcher3/folder/FolderNameInfo.java
index ecbe46c..1287219 100644
--- a/src/com/android/launcher3/folder/FolderNameInfo.java
+++ b/src/com/android/launcher3/folder/FolderNameInfo.java
@@ -84,6 +84,6 @@
     @Override
     @NonNull
     public String toString() {
-        return mLabel.toString() + ":" + mScore;
+        return String.format("%s:%.2f", mLabel, mScore);
     }
 }
diff --git a/src/com/android/launcher3/logging/FileLog.java b/src/com/android/launcher3/logging/FileLog.java
index 67f07b1..a3fdf8d 100644
--- a/src/com/android/launcher3/logging/FileLog.java
+++ b/src/com/android/launcher3/logging/FileLog.java
@@ -10,6 +10,7 @@
 
 import androidx.annotation.VisibleForTesting;
 
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.util.IOUtils;
 
 import java.io.BufferedReader;
@@ -42,7 +43,7 @@
     private static Handler sHandler = null;
     private static File sLogsDirectory = null;
 
-    public static final int LOG_DAYS = 4;
+    public static final int LOG_DAYS = FeatureFlags.ENABLE_HYBRID_HOTSEAT.get() ? 10 : 4;
 
     public static void setDir(File logsDir) {
         if (ENABLED) {
diff --git a/src/com/android/launcher3/logging/UserEventDispatcher.java b/src/com/android/launcher3/logging/UserEventDispatcher.java
index 199d13f..afa3f6d 100644
--- a/src/com/android/launcher3/logging/UserEventDispatcher.java
+++ b/src/com/android/launcher3/logging/UserEventDispatcher.java
@@ -147,7 +147,7 @@
             fillIntentInfo(event.srcTarget[0], intent, userHandle);
         }
         ItemInfo info = (ItemInfo) v.getTag();
-        if (Utilities.IS_DEBUG_DEVICE && FeatureFlags.ENABLE_HYBRID_HOTSEAT.get()) {
+        if (info != null && Utilities.IS_DEBUG_DEVICE && FeatureFlags.ENABLE_HYBRID_HOTSEAT.get()) {
             FileLog.d(TAG, "appLaunch: packageName:" + info.getTargetComponent().getPackageName()
                     + ",isWorkApp:" + (info.user != null && !Process.myUserHandle().equals(
                     userHandle)) + ",launchLocation:" + info.container);
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index d9bd714..065eb37 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -32,6 +32,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.ShapeDrawable;
 import android.util.AttributeSet;
+import android.util.Pair;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -358,6 +359,11 @@
         }
     }
 
+    @Override
+    protected Pair<View, String> getAccessibilityTarget() {
+        return Pair.create(this, "");
+    }
+
     private void animateOpen() {
         setVisibility(View.VISIBLE);
 
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 05ea694..445acca 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -37,7 +37,6 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.util.AttributeSet;
-import android.util.Pair;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
@@ -330,11 +329,6 @@
     }
 
     @Override
-    protected Pair<View, String> getAccessibilityTarget() {
-        return Pair.create(this, "");
-    }
-
-    @Override
     protected void getTargetObjectLocation(Rect outPos) {
         getPopupContainer().getDescendantRectRelativeToSelf(mOriginalIcon, outPos);
         outPos.top += mOriginalIcon.getPaddingTop();
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index b3b887d..6775521 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -145,7 +145,7 @@
 
     private static final String WORKSPACE_RES_ID = "workspace";
     private static final String APPS_RES_ID = "apps_view";
-    private static final String OVERVIEW_RES_ID = "overview_panel";
+    private static final String OVERVIEW_RES_ID = "overview_panel_recents";
     private static final String WIDGETS_RES_ID = "widgets_list_view";
     private static final String CONTEXT_MENU_RES_ID = "deep_shortcuts_container";
     public static final int WAIT_TIME_MS = 10000;