Merge "Animate recommended widgets vertical transition when reset widgets picker scroll position" into sc-dev
diff --git a/src/com/android/launcher3/widget/picker/SearchAndRecommendationsScrollController.java b/src/com/android/launcher3/widget/picker/SearchAndRecommendationsScrollController.java
index 34346ab..6781824 100644
--- a/src/com/android/launcher3/widget/picker/SearchAndRecommendationsScrollController.java
+++ b/src/com/android/launcher3/widget/picker/SearchAndRecommendationsScrollController.java
@@ -15,6 +15,7 @@
  */
 package com.android.launcher3.widget.picker;
 
+import android.animation.ValueAnimator;
 import android.graphics.Point;
 import android.view.MotionEvent;
 import android.view.View;
@@ -32,13 +33,14 @@
  * vertical displacement upon scrolling.
  */
 final class SearchAndRecommendationsScrollController implements
-        RecyclerViewFastScroller.OnFastScrollChangeListener {
+        RecyclerViewFastScroller.OnFastScrollChangeListener, ValueAnimator.AnimatorUpdateListener {
     private final boolean mHasWorkProfile;
     private final SearchAndRecommendationViewHolder mViewHolder;
     private final View mSearchAndRecommendationViewParent;
     private final WidgetsRecyclerView mPrimaryRecyclerView;
     private final WidgetsRecyclerView mSearchRecyclerView;
     private final int mTabsHeight;
+    private final ValueAnimator mAnimator = ValueAnimator.ofInt(0, 0);
     private final Point mTempOffset = new Point();
 
     // The following are only non null if mHasWorkProfile is true.
@@ -47,8 +49,9 @@
     @Nullable private final PersonalWorkPagedView mPrimaryWorkViewPager;
 
     private WidgetsRecyclerView mCurrentRecyclerView;
+    private int mCurrentRecyclerViewScrollY = 0;
 
-    private OnContentChangeListener mOnContentChangeListener = () -> applyVerticalTransition();
+    private OnContentChangeListener mOnContentChangeListener = () -> onScrollChanged();
 
     /**
      * The vertical distance, in pixels, until the search is pinned at the top of the screen when
@@ -89,23 +92,25 @@
         mPrimaryWorkTabsView = personalWorkTabsView;
         mPrimaryWorkViewPager = primaryWorkViewPager;
         mTabsHeight = tabsHeight;
-        setCurrentRecyclerView(mPrimaryRecyclerView);
+        setCurrentRecyclerView(mPrimaryRecyclerView, /* animateReset= */ false);
+    }
+
+    public void setCurrentRecyclerView(WidgetsRecyclerView currentRecyclerView) {
+        setCurrentRecyclerView(currentRecyclerView, /* animateReset= */ true);
     }
 
     /** Sets the current active {@link WidgetsRecyclerView}. */
-    public void setCurrentRecyclerView(WidgetsRecyclerView currentRecyclerView) {
+    private void setCurrentRecyclerView(WidgetsRecyclerView currentRecyclerView,
+            boolean animateReset) {
+        if (mCurrentRecyclerView == currentRecyclerView) {
+            return;
+        }
         if (mCurrentRecyclerView != null) {
             mCurrentRecyclerView.setOnContentChangeListener(null);
         }
         mCurrentRecyclerView = currentRecyclerView;
         mCurrentRecyclerView.setOnContentChangeListener(mOnContentChangeListener);
-        mViewHolder.mHeaderTitle.setTranslationY(0);
-        mViewHolder.mRecommendedWidgetsTable.setTranslationY(0);
-        mViewHolder.mSearchBarContainer.setTranslationY(0);
-
-        if (mHasWorkProfile) {
-            mPrimaryWorkTabsView.setTranslationY(0);
-        }
+        reset(animateReset);
     }
 
     /**
@@ -222,6 +227,12 @@
 
     @Override
     public void onScrollChanged() {
+        int recyclerViewYOffset = mCurrentRecyclerView.getCurrentScrollY();
+        if (recyclerViewYOffset < 0) return;
+        mCurrentRecyclerViewScrollY = recyclerViewYOffset;
+        if (mAnimator.isStarted()) {
+            mAnimator.cancel();
+        }
         applyVerticalTransition();
     }
 
@@ -230,34 +241,43 @@
      * views (e.g. recycler views, tabs) upon scrolling / content changes in the recycler view.
      */
     private void applyVerticalTransition() {
-        // Always use the recycler view offset because fast scroller offset has a different scale.
-        int recyclerViewYOffset = mCurrentRecyclerView.getCurrentScrollY();
-        if (recyclerViewYOffset < 0) return;
-
         if (mCollapsibleHeightForRecommendation > 0) {
-            int yDisplacement = Math.max(-recyclerViewYOffset,
+            int yDisplacement = Math.max(-mCurrentRecyclerViewScrollY,
                     -mCollapsibleHeightForRecommendation);
             mViewHolder.mHeaderTitle.setTranslationY(yDisplacement);
             mViewHolder.mRecommendedWidgetsTable.setTranslationY(yDisplacement);
         }
 
         if (mCollapsibleHeightForSearch > 0) {
-            int searchYDisplacement = Math.max(-recyclerViewYOffset, -mCollapsibleHeightForSearch);
+            int searchYDisplacement = Math.max(-mCurrentRecyclerViewScrollY,
+                    -mCollapsibleHeightForSearch);
             mViewHolder.mSearchBarContainer.setTranslationY(searchYDisplacement);
         }
 
         if (mHasWorkProfile && mCollapsibleHeightForTabs > 0) {
-            int yDisplacementForTabs = Math.max(-recyclerViewYOffset, -mCollapsibleHeightForTabs);
+            int yDisplacementForTabs = Math.max(-mCurrentRecyclerViewScrollY,
+                    -mCollapsibleHeightForTabs);
             mPrimaryWorkTabsView.setTranslationY(yDisplacementForTabs);
         }
     }
 
     /** Resets any previous view translation. */
-    public void reset() {
-        mViewHolder.mHeaderTitle.setTranslationY(0);
-        mViewHolder.mSearchBarContainer.setTranslationY(0);
-        if (mHasWorkProfile) {
-            mPrimaryWorkTabsView.setTranslationY(0);
+    public void reset(boolean animate) {
+        if (mCurrentRecyclerViewScrollY == 0) {
+            return;
+        }
+        if (mAnimator.isStarted()) {
+            mAnimator.cancel();
+        }
+
+        if (animate) {
+            mAnimator.setIntValues(mCurrentRecyclerViewScrollY, 0);
+            mAnimator.addUpdateListener(this);
+            mAnimator.setDuration(300);
+            mAnimator.start();
+        } else {
+            mCurrentRecyclerViewScrollY = 0;
+            applyVerticalTransition();
         }
     }
 
@@ -308,6 +328,12 @@
                 + marginLayoutParams.topMargin;
     }
 
+    @Override
+    public void onAnimationUpdate(ValueAnimator animation) {
+        mCurrentRecyclerViewScrollY = (Integer) animation.getAnimatedValue();
+        applyVerticalTransition();
+    }
+
     /**
      * A listener to be notified when there is a content change in the recycler view that may affect
      * the relative position of the search and recommendation container.
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index bfdddeb..801ecc2 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -254,7 +254,7 @@
             mAdapters.get(AdapterHolder.WORK).mWidgetsRecyclerView.scrollToTop();
         }
         mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView.scrollToTop();
-        mSearchAndRecommendationsScrollController.reset();
+        mSearchAndRecommendationsScrollController.reset(/* animate= */ true);
     }
 
     @VisibleForTesting