Merge "Tweak ordering of first match search" into sc-dev
diff --git a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java
index 9077675..117b8e6 100644
--- a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java
+++ b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java
@@ -27,6 +27,7 @@
 import android.graphics.Matrix;
 import android.net.Uri;
 import android.os.SystemClock;
+import android.os.UserManager;
 import android.provider.Settings;
 import android.text.TextUtils;
 
@@ -96,7 +97,10 @@
             }
 
             getActionsView().updateDisabledFlags(DISABLED_ROTATED, rotated);
-            boolean isAllowedByPolicy = mThumbnailView.isRealSnapshot();
+            // Disable Overview Actions for Work Profile apps
+            boolean isManagedProfileTask =
+                    UserManager.get(mApplicationContext).isManagedProfile(task.key.userId);
+            boolean isAllowedByPolicy = mThumbnailView.isRealSnapshot() && !isManagedProfileTask;
             getActionsView().setCallbacks(new OverlayUICallbacksGoImpl(isAllowedByPolicy, task));
             mTaskPackageName = task.key.getPackageName();
 
@@ -127,8 +131,7 @@
         /**
          * Creates and sends an Intent corresponding to the button that was clicked
          */
-        @VisibleForTesting
-        public void sendNIUIntent(String actionType) {
+        private void sendNIUIntent(String actionType) {
             Intent intent = createNIUIntent(actionType);
             // Only add and send the image if the appropriate permissions are held
             if (mAssistPermissionsEnabled) {
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
index 59d0afa..e608885 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
@@ -217,17 +217,11 @@
         }
 
         if (supportsBlur) {
-            final int blur;
-            if (mLauncher.isInState(LauncherState.ALL_APPS) && mDepth == 1) {
-                // All apps has a solid background. We don't need to draw blurs after it's fully
-                // visible. This will take us out of GPU composition, saving battery and increasing
-                // performance.
-                blur = 0;
-            } else {
-                blur = (int) (mDepth * mMaxBlurRadius);
-            }
+            boolean isOpaque = mLauncher.getScrimView().isFullyOpaque();
+            int blur = isOpaque ? 0 : (int) (mDepth * mMaxBlurRadius);
             new TransactionCompat()
                     .setBackgroundBlurRadius(mSurface, blur)
+                    .setOpaque(mSurface, isOpaque)
                     .apply();
         }
     }
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index e0f430d..005e9b5 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -750,6 +750,7 @@
         setIsLikelyToStartNewTask(isLikelyToStartNewTask, false /* animate */);
         mStateCallback.setStateOnUiThread(STATE_GESTURE_STARTED);
         mGestureStarted = true;
+        SystemUiProxy.INSTANCE.get(mContext).notifySwipeUpGestureStarted();
     }
 
     /**
diff --git a/quickstep/src/com/android/quickstep/RotationTouchHelper.java b/quickstep/src/com/android/quickstep/RotationTouchHelper.java
index 070d725..66929d0 100644
--- a/quickstep/src/com/android/quickstep/RotationTouchHelper.java
+++ b/quickstep/src/com/android/quickstep/RotationTouchHelper.java
@@ -369,7 +369,7 @@
 
     private void notifySysuiOfCurrentRotation(int rotation) {
         UI_HELPER_EXECUTOR.execute(() -> SystemUiProxy.INSTANCE.get(mContext)
-                .onQuickSwitchToNewTask(rotation));
+                .notifyPrioritizedRotation(rotation));
     }
 
     /**
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index acf9992..7ef6a4a 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -341,6 +341,17 @@
         }
     }
 
+    @Override
+    public void notifySwipeUpGestureStarted() {
+        if (mSystemUiProxy != null) {
+            try {
+                mSystemUiProxy.notifySwipeUpGestureStarted();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed call notifySwipeUpGestureStarted", e);
+            }
+        }
+    }
+
     /**
      * Notifies that swipe-to-home action is finished.
      */
@@ -350,18 +361,18 @@
             try {
                 mSystemUiProxy.notifySwipeToHomeFinished();
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed call setPinnedStackAnimationType", e);
+                Log.w(TAG, "Failed call notifySwipeToHomeFinished", e);
             }
         }
     }
 
     @Override
-    public void onQuickSwitchToNewTask(int rotation) {
+    public void notifyPrioritizedRotation(int rotation) {
         if (mSystemUiProxy != null) {
             try {
-                mSystemUiProxy.onQuickSwitchToNewTask(rotation);
+                mSystemUiProxy.notifyPrioritizedRotation(rotation);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed call onQuickSwitchToNewTask with arg: " + rotation, e);
+                Log.w(TAG, "Failed call notifyPrioritizedRotation with arg: " + rotation, e);
             }
         }
     }
diff --git a/res/drawable-v28/widgets_bottom_sheet_background.xml b/res/drawable-v28/widgets_bottom_sheet_background.xml
new file mode 100644
index 0000000..c3009c3
--- /dev/null
+++ b/res/drawable-v28/widgets_bottom_sheet_background.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2021 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <solid android:color="@color/widgets_picker_surface" />
+    <corners
+        android:topLeftRadius="?android:attr/dialogCornerRadius"
+        android:topRightRadius="?android:attr/dialogCornerRadius"
+        android:bottomLeftRadius="0dp"
+        android:bottomRightRadius="0dp"
+        />
+</shape>
\ No newline at end of file
diff --git a/res/drawable/widgets_bottom_sheet_background.xml b/res/drawable/widgets_bottom_sheet_background.xml
index faa414c..2460767 100644
--- a/res/drawable/widgets_bottom_sheet_background.xml
+++ b/res/drawable/widgets_bottom_sheet_background.xml
@@ -18,8 +18,8 @@
     android:shape="rectangle">
     <solid android:color="@color/widgets_picker_surface" />
     <corners
-        android:topLeftRadius="@dimen/bg_round_rect_radius"
-        android:topRightRadius="@dimen/bg_round_rect_radius"
+        android:topLeftRadius="@dimen/default_dialog_corner_radius"
+        android:topRightRadius="@dimen/default_dialog_corner_radius"
         android:bottomLeftRadius="0dp"
         android:bottomRightRadius="0dp"
         />
diff --git a/res/layout/widget_cell_content.xml b/res/layout/widget_cell_content.xml
index 0f6fc6c..b27b505 100644
--- a/res/layout/widget_cell_content.xml
+++ b/res/layout/widget_cell_content.xml
@@ -33,14 +33,6 @@
             android:layout_height="match_parent"
             android:importantForAccessibility="no"
             android:layout_gravity="fill"/>
-
-        <ImageView
-            android:id="@+id/widget_badge"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:importantForAccessibility="no"
-            android:layout_gravity="end|bottom"
-            android:layout_margin="@dimen/profile_badge_margin"/>
     </com.android.launcher3.widget.WidgetCellPreview>
 
     <!-- The name of the widget. -->
diff --git a/robolectric_tests/src/com/android/launcher3/testing/TestActivity.java b/robolectric_tests/src/com/android/launcher3/testing/TestActivity.java
index dbf4b3e..17d0ac1 100644
--- a/robolectric_tests/src/com/android/launcher3/testing/TestActivity.java
+++ b/robolectric_tests/src/com/android/launcher3/testing/TestActivity.java
@@ -27,7 +27,12 @@
 
     @Override
     public BaseDragLayer getDragLayer() {
-        return null;
+        return new BaseDragLayer(this, /* attrs= */ null, /* alphaChannelCount= */ 1) {
+            @Override
+            public void recreateControllers() {
+                // Do nothing.
+            }
+        };
     }
 
     @Override
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarControllerTest.java b/robolectric_tests/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarControllerTest.java
index 4e6f17c..a057a84 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarControllerTest.java
+++ b/robolectric_tests/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarControllerTest.java
@@ -19,24 +19,27 @@
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 
-import android.content.Context;
 import android.view.View;
 import android.widget.ImageButton;
 
 import com.android.launcher3.ExtendedEditText;
 import com.android.launcher3.search.SearchAlgorithm;
+import com.android.launcher3.testing.TestActivity;
 import com.android.launcher3.widget.model.WidgetsListBaseEntry;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
+import org.robolectric.android.controller.ActivityController;
 
 import java.util.ArrayList;
 
@@ -44,7 +47,9 @@
 public class WidgetsSearchBarControllerTest {
 
     private WidgetsSearchBarController mController;
-    private Context mContext;
+    // TODO: Replace ActivityController with ActivityScenario, which is the recommended way for
+    // activity testing.
+    private ActivityController<TestActivity> mActivityController;
     private ExtendedEditText mEditText;
     private ImageButton mCancelButton;
     @Mock
@@ -55,13 +60,20 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
-        mEditText = new ExtendedEditText(mContext);
-        mCancelButton = new ImageButton(mContext);
+        mActivityController = Robolectric.buildActivity(TestActivity.class);
+        TestActivity testActivity = mActivityController.setup().get();
+
+        mEditText = new ExtendedEditText(testActivity);
+        mCancelButton = new ImageButton(testActivity);
         mController = new WidgetsSearchBarController(
                 mSearchAlgorithm, mEditText, mCancelButton, mSearchModeListener);
     }
 
+    @After
+    public void tearDown() {
+        mActivityController.destroy();
+    }
+
     @Test
     public void onSearchResult_shouldInformSearchModeListener() {
         ArrayList<WidgetsListBaseEntry> entries = new ArrayList<>();
@@ -119,14 +131,18 @@
     public void cancelSearch_shouldInformSearchModeListenerToClearResultsAndExitSearch() {
         mCancelButton.performClick();
 
-        verify(mSearchModeListener).exitSearchMode();
+        // 1 time explicitly from the cancel button on click listener.
+        // Another from the setText("") the cancel button on click listener causing afterTextChange.
+        verify(mSearchModeListener, times(2)).exitSearchMode();
     }
 
     @Test
     public void cancelSearch_shouldCancelSearch() {
         mCancelButton.performClick();
 
-        verify(mSearchAlgorithm).cancel(true);
+        // 1 time explicitly from the cancel button on click listener.
+        // Another from the setText("") the cancel button on click listener causing afterTextChange.
+        verify(mSearchAlgorithm, times(2)).cancel(true);
         verifyNoMoreInteractions(mSearchAlgorithm);
     }
 
diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java
index 75d25d7..8b7a750 100644
--- a/src/com/android/launcher3/WidgetPreviewLoader.java
+++ b/src/com/android/launcher3/WidgetPreviewLoader.java
@@ -21,9 +21,7 @@
 import android.graphics.Paint;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffXfermode;
-import android.graphics.Rect;
 import android.graphics.RectF;
-import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.AsyncTask;
 import android.os.CancellationSignal;
@@ -35,9 +33,7 @@
 import android.util.Pair;
 
 import androidx.annotation.Nullable;
-import androidx.annotation.UiThread;
 
-import com.android.launcher3.icons.FastBitmapDrawable;
 import com.android.launcher3.icons.GraphicsUtils;
 import com.android.launcher3.icons.IconCache;
 import com.android.launcher3.icons.LauncherIcons;
@@ -94,51 +90,6 @@
     }
 
     /**
-     * Returns a drawable that can be used as a badge for the user or null.
-     */
-    @UiThread
-    public Drawable getBadgeForUser(UserHandle user, int badgeSize) {
-        if (mMyUser.equals(user)) {
-            return null;
-        }
-
-        Bitmap badgeBitmap = getUserBadge(user, badgeSize);
-        FastBitmapDrawable d = new FastBitmapDrawable(badgeBitmap);
-        d.setFilterBitmap(true);
-        d.setBounds(0, 0, badgeBitmap.getWidth(), badgeBitmap.getHeight());
-        return d;
-    }
-
-    private Bitmap getUserBadge(UserHandle user, int badgeSize) {
-        synchronized (mUserBadges) {
-            Bitmap badgeBitmap = mUserBadges.get(user);
-            if (badgeBitmap != null) {
-                return badgeBitmap;
-            }
-
-            final Resources res = mContext.getResources();
-            badgeBitmap = Bitmap.createBitmap(badgeSize, badgeSize, Bitmap.Config.ARGB_8888);
-
-            Drawable drawable = mContext.getPackageManager().getUserBadgedDrawableForDensity(
-                    new BitmapDrawable(res, badgeBitmap), user,
-                    new Rect(0, 0, badgeSize, badgeSize),
-                    0);
-            if (drawable instanceof BitmapDrawable) {
-                badgeBitmap = ((BitmapDrawable) drawable).getBitmap();
-            } else {
-                badgeBitmap.eraseColor(Color.TRANSPARENT);
-                Canvas c = new Canvas(badgeBitmap);
-                drawable.setBounds(0, 0, badgeSize, badgeSize);
-                drawable.draw(c);
-                c.setBitmap(null);
-            }
-
-            mUserBadges.put(user, badgeBitmap);
-            return badgeBitmap;
-        }
-    }
-
-    /**
      * Generates the widget preview on {@link AsyncTask#THREAD_POOL_EXECUTOR}. Must be
      * called on UI thread
      *
diff --git a/src/com/android/launcher3/views/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java
index 0ba94ab..fb1485b 100644
--- a/src/com/android/launcher3/views/ScrimView.java
+++ b/src/com/android/launcher3/views/ScrimView.java
@@ -19,6 +19,7 @@
 
 import android.content.Context;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
 import android.util.AttributeSet;
@@ -39,6 +40,8 @@
     private SystemUiController mSystemUiController;
 
     private ScrimDrawingController mDrawingController;
+    private int mBackgroundColor;
+    private boolean mIsVisible = true;
 
     public ScrimView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -62,11 +65,22 @@
 
     @Override
     public void setBackgroundColor(int color) {
+        mBackgroundColor = color;
         updateSysUiColors();
         super.setBackgroundColor(color);
     }
 
     @Override
+    public void onVisibilityAggregated(boolean isVisible) {
+        super.onVisibilityAggregated(isVisible);
+        mIsVisible = isVisible;
+    }
+
+    public boolean isFullyOpaque() {
+        return mIsVisible && getAlpha() == 1 && Color.alpha(mBackgroundColor) == 255;
+    }
+
+    @Override
     protected void onDraw(Canvas canvas) {
         super.onDraw(canvas);
         if (mDrawingController != null) {
diff --git a/src/com/android/launcher3/views/TopRoundedCornerView.java b/src/com/android/launcher3/views/TopRoundedCornerView.java
index 7888b08..5519df1 100644
--- a/src/com/android/launcher3/views/TopRoundedCornerView.java
+++ b/src/com/android/launcher3/views/TopRoundedCornerView.java
@@ -21,7 +21,6 @@
 import android.graphics.Path;
 import android.graphics.RectF;
 import android.util.AttributeSet;
-import android.widget.FrameLayout;
 
 import com.android.launcher3.R;
 import com.android.launcher3.util.Themes;
@@ -41,7 +40,7 @@
     public TopRoundedCornerView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
 
-        int radius = getResources().getDimensionPixelSize(R.dimen.bg_round_rect_radius);
+        float radius = Themes.getDialogCornerRadius(context);
         mRadii = new float[] {radius, radius, radius, radius, 0, 0, 0, 0};
 
         mNavBarScrimPaint = new Paint();
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index 3fcd3f7..f7993dc 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -33,7 +33,6 @@
 import android.view.ViewPropertyAnimator;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.FrameLayout;
-import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.RemoteViews;
 import android.widget.TextView;
@@ -45,7 +44,6 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
 import com.android.launcher3.WidgetPreviewLoader;
-import com.android.launcher3.icons.BaseIconFactory;
 import com.android.launcher3.icons.FastBitmapDrawable;
 import com.android.launcher3.icons.RoundDrawableWrapper;
 import com.android.launcher3.model.WidgetItem;
@@ -80,7 +78,6 @@
 
     private FrameLayout mWidgetImageContainer;
     private WidgetImageView mWidgetImage;
-    private ImageView mWidgetBadge;
     private TextView mWidgetName;
     private TextView mWidgetDims;
     private TextView mWidgetDescription;
@@ -136,7 +133,6 @@
 
         mWidgetImageContainer = findViewById(R.id.widget_preview_container);
         mWidgetImage = findViewById(R.id.widget_preview);
-        mWidgetBadge = findViewById(R.id.widget_badge);
         mWidgetName = findViewById(R.id.widget_name);
         mWidgetDims = findViewById(R.id.widget_dims);
         mWidgetDescription = findViewById(R.id.widget_description);
@@ -161,7 +157,6 @@
         mWidgetImage.animate().cancel();
         mWidgetImage.setDrawable(null);
         mWidgetImage.setVisibility(View.VISIBLE);
-        mWidgetBadge.setImageDrawable(null);
         mWidgetName.setText(null);
         mWidgetDims.setText(null);
         mWidgetDescription.setText(null);
@@ -294,15 +289,6 @@
                 mAppWidgetHostViewPreview = null;
             }
         }
-        Drawable badge = mWidgetPreviewLoader.getBadgeForUser(mItem.user,
-                BaseIconFactory.getBadgeSizeForIconSize(
-                        mActivity.getDeviceProfile().allAppsIconSizePx));
-        if (badge == null) {
-            mWidgetBadge.setVisibility(View.GONE);
-        } else {
-            mWidgetBadge.setVisibility(View.VISIBLE);
-            mWidgetBadge.setImageDrawable(badge);
-        }
         if (mAnimatePreview) {
             mWidgetImageContainer.setAlpha(0f);
             ViewPropertyAnimator anim = mWidgetImageContainer.animate();
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 e44acc3..801ecc2 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -130,6 +130,7 @@
     private final int mTabsHeight;
     private final int mWidgetCellHorizontalPadding;
 
+    @Nullable private WidgetsRecyclerView mCurrentWidgetsRecyclerView;
     @Nullable private PersonalWorkPagedView mViewPager;
     private boolean mIsInSearchMode;
     private int mMaxSpansPerRow = 4;
@@ -222,13 +223,18 @@
 
         updateRecyclerViewVisibility(currentAdapterHolder);
         attachScrollbarToRecyclerView(currentRecyclerView);
-        resetExpandedHeaders();
     }
 
     private void attachScrollbarToRecyclerView(WidgetsRecyclerView recyclerView) {
         recyclerView.bindFastScrollbar();
-        mSearchAndRecommendationsScrollController.setCurrentRecyclerView(recyclerView);
-        reset();
+        if (mCurrentWidgetsRecyclerView != recyclerView) {
+            // Only reset the scroll position & expanded apps if the currently shown recycler view
+            // has been updated.
+            reset();
+            resetExpandedHeaders();
+            mCurrentWidgetsRecyclerView = recyclerView;
+            mSearchAndRecommendationsScrollController.setCurrentRecyclerView(recyclerView);
+        }
     }
 
     private void updateRecyclerViewVisibility(AdapterHolder adapterHolder) {
@@ -248,7 +254,7 @@
             mAdapters.get(AdapterHolder.WORK).mWidgetsRecyclerView.scrollToTop();
         }
         mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView.scrollToTop();
-        mSearchAndRecommendationsScrollController.reset();
+        mSearchAndRecommendationsScrollController.reset(/* animate= */ true);
     }
 
     @VisibleForTesting
@@ -413,7 +419,6 @@
         if (mIsInSearchMode) return;
         setViewVisibilityBasedOnSearch(/*isInSearchMode= */ true);
         attachScrollbarToRecyclerView(mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView);
-        resetExpandedHeaders();
     }
 
     @Override
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
index 0504e74..8345a0e 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
@@ -33,6 +33,7 @@
 import com.android.launcher3.R;
 import com.android.launcher3.WidgetPreviewLoader;
 import com.android.launcher3.icons.IconCache;
+import com.android.launcher3.model.data.PackageItemInfo;
 import com.android.launcher3.recyclerview.ViewHolderBinder;
 import com.android.launcher3.util.LabelComparator;
 import com.android.launcher3.util.PackageUserKey;
@@ -47,6 +48,7 @@
 import java.util.Arrays;
 import java.util.Comparator;
 import java.util.List;
+import java.util.Map;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
@@ -153,6 +155,9 @@
     public void setWidgets(List<WidgetsListBaseEntry> tempEntries) {
         mAllEntries = tempEntries.stream().sorted(mRowComparator)
                 .collect(Collectors.toList());
+        if (shouldClearVisibleEntries()) {
+            mVisibleEntries.clear();
+        }
         updateVisibleEntries();
     }
 
@@ -272,6 +277,30 @@
         mWidgetsListTableViewHolderBinder.setMaxSpansPerRow(maxHorizontalSpans);
     }
 
+    /**
+     * Returns {@code true} if there is a change in {@link #mAllEntries} that results in an
+     * invalidation of {@link #mVisibleEntries}. e.g. there is change in the device language.
+     */
+    private boolean shouldClearVisibleEntries() {
+        Map<PackageUserKey, PackageItemInfo> packagesInfo =
+                mAllEntries.stream()
+                        .filter(entry -> entry instanceof WidgetsListHeaderEntry)
+                        .map(entry -> entry.mPkgItem)
+                        .collect(Collectors.toMap(
+                                entry -> new PackageUserKey(entry.packageName, entry.user),
+                                entry -> entry));
+        for (WidgetsListBaseEntry visibleEntry: mVisibleEntries) {
+            PackageUserKey key = new PackageUserKey(visibleEntry.mPkgItem.packageName,
+                    visibleEntry.mPkgItem.user);
+            PackageItemInfo packageItemInfo = packagesInfo.get(key);
+            if (packageItemInfo != null
+                    && !visibleEntry.mPkgItem.title.equals(packageItemInfo.title)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /** Comparator for sorting WidgetListRowEntry based on package title. */
     public static class WidgetListBaseRowEntryComparator implements
             Comparator<WidgetsListBaseEntry> {