Pause page scrolls while new recommendation are being applied

http://screencast/cast/NDg4NzU2MjI3NDQ3MTkzNnw5MTU1NTc4Yy1lYw
http://screencast/cast/NDk5Nzg4MzQ5MjMwMjg0OHxmZGM0MGZlYS0wMg

This cl is NO-OP for anything else using it already. Just renamed it.

Bug: 318410881
Test: Manual (see screencast)
Flag: ACONFIG com.android.launcher3.enable_categorized_widget_recommendations DEVELOPMENT
Change-Id: I55d599437b2554f58d635d11f2b603516b030f30
diff --git a/src/com/android/launcher3/ModelCallbacks.kt b/src/com/android/launcher3/ModelCallbacks.kt
index 0e38007..9867556 100644
--- a/src/com/android/launcher3/ModelCallbacks.kt
+++ b/src/com/android/launcher3/ModelCallbacks.kt
@@ -132,7 +132,7 @@
         launcher.viewCache.setCacheSize(R.layout.folder_page, 2)
         TraceHelper.INSTANCE.endSection()
         launcher.workspace.removeExtraEmptyScreen(/* stripEmptyScreens= */ true)
-        launcher.workspace.pageIndicator.setAreScreensBinding(false, deviceProfile.isTwoPanels)
+        launcher.workspace.pageIndicator.setPauseScroll(/*pause=*/ false, deviceProfile.isTwoPanels)
     }
 
     /**
@@ -299,8 +299,8 @@
     }
 
     override fun bindScreens(orderedScreenIds: LIntArray) {
-        launcher.workspace.pageIndicator.setAreScreensBinding(
-            true,
+        launcher.workspace.pageIndicator.setPauseScroll(
+            /*pause=*/ true,
             launcher.deviceProfile.isTwoPanels
         )
         val firstScreenPosition = 0
diff --git a/src/com/android/launcher3/pageindicators/PageIndicator.java b/src/com/android/launcher3/pageindicators/PageIndicator.java
index 30156c8..0640bf3 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicator.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicator.java
@@ -27,10 +27,12 @@
     void setMarkersCount(int numMarkers);
 
     /**
-     * Sets flag to indicate when the screens are in the process of binding so that we don't animate
-     * during that period.
+     * Sets a flag indicating whether to pause scroll.
+     * <p>Should be set to {@code true} while the screen is binding or new data is being applied,
+     * and to {@code false} once done. This prevents animation conflicts due to scrolling during
+     * those periods.</p>
      */
-    default void setAreScreensBinding(boolean areScreensBinding, boolean isTwoPanels) {
+    default void setPauseScroll(boolean pause, boolean isTwoPanels) {
         // No-op by default
     }
 
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
index 1b5abaa..77effca 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
@@ -130,7 +130,7 @@
      */
     private float mCurrentPosition;
     private float mFinalPosition;
-    private boolean mAreScreensBinding;
+    private boolean mIsScrollPaused;
     private boolean mIsTwoPanels;
     private ObjectAnimator mAnimator;
     private @Nullable ObjectAnimator mAlphaAnimator;
@@ -172,7 +172,7 @@
         }
 
         // Skip scroll update during binding. We will update it when binding completes.
-        if (mAreScreensBinding) {
+        if (mIsScrollPaused) {
             return;
         }
 
@@ -376,15 +376,15 @@
     }
 
     @Override
-    public void setAreScreensBinding(boolean areScreensBinding, boolean isTwoPanels) {
+    public void setPauseScroll(boolean pause, boolean isTwoPanels) {
         mIsTwoPanels = isTwoPanels;
 
         // Reapply correct current position which was skipped during setScroll.
-        if (mAreScreensBinding && !areScreensBinding) {
+        if (mIsScrollPaused && !pause) {
             CURRENT_POSITION.set(this, (float) mActivePage);
         }
 
-        mAreScreensBinding = areScreensBinding;
+        mIsScrollPaused = pause;
     }
 
     @Override
diff --git a/src/com/android/launcher3/widget/picker/WidgetRecommendationsView.java b/src/com/android/launcher3/widget/picker/WidgetRecommendationsView.java
index 738d74e..426a3ae 100644
--- a/src/com/android/launcher3/widget/picker/WidgetRecommendationsView.java
+++ b/src/com/android/launcher3/widget/picker/WidgetRecommendationsView.java
@@ -29,7 +29,6 @@
 import androidx.annotation.Px;
 
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Launcher;
 import com.android.launcher3.PagedView;
 import com.android.launcher3.R;
 import com.android.launcher3.model.WidgetItem;
@@ -88,6 +87,7 @@
      * Displays all the provided recommendations in a single table if they fit.
      *
      * @param recommendedWidgets list of widgets to be displayed in recommendation section.
+     * @param deviceProfile      the current {@link DeviceProfile}
      * @param availableHeight    height in px that can be used to display the recommendations;
      *                           recommendations that don't fit in this height won't be shown
      * @param availableWidth     width in px that the recommendations should display in
@@ -96,12 +96,13 @@
      * @return {@code false} if no recommendations could fit in the available space.
      */
     public boolean setRecommendations(
-            List<WidgetItem> recommendedWidgets, final @Px float availableHeight,
-            final @Px int availableWidth, final @Px int cellPadding) {
+            List<WidgetItem> recommendedWidgets, DeviceProfile deviceProfile,
+            final @Px float availableHeight, final @Px int availableWidth,
+            final @Px int cellPadding) {
         this.mAvailableHeight = availableHeight;
         removeAllViews();
 
-        maybeDisplayInTable(recommendedWidgets, availableWidth, cellPadding);
+        maybeDisplayInTable(recommendedWidgets, deviceProfile, availableWidth, cellPadding);
         updateTitleAndIndicator();
         return getChildCount() > 0;
     }
@@ -111,6 +112,7 @@
      * <p>In case of a single category, no title is displayed for it.</p>
      *
      * @param recommendations a map of widget items per recommendation category
+     * @param deviceProfile   the current {@link DeviceProfile}
      * @param availableHeight height in px that can be used to display the recommendations;
      *                        recommendations that don't fit in this height won't be shown
      * @param availableWidth  width in px that the recommendations should display in
@@ -120,10 +122,12 @@
      */
     public boolean setRecommendations(
             Map<WidgetRecommendationCategory, List<WidgetItem>> recommendations,
+            DeviceProfile deviceProfile,
             final @Px float availableHeight, final @Px int availableWidth,
             final @Px int cellPadding) {
         this.mAvailableHeight = availableHeight;
         Context context = getContext();
+        mPageIndicator.setPauseScroll(true, deviceProfile.isTwoPanels);
         removeAllViews();
 
         int displayedCategories = 0;
@@ -133,7 +137,7 @@
                 new TreeMap<>(recommendations).entrySet()) {
             // If none of the recommendations for the category could fit in the mAvailableHeight, we
             // don't want to add that category; and we look for the next one.
-            if (maybeDisplayInTable(entry.getValue(), availableWidth, cellPadding)) {
+            if (maybeDisplayInTable(entry.getValue(), deviceProfile, availableWidth, cellPadding)) {
                 mCategoryTitles.add(
                         context.getResources().getString(entry.getKey().categoryTitleRes));
                 displayedCategories++;
@@ -145,14 +149,21 @@
         }
 
         updateTitleAndIndicator();
+        mPageIndicator.setPauseScroll(false, deviceProfile.isTwoPanels);
         return getChildCount() > 0;
     }
 
     /** Displays the page title and paging indicator if there are multiple pages. */
     private void updateTitleAndIndicator() {
-        int titleAndIndicatorVisibility = getPageCount() > 1 ? View.VISIBLE : View.GONE;
+        boolean showPaginatedView = getPageCount() > 1;
+        int titleAndIndicatorVisibility = showPaginatedView ? View.VISIBLE : View.GONE;
         mRecommendationPageTitle.setVisibility(titleAndIndicatorVisibility);
         mPageIndicator.setVisibility(titleAndIndicatorVisibility);
+        if (showPaginatedView) {
+            mPageIndicator.setActiveMarker(0);
+            setCurrentPage(0);
+            mRecommendationPageTitle.setText(mCategoryTitles.get(0));
+        }
     }
 
     @Override
@@ -218,9 +229,9 @@
      * <p>Returns false if none of the recommendations could fit.</p>
      */
     private boolean maybeDisplayInTable(List<WidgetItem> recommendedWidgets,
+            DeviceProfile deviceProfile,
             final @Px int availableWidth, final @Px int cellPadding) {
         Context context = getContext();
-        DeviceProfile deviceProfile = Launcher.getLauncher(context).getDeviceProfile();
         LayoutInflater inflater = LayoutInflater.from(context);
 
         List<ArrayList<WidgetItem>> rows = groupWidgetItemsUsingRowPxWithoutReordering(
@@ -239,7 +250,7 @@
         recommendationsTable.setWidgetCellLongClickListener(mWidgetCellOnLongClickListener);
 
         boolean displayedAtLeastOne = recommendationsTable.setRecommendedWidgets(rows,
-                mAvailableHeight);
+                deviceProfile, mAvailableHeight);
         if (displayedAtLeastOne) {
             addView(recommendationsTable);
         }
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 237078e..f5742af 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -590,6 +590,7 @@
         if (enableCategorizedWidgetSuggestions()) {
             mHasRecommendedWidgets = mWidgetRecommendationsView.setRecommendations(
                     mActivityContext.getPopupDataProvider().getCategorizedRecommendedWidgets(),
+                    mDeviceProfile,
                     /* availableHeight= */ getMaxAvailableHeightForRecommendations(),
                     /* availableWidth= */ mMaxSpanPerRow,
                     /* cellPadding= */ mWidgetCellHorizontalPadding
@@ -597,6 +598,7 @@
         } else {
             mHasRecommendedWidgets = mWidgetRecommendationsView.setRecommendations(
                     mActivityContext.getPopupDataProvider().getRecommendedWidgets(),
+                    mDeviceProfile,
                     /* availableHeight= */ getMaxAvailableHeightForRecommendations(),
                     /* availableWidth= */ mMaxSpanPerRow,
                     /* cellPadding= */ mWidgetCellHorizontalPadding
diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java b/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
index ce1f4e0..47750a5 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
@@ -32,7 +32,6 @@
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.widget.WidgetCell;
@@ -89,9 +88,11 @@
      * <p>Returns {@code false} if none of the widgets could fit</p>
      */
     public boolean setRecommendedWidgets(List<ArrayList<WidgetItem>> recommendedWidgets,
+            DeviceProfile deviceProfile,
             float recommendationTableMaxHeight) {
         mRecommendationTableMaxHeight = recommendationTableMaxHeight;
         RecommendationTableData data = fitRecommendedWidgetsToTableSpace(/* previewScale= */ 1f,
+                deviceProfile,
                 recommendedWidgets);
         bindData(data);
         return !data.mRecommendationTable.isEmpty();
@@ -144,6 +145,7 @@
 
     private RecommendationTableData fitRecommendedWidgetsToTableSpace(
             float previewScale,
+            DeviceProfile deviceProfile,
             List<ArrayList<WidgetItem>> recommendedWidgetsInTable) {
         if (previewScale < MAX_DOWN_SCALE_RATIO) {
             Log.w(TAG, "Hide recommended widgets. Can't down scale previews to " + previewScale);
@@ -151,7 +153,6 @@
         }
         // A naive estimation of the widgets recommendation table height without inflation.
         float totalHeight = mWidgetsRecommendationTableVerticalPadding;
-        DeviceProfile deviceProfile = Launcher.getLauncher(getContext()).getDeviceProfile();
         for (int i = 0; i < recommendedWidgetsInTable.size(); i++) {
             List<WidgetItem> widgetItems = recommendedWidgetsInTable.get(i);
             float rowHeight = 0;
@@ -175,12 +176,14 @@
             // num of row by 1 to see if it fits.
             return fitRecommendedWidgetsToTableSpace(
                     previewScale,
+                    deviceProfile,
                     recommendedWidgetsInTable.subList(/* fromIndex= */0,
                             /* toIndex= */recommendedWidgetsInTable.size() - 1));
         }
 
         float nextPreviewScale = previewScale * DOWN_SCALE_RATIO;
-        return fitRecommendedWidgetsToTableSpace(nextPreviewScale, recommendedWidgetsInTable);
+        return fitRecommendedWidgetsToTableSpace(nextPreviewScale, deviceProfile,
+                recommendedWidgetsInTable);
     }
 
     /** Data class for the widgets recommendation table and widgets preview scaling. */