Merge "Properly prevent All Apps relayouts by avoiding scrollToPosition" into ub-launcher3-qt-qpr1-dev
diff --git a/go/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/go/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index d0cfcf9..212ce9b 100644
--- a/go/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/go/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -32,6 +32,7 @@
 import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_7;
 import static com.android.launcher3.states.RotationHelper.REQUEST_ROTATE;
 
+import android.content.Context;
 import android.view.View;
 
 import com.android.launcher3.DeviceProfile;
@@ -115,10 +116,10 @@
     }
 
     public static float getDefaultSwipeHeight(Launcher launcher) {
-        return getDefaultSwipeHeight(launcher.getDeviceProfile());
+        return getDefaultSwipeHeight(launcher, launcher.getDeviceProfile());
     }
 
-    public static float getDefaultSwipeHeight(DeviceProfile dp) {
+    public static float getDefaultSwipeHeight(Context context, DeviceProfile dp) {
         return dp.allAppsCellHeightPx - dp.allAppsIconTextSizePx;
     }
 
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java
index 151ceb8..93d4de1 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -32,6 +32,7 @@
 import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
 import static com.android.launcher3.states.RotationHelper.REQUEST_ROTATE;
 
+import android.content.Context;
 import android.graphics.Rect;
 import android.view.View;
 
@@ -159,11 +160,15 @@
     }
 
     public static float getDefaultSwipeHeight(Launcher launcher) {
-        return getDefaultSwipeHeight(launcher.getDeviceProfile());
+        return getDefaultSwipeHeight(launcher, launcher.getDeviceProfile());
     }
 
-    public static float getDefaultSwipeHeight(DeviceProfile dp) {
-        return dp.allAppsCellHeightPx - dp.allAppsIconTextSizePx;
+    public static float getDefaultSwipeHeight(Context context, DeviceProfile dp) {
+        float swipeHeight = dp.allAppsCellHeightPx - dp.allAppsIconTextSizePx;
+        if (SysUINavigationMode.getMode(context) == SysUINavigationMode.Mode.NO_BUTTON) {
+            swipeHeight -= dp.getInsets().bottom;
+        }
+        return swipeHeight;
     }
 
     @Override
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java
index 4eb9df2..da46426 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -24,7 +24,7 @@
         switch (method) {
             case TestProtocol.REQUEST_HOME_TO_OVERVIEW_SWIPE_HEIGHT: {
                 final float swipeHeight =
-                        OverviewState.getDefaultSwipeHeight(mDeviceProfile);
+                        OverviewState.getDefaultSwipeHeight(mContext, mDeviceProfile);
                 response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, (int) swipeHeight);
                 return response;
             }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
index 1069bed..1aa5365 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
@@ -29,6 +29,7 @@
 
 import androidx.annotation.Nullable;
 
+import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.CellLayout;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
@@ -40,7 +41,9 @@
 import com.android.launcher3.anim.AnimatorSetBuilder;
 import com.android.launcher3.anim.PropertySetter;
 import com.android.launcher3.anim.SpringObjectAnimator;
+import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.graphics.OverviewScrim;
+import com.android.launcher3.views.IconLabelDotView;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -62,7 +65,9 @@
 
     private final float mVelocity;
     private final float mSpringTransY;
-    private final View mViewToIgnore;
+
+    // The original view of the {@link FloatingIconView}.
+    private final View mOriginalView;
 
     private final List<Animator> mAnimators = new ArrayList<>();
 
@@ -72,9 +77,7 @@
     public StaggeredWorkspaceAnim(Launcher launcher, @Nullable View floatingViewOriginalView,
             float velocity) {
         mVelocity = velocity;
-        // We ignore this view since it's visibility and position is controlled by
-        // the FloatingIconView.
-        mViewToIgnore = floatingViewOriginalView;
+        mOriginalView = floatingViewOriginalView;
 
         // Scale the translationY based on the initial velocity to better sync the workspace items
         // with the floating view.
@@ -86,16 +89,21 @@
         Workspace workspace = launcher.getWorkspace();
         CellLayout cellLayout = (CellLayout) workspace.getChildAt(workspace.getCurrentPage());
         ShortcutAndWidgetContainer currentPage = cellLayout.getShortcutsAndWidgets();
+        ViewGroup hotseat = launcher.getHotseat();
 
         boolean workspaceClipChildren = workspace.getClipChildren();
         boolean workspaceClipToPadding = workspace.getClipToPadding();
         boolean cellLayoutClipChildren = cellLayout.getClipChildren();
         boolean cellLayoutClipToPadding = cellLayout.getClipToPadding();
+        boolean hotseatClipChildren = hotseat.getClipChildren();
+        boolean hotseatClipToPadding = hotseat.getClipToPadding();
 
         workspace.setClipChildren(false);
         workspace.setClipToPadding(false);
         cellLayout.setClipChildren(false);
         cellLayout.setClipToPadding(false);
+        hotseat.setClipChildren(false);
+        hotseat.setClipToPadding(false);
 
         // Hotseat and QSB takes up two additional rows.
         int totalRows = grid.inv.numRows + (grid.isVerticalBarLayout() ? 0 : 2);
@@ -108,16 +116,18 @@
         }
 
         // Set up springs for the hotseat and qsb.
+        ViewGroup hotseatChild = (ViewGroup) hotseat.getChildAt(0);
         if (grid.isVerticalBarLayout()) {
-            ViewGroup hotseat = (ViewGroup) launcher.getHotseat().getChildAt(0);
-            for (int i = hotseat.getChildCount() - 1; i >= 0; i--) {
-                View child = hotseat.getChildAt(i);
+            for (int i = hotseatChild.getChildCount() - 1; i >= 0; i--) {
+                View child = hotseatChild.getChildAt(i);
                 CellLayout.LayoutParams lp = ((CellLayout.LayoutParams) child.getLayoutParams());
                 addStaggeredAnimationForView(child, lp.cellY + 1, totalRows);
             }
         } else {
-            View hotseat = launcher.getHotseat().getChildAt(0);
-            addStaggeredAnimationForView(hotseat, grid.inv.numRows + 1, totalRows);
+            for (int i = hotseatChild.getChildCount() - 1; i >= 0; i--) {
+                View child = hotseatChild.getChildAt(i);
+                addStaggeredAnimationForView(child, grid.inv.numRows + 1, totalRows);
+            }
 
             View qsb = launcher.findViewById(R.id.search_container_all_apps);
             addStaggeredAnimationForView(qsb, grid.inv.numRows + 2, totalRows);
@@ -140,6 +150,8 @@
                 workspace.setClipToPadding(workspaceClipToPadding);
                 cellLayout.setClipChildren(cellLayoutClipChildren);
                 cellLayout.setClipToPadding(cellLayoutClipToPadding);
+                hotseat.setClipChildren(hotseatClipChildren);
+                hotseat.setClipToPadding(hotseatClipToPadding);
             }
         };
 
@@ -180,16 +192,35 @@
         springTransY.setStartDelay(startDelay);
         mAnimators.add(springTransY);
 
-        if (v == mViewToIgnore) {
-            return;
+        ObjectAnimator alpha = getAlphaAnimator(v, startDelay);
+        if (v == mOriginalView) {
+            // For IconLabelDotViews, we just want the label to fade in.
+            // Icon, badge, and dots will animate in separately (controlled via FloatingIconView)
+            if (v instanceof IconLabelDotView) {
+                alpha.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationStart(Animator animation) {
+                        IconLabelDotView view = (IconLabelDotView) v;
+                        view.setIconVisible(false);
+                        view.setForceHideDot(true);
+                    }
+                });
+            } else {
+                return;
+            }
         }
 
         v.setAlpha(0);
+        mAnimators.add(alpha);
+    }
+
+    private ObjectAnimator getAlphaAnimator(View v, long startDelay) {
         ObjectAnimator alpha = ObjectAnimator.ofFloat(v, View.ALPHA, 0f, 1f);
         alpha.setInterpolator(LINEAR);
         alpha.setDuration(ALPHA_DURATION_MS);
         alpha.setStartDelay(startDelay);
-        mAnimators.add(alpha);
+        return alpha;
+
     }
 
     private void addScrimAnimationForState(Launcher launcher, LauncherState state, long duration) {
diff --git a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
index 3747f9a..dc6b56e 100644
--- a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
+++ b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
@@ -156,12 +156,14 @@
                 mDragHandleProgress = 1;
                 mMidAlpha = 0;
             } else {
-                mMidAlpha = Themes.getAttrInteger(getContext(), R.attr.allAppsInterimScrimAlpha);
+                Context context = getContext();
+                mMidAlpha = Themes.getAttrInteger(context, R.attr.allAppsInterimScrimAlpha);
                 mMidProgress =  OVERVIEW.getVerticalProgress(mLauncher);
                 Rect hotseatPadding = dp.getHotseatLayoutPadding();
                 int hotseatSize = dp.hotseatBarSizePx + dp.getInsets().bottom
                         - hotseatPadding.bottom - hotseatPadding.top;
-                float dragHandleTop = Math.min(hotseatSize, OverviewState.getDefaultSwipeHeight(dp));
+                float dragHandleTop =
+                        Math.min(hotseatSize, OverviewState.getDefaultSwipeHeight(context, dp));
                 mDragHandleProgress =  1 - (dragHandleTop / mShiftRange);
             }
             mTopOffset = dp.getInsets().top - mShelfOffset;
diff --git a/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java b/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java
index ec3d49a..a7c33a9 100644
--- a/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java
+++ b/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java
@@ -69,10 +69,9 @@
     private DigitalWellBeingToast getToast() {
         executeOnLauncher(launcher -> launcher.getStateManager().goToState(OVERVIEW));
         waitForState("Launcher internal state didn't switch to Overview", OVERVIEW);
-        waitForLauncherCondition("No latest task", launcher -> getLatestTask(launcher) != null);
+        final TaskView task = getOnceNotNull("No latest task", launcher -> getLatestTask(launcher));
 
         return getFromLauncher(launcher -> {
-            final TaskView task = getLatestTask(launcher);
             assertTrue("Latest task is not Calculator",
                     CALCULATOR_PACKAGE.equals(task.getTask().getTopComponent().getPackageName()));
             return task.getDigitalWellBeingToast();
diff --git a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
index edd5011..e295527 100644
--- a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
+++ b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
@@ -118,7 +118,6 @@
                         assertTrue("Couldn't set overlay",
                                 setActiveOverlay(prevOverlayPkg, originalMode));
                     }
-                    mLauncher.disableDebugTracing();
                 }
 
                 private void evaluateWithThreeButtons() throws Throwable {
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index be8506d..885fdbf 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -97,7 +97,6 @@
     @Test
     @PortraitLandscape
     public void testOverview() throws Exception {
-        mLauncher.enableDebugTracing();
         startTestApps();
         Overview overview = mLauncher.pressHome().switchToOverview();
         assertTrue("Launcher internal state didn't switch to Overview",
@@ -177,7 +176,6 @@
         executeOnLauncher(
                 launcher -> assertEquals("Still have tasks after dismissing all",
                         0, getTaskCount(launcher)));
-        mLauncher.disableDebugTracing();
     }
 
     private int getCurrentOverviewPage(Launcher launcher) {
diff --git a/src/com/android/launcher3/BaseRecyclerView.java b/src/com/android/launcher3/BaseRecyclerView.java
index c84be4d..864fa6e 100644
--- a/src/com/android/launcher3/BaseRecyclerView.java
+++ b/src/com/android/launcher3/BaseRecyclerView.java
@@ -22,6 +22,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 
+import com.android.launcher3.compat.AccessibilityManagerCompat;
 import com.android.launcher3.views.RecyclerViewFastScroller;
 
 import androidx.recyclerview.widget.RecyclerView;
@@ -171,4 +172,13 @@
      * <p>Override in each subclass of this base class.
      */
     public void onFastScrollCompleted() {}
+
+    @Override
+    public void onScrollStateChanged(int state) {
+        super.onScrollStateChanged(state);
+
+        if (state == SCROLL_STATE_IDLE) {
+            AccessibilityManagerCompat.sendScrollFinishedEventToTest(getContext());
+        }
+    }
 }
\ No newline at end of file
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 22c69f5..b113249 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -32,7 +32,6 @@
 import android.graphics.drawable.Drawable;
 import android.text.TextUtils.TruncateAt;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.util.Property;
 import android.util.TypedValue;
 import android.view.KeyEvent;
@@ -54,8 +53,8 @@
 import com.android.launcher3.icons.IconCache.IconLoadRequest;
 import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver;
 import com.android.launcher3.model.PackageItemInfo;
-import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.views.ActivityContext;
+import com.android.launcher3.views.IconLabelDotView;
 
 import java.text.NumberFormat;
 
@@ -64,7 +63,8 @@
  * because we want to make the bubble taller than the text and TextView's clip is
  * too aggressive.
  */
-public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, OnResumeCallback {
+public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, OnResumeCallback,
+        IconLabelDotView {
 
     private static final int DISPLAY_WORKSPACE = 0;
     private static final int DISPLAY_ALL_APPS = 1;
@@ -413,7 +413,8 @@
         }
     }
 
-    public void forceHideDot(boolean forceHideDot) {
+    @Override
+    public void setForceHideDot(boolean forceHideDot) {
         if (mForceHideDot == forceHideDot) {
             return;
         }
@@ -602,6 +603,7 @@
         }
     }
 
+    @Override
     public void setIconVisible(boolean visible) {
         mIsIconVisible = visible;
         Drawable icon = visible ? mIcon : new ColorDrawable(Color.TRANSPARENT);
diff --git a/src/com/android/launcher3/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java
index 7ab88a0..a90025e 100644
--- a/src/com/android/launcher3/FastBitmapDrawable.java
+++ b/src/com/android/launcher3/FastBitmapDrawable.java
@@ -142,8 +142,11 @@
 
     @Override
     public void setAlpha(int alpha) {
-        mAlpha = alpha;
-        mPaint.setAlpha(alpha);
+        if (mAlpha != alpha) {
+            mAlpha = alpha;
+            mPaint.setAlpha(alpha);
+            invalidateSelf();
+        }
     }
 
     @Override
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index a2f869f..f82e380 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -427,13 +427,4 @@
     public boolean hasOverlappingRendering() {
         return false;
     }
-
-    @Override
-    public void onScrollStateChanged(int state) {
-        super.onScrollStateChanged(state);
-
-        if (state == SCROLL_STATE_IDLE) {
-            AccessibilityManagerCompat.sendScrollFinishedEventToTest(getContext());
-        }
-    }
 }
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 2ef6d70..f22b533 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -516,7 +516,7 @@
         anim.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationStart(Animator animation) {
-                mFolderIcon.setBackgroundVisible(false);
+                mFolderIcon.setIconVisible(false);
                 mFolderIcon.drawLeaveBehindIfExists();
             }
             @Override
@@ -646,7 +646,7 @@
         clearFocus();
         if (mFolderIcon != null) {
             mFolderIcon.setVisibility(View.VISIBLE);
-            mFolderIcon.setBackgroundVisible(true);
+            mFolderIcon.setIconVisible(true);
             mFolderIcon.mFolderName.setTextVisibility(true);
             if (wasAnimated) {
                 mFolderIcon.animateBgShadowAndStroke();
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index 250169c..0e2d467 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -65,6 +65,7 @@
 import com.android.launcher3.icons.DotRenderer;
 import com.android.launcher3.touch.ItemClickHandler;
 import com.android.launcher3.util.Thunk;
+import com.android.launcher3.views.IconLabelDotView;
 import com.android.launcher3.widget.PendingAddShortcutInfo;
 
 import java.util.ArrayList;
@@ -73,7 +74,7 @@
 /**
  * An icon that can appear on in the workspace representing an {@link Folder}.
  */
-public class FolderIcon extends FrameLayout implements FolderListener {
+public class FolderIcon extends FrameLayout implements FolderListener, IconLabelDotView {
 
     @Thunk Launcher mLauncher;
     @Thunk Folder mFolder;
@@ -107,6 +108,7 @@
 
     private Alarm mOpenAlarm = new Alarm();
 
+    private boolean mForceHideDot;
     @ViewDebug.ExportedProperty(category = "launcher", deepExport = true)
     private FolderDotInfo mDotInfo = new FolderDotInfo();
     private DotRenderer mDotRenderer;
@@ -409,6 +411,20 @@
         return mPreviewLayoutRule;
     }
 
+    @Override
+    public void setForceHideDot(boolean forceHideDot) {
+        if (mForceHideDot == forceHideDot) {
+            return;
+        }
+        mForceHideDot = forceHideDot;
+
+        if (forceHideDot) {
+            invalidate();
+        } else if (hasDot()) {
+            animateDotScale(0, 1);
+        }
+    }
+
     /**
      * Sets mDotScale to 1 or 0, animating if wasDotted or isDotted is false
      * (the dot is being added or removed).
@@ -468,7 +484,8 @@
         mBackground.setInvalidateDelegate(this);
     }
 
-    public void setBackgroundVisible(boolean visible) {
+    @Override
+    public void setIconVisible(boolean visible) {
         mBackgroundIsVisible = visible;
         invalidate();
     }
@@ -509,7 +526,7 @@
     }
 
     public void drawDot(Canvas canvas) {
-        if ((mDotInfo != null && mDotInfo.hasDot()) || mDotScale > 0) {
+        if (!mForceHideDot && ((mDotInfo != null && mDotInfo.hasDot()) || mDotScale > 0)) {
             Rect iconBounds = mDotParams.iconBounds;
             BubbleTextView.getIconBounds(this, iconBounds,
                     mLauncher.getWallpaperDeviceProfile().iconSizePx);
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index baaad65..15fb4ce 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -36,7 +36,6 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.util.Pair;
 import android.view.MotionEvent;
 import android.view.View;
@@ -53,7 +52,6 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherModel;
 import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
 import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
 import com.android.launcher3.accessibility.ShortcutMenuAccessibilityDelegate;
 import com.android.launcher3.dot.DotInfo;
@@ -65,10 +63,8 @@
 import com.android.launcher3.notification.NotificationItemView;
 import com.android.launcher3.notification.NotificationKeyData;
 import com.android.launcher3.popup.PopupDataProvider.PopupDataChangeListener;
-import com.android.launcher3.shortcuts.DeepShortcutManager;
 import com.android.launcher3.shortcuts.DeepShortcutView;
 import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
-import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.touch.ItemClickHandler;
 import com.android.launcher3.touch.ItemLongClickListener;
 import com.android.launcher3.util.PackageUserKey;
@@ -301,7 +297,7 @@
         }
 
         mLauncher.getDragController().addDragListener(this);
-        mOriginalIcon.forceHideDot(true);
+        mOriginalIcon.setForceHideDot(true);
 
         // All views are added. Animate layout from now on.
         setLayoutTransition(new LayoutTransition());
@@ -564,14 +560,14 @@
     protected void onCreateCloseAnimation(AnimatorSet anim) {
         // Animate original icon's text back in.
         anim.play(mOriginalIcon.createTextAlphaAnimator(true /* fadeIn */));
-        mOriginalIcon.forceHideDot(false);
+        mOriginalIcon.setForceHideDot(false);
     }
 
     @Override
     protected void closeComplete() {
         super.closeComplete();
         mOriginalIcon.setTextVisibility(mOriginalIcon.shouldTextBeVisible());
-        mOriginalIcon.forceHideDot(false);
+        mOriginalIcon.setForceHideDot(false);
     }
 
     @Override
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index e09a9e8..15b8d46 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -18,7 +18,6 @@
 import static com.android.launcher3.LauncherAnimUtils.DRAWABLE_ALPHA;
 import static com.android.launcher3.Utilities.getBadge;
 import static com.android.launcher3.Utilities.getFullDrawable;
-import static com.android.launcher3.Utilities.isRtl;
 import static com.android.launcher3.Utilities.mapToRange;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.config.FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM;
@@ -564,11 +563,6 @@
      */
     private void checkIconResult(View originalView, boolean isOpening) {
         CancellationSignal cancellationSignal = new CancellationSignal();
-        if (!isOpening) {
-            // Hide immediately since the floating view starts at a different location.
-            originalView.setVisibility(INVISIBLE);
-            cancellationSignal.setOnCancelListener(() -> originalView.setVisibility(VISIBLE));
-        }
 
         if (mIconLoadResult == null) {
             Log.w(TAG, "No icon load result found in checkIconResult");
@@ -580,7 +574,7 @@
                 setIcon(originalView, mIconLoadResult.drawable, mIconLoadResult.badge,
                         mIconLoadResult.iconOffset);
                 if (isOpening) {
-                    originalView.setVisibility(INVISIBLE);
+                    hideOriginalView(originalView);
                 }
             } else {
                 mIconLoadResult.onIconLoaded = () -> {
@@ -591,15 +585,26 @@
                     setIcon(originalView, mIconLoadResult.drawable, mIconLoadResult.badge,
                             mIconLoadResult.iconOffset);
 
-                    // Delay swapping views until the icon is loaded to prevent a flash.
                     setVisibility(VISIBLE);
-                    originalView.setVisibility(INVISIBLE);
+                    if (isOpening) {
+                        // Delay swapping views until the icon is loaded to prevent a flash.
+                        hideOriginalView(originalView);
+                    }
                 };
                 mLoadIconSignal = cancellationSignal;
             }
         }
     }
 
+    private void hideOriginalView(View originalView) {
+        if (originalView instanceof BubbleTextView) {
+            ((BubbleTextView) originalView).setIconVisible(false);
+            ((BubbleTextView) originalView).setForceHideDot(true);
+        } else {
+            originalView.setVisibility(INVISIBLE);
+        }
+    }
+
     private void setBackgroundDrawableBounds(float scale) {
         sTmpRect.set(mFinalDrawableBounds);
         Utilities.scaleRectAboutCenter(sTmpRect, scale);
@@ -776,7 +781,12 @@
 
             if (hideOriginal) {
                 if (isOpening) {
-                    originalView.setVisibility(VISIBLE);
+                    if (originalView instanceof BubbleTextView) {
+                        ((BubbleTextView) originalView).setIconVisible(true);
+                        ((BubbleTextView) originalView).setForceHideDot(false);
+                    } else {
+                        originalView.setVisibility(VISIBLE);
+                    }
                     view.finish(dragLayer);
                 } else {
                     view.mFadeAnimatorSet = view.createFadeAnimation(originalView, dragLayer);
@@ -804,38 +814,33 @@
             }
         });
 
-        if (mBadge != null && !(mOriginalIcon instanceof FolderIcon)) {
+        if (mBadge != null) {
             ObjectAnimator badgeFade = ObjectAnimator.ofInt(mBadge, DRAWABLE_ALPHA, 255);
             badgeFade.addUpdateListener(valueAnimator -> invalidate());
             fade.play(badgeFade);
         }
 
-        if (originalView instanceof BubbleTextView) {
-            BubbleTextView btv = (BubbleTextView) originalView;
-            btv.forceHideDot(true);
+        if (originalView instanceof IconLabelDotView) {
+            IconLabelDotView view = (IconLabelDotView) originalView;
             fade.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
-                    btv.forceHideDot(false);
+                    view.setIconVisible(true);
+                    view.setForceHideDot(false);
                 }
             });
         }
 
-        if (originalView instanceof FolderIcon) {
-            FolderIcon folderIcon = (FolderIcon) originalView;
-            folderIcon.setBackgroundVisible(false);
-            folderIcon.getFolderName().setTextVisibility(false);
-            fade.play(folderIcon.getFolderName().createTextAlphaAnimator(true));
+        if (originalView instanceof BubbleTextView) {
+            BubbleTextView btv = (BubbleTextView) originalView;
             fade.addListener(new AnimatorListenerAdapter() {
                 @Override
-                public void onAnimationEnd(Animator animation) {
-                    folderIcon.setBackgroundVisible(true);
-                    if (folderIcon.hasDot()) {
-                        folderIcon.animateDotScale(0, 1f);
-                    }
+                public void onAnimationStart(Animator animation) {
+                    btv.setIconVisible(true);
                 }
             });
-        } else {
+            fade.play(ObjectAnimator.ofInt(btv.getIcon(), DRAWABLE_ALPHA, 0, 255));
+        } else if (!(originalView instanceof FolderIcon)) {
             fade.play(ObjectAnimator.ofFloat(originalView, ALPHA, 0f, 1f));
         }
 
diff --git a/src/com/android/launcher3/views/IconLabelDotView.java b/src/com/android/launcher3/views/IconLabelDotView.java
new file mode 100644
index 0000000..057caaf
--- /dev/null
+++ b/src/com/android/launcher3/views/IconLabelDotView.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2019 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.launcher3.views;
+
+/**
+ * A view that has an icon, label, and notification dot.
+ */
+public interface IconLabelDotView {
+    void setIconVisible(boolean visible);
+    void setForceHideDot(boolean hide);
+}
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index fc19baa..dc890bb 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -24,7 +24,6 @@
 
 import static java.lang.System.exit;
 
-import android.app.Instrumentation;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -112,6 +111,7 @@
                             launcher ->
                                     checkLauncherIntegrity(launcher, containerType)));
         }
+        mLauncher.enableDebugTracing();
     }
 
     protected final LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
@@ -187,14 +187,6 @@
         }
     }
 
-    protected void lockRotation(boolean naturalOrientation) throws RemoteException {
-        if (naturalOrientation) {
-            mDevice.setOrientationNatural();
-        } else {
-            mDevice.setOrientationRight();
-        }
-    }
-
     protected void clearLauncherData() throws IOException, InterruptedException {
         if (TestHelpers.isInLauncherProcess()) {
             LauncherSettings.Settings.call(mTargetContext.getContentResolver(),
@@ -202,6 +194,7 @@
             resetLoaderState();
         } else {
             clearPackageData(mDevice.getLauncherPackageName());
+            mLauncher.enableDebugTracing();
         }
     }
 
@@ -275,6 +268,12 @@
 
     // Cannot be used in TaplTests after injecting any gesture using Tapl because this can hide
     // flakiness.
+    protected <T> T getOnceNotNull(String message, Function<Launcher, T> f) {
+        return getOnceNotNull(message, f, DEFAULT_ACTIVITY_TIMEOUT);
+    }
+
+    // Cannot be used in TaplTests after injecting any gesture using Tapl because this can hide
+    // flakiness.
     protected void waitForLauncherCondition(
             String message, Function<Launcher, Boolean> condition, long timeout) {
         if (!TestHelpers.isInLauncherProcess()) return;
@@ -283,6 +282,20 @@
 
     // Cannot be used in TaplTests after injecting any gesture using Tapl because this can hide
     // flakiness.
+    protected <T> T getOnceNotNull(String message, Function<Launcher, T> f, long timeout) {
+        if (!TestHelpers.isInLauncherProcess()) return null;
+
+        final Object[] output = new Object[1];
+        Wait.atMost(message, () -> {
+            final Object fromLauncher = getFromLauncher(f);
+            output[0] = fromLauncher;
+            return fromLauncher != null;
+        }, timeout);
+        return (T) output[0];
+    }
+
+    // Cannot be used in TaplTests after injecting any gesture using Tapl because this can hide
+    // flakiness.
     protected void waitForLauncherCondition(
             String message,
             Runnable testThreadAction, Function<Launcher, Boolean> condition,
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index 0c87ab9..c2a3c1c 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -173,7 +173,6 @@
 
     @Test
     public void testWorkspace() throws Exception {
-        mLauncher.enableDebugTracing();
         final Workspace workspace = mLauncher.getWorkspace();
 
         // Test that ensureWorkspaceIsScrollable adds a page by dragging an icon there.
@@ -209,7 +208,6 @@
         // Test starting a workspace app.
         final AppIcon app = workspace.getWorkspaceAppIcon("Chrome");
         assertNotNull("No Chrome app in workspace", app);
-        mLauncher.disableDebugTracing();
     }
 
     public static void runIconLaunchFromAllAppsTest(AbstractLauncherUiTest test, AllApps allApps) {
@@ -300,7 +298,6 @@
     @Test
     @PortraitLandscape
     public void testDragAppIcon() throws Throwable {
-        mLauncher.enableDebugTracing();
         // 1. Open all apps and wait for load complete.
         // 2. Drag icon to homescreen.
         // 3. Verify that the icon works on homescreen.
@@ -317,13 +314,11 @@
                 "Launcher activity is the top activity; expecting another activity to be the top "
                         + "one",
                 isInBackground(launcher)));
-        mLauncher.disableDebugTracing();
     }
 
     @Test
     @PortraitLandscape
     public void testDragShortcut() throws Throwable {
-        mLauncher.enableDebugTracing();
         // 1. Open all apps and wait for load complete.
         // 2. Find the app and long press it to show shortcuts.
         // 3. Press icon center until shortcuts appear
@@ -343,7 +338,6 @@
         } finally {
             allApps.unfreeze();
         }
-        mLauncher.disableDebugTracing();
     }
 
     public static String getAppPackageName() {
diff --git a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
index 3206a69..5c38c8d 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
@@ -41,7 +41,6 @@
 import com.android.launcher3.util.rule.ShellCommandRule;
 
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -69,34 +68,22 @@
     }
 
     @Test
+    @PortraitLandscape
     public void testWidgetConfig() throws Throwable {
-        runTest(false, true);
+        runTest(true);
     }
 
     @Test
-    @Ignore // b/121280703
-    public void testWidgetConfig_rotate() throws Throwable {
-        runTest(true, true);
-    }
-
-    @Test
+    @PortraitLandscape
     public void testConfigCancelled() throws Throwable {
-        runTest(false, false);
+        runTest(false);
     }
 
-    @Test
-    @Ignore // b/121280703
-    public void testConfigCancelled_rotate() throws Throwable {
-        runTest(true, false);
-    }
 
     /**
-     * @param rotateConfig should the config screen be rotated
      * @param acceptConfig accept the config activity
      */
-    private void runTest(boolean rotateConfig, boolean acceptConfig) throws Throwable {
-        lockRotation(true);
-
+    private void runTest(boolean acceptConfig) throws Throwable {
         clearHomescreen();
         mDevice.pressHome();
 
@@ -110,13 +97,6 @@
         // Widget id for which the config activity was opened
         mWidgetId = monitor.getWidgetId();
 
-        if (rotateConfig) {
-            // Rotate the screen and verify that the config activity is recreated
-            monitor = new WidgetConfigStartupMonitor();
-            lockRotation(false);
-            assertEquals(mWidgetId, monitor.getWidgetId());
-        }
-
         // Verify that the widget id is valid and bound
         assertNotNull(mAppWidgetManager.getAppWidgetInfo(mWidgetId));
 
diff --git a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
index 276c614..b9abc2e 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
@@ -26,7 +26,6 @@
 import com.android.launcher3.ui.TestViewHelpers;
 import com.android.launcher3.util.rule.ShellCommandRule;
 
-import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -41,19 +40,8 @@
     @Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
 
     @Test
-    public void testDragIcon_portrait() throws Throwable {
-        lockRotation(true);
-        performTest();
-    }
-
-    @Test
-    @Ignore // b/121280703
-    public void testDragIcon_landscape() throws Throwable {
-        lockRotation(false);
-        performTest();
-    }
-
-    private void performTest() throws Throwable {
+    @PortraitLandscape
+    public void testDragIcon() throws Throwable {
         clearHomescreen();
         mDevice.pressHome();
 
diff --git a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
index a9a5090..07129dd 100644
--- a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
@@ -128,8 +128,6 @@
         if (!Utilities.ATLEAST_OREO) {
             return;
         }
-        lockRotation(true);
-
         clearHomescreen();
         mDevice.pressHome();
 
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 9d43352..0bd6362 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -763,8 +763,7 @@
         final Bundle parcel = (Bundle) executeAndWaitForEvent(
                 () -> linearGesture(startX, startY, endX, endY, steps),
                 event -> TestProtocol.SWITCHED_TO_STATE_MESSAGE.equals(event.getClassName()),
-                "Swipe failed to receive an event for the swipe end: " + startX + ", " + startY
-                        + ", " + endX + ", " + endY);
+                "Swipe failed to receive an event for the swipe end");
         assertEquals("Swipe switched launcher to a wrong state;",
                 TestProtocol.stateOrdinalToString(expectedState),
                 TestProtocol.stateOrdinalToString(parcel.getInt(TestProtocol.STATE_FIELD)));
diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java
index 2495933..f3295d0 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widgets.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java
@@ -19,6 +19,7 @@
 import static org.junit.Assert.fail;
 
 import android.graphics.Point;
+import android.graphics.Rect;
 
 import androidx.test.uiautomator.By;
 import androidx.test.uiautomator.BySelector;
@@ -31,7 +32,8 @@
  * All widgets container.
  */
 public final class Widgets extends LauncherInstrumentation.VisibleContainer {
-    private static final int FLING_SPEED = 1500;
+    private static final Rect MARGINS = new Rect(100, 100, 100, 100);
+    private static final int FLING_STEPS = 10;
 
     Widgets(LauncherInstrumentation launcher) {
         super(launcher);
@@ -46,11 +48,7 @@
                 "want to fling forward in widgets")) {
             LauncherInstrumentation.log("Widgets.flingForward enter");
             final UiObject2 widgetsContainer = verifyActiveContainer();
-            widgetsContainer.setGestureMargins(0, 0, 0,
-                    ResourceUtils.getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE,
-                            mLauncher.getResources()) + 1);
-            widgetsContainer.fling(Direction.DOWN,
-                    (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
+            mLauncher.scroll(widgetsContainer, Direction.DOWN, 1f, MARGINS, FLING_STEPS);
             try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung forward")) {
                 verifyActiveContainer();
             }
@@ -66,10 +64,7 @@
                 "want to fling backwards in widgets")) {
             LauncherInstrumentation.log("Widgets.flingBackward enter");
             final UiObject2 widgetsContainer = verifyActiveContainer();
-            widgetsContainer.setGestureMargin(100);
-            widgetsContainer.fling(Direction.UP,
-                    (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
-            mLauncher.waitForIdle();
+            mLauncher.scroll(widgetsContainer, Direction.UP, 1f, MARGINS, FLING_STEPS);
             try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung back")) {
                 verifyActiveContainer();
             }
@@ -101,7 +96,7 @@
                 return new Widget(mLauncher, widget);
             }
             if (++i > 40) fail("Too many attempts");
-            widgetsContainer.scroll(Direction.DOWN, 1f);
+            mLauncher.scroll(widgetsContainer, Direction.DOWN, 1f, MARGINS, 50);
         }
     }
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 639902f..510ea14 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -21,6 +21,7 @@
 import static junit.framework.TestCase.assertTrue;
 
 import android.graphics.Point;
+import android.graphics.Rect;
 import android.os.SystemClock;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
@@ -40,6 +41,7 @@
     private static final float FLING_SPEED =
             LauncherInstrumentation.isAvd() ? 1500.0F : 3500.0F;
     private static final int DRAG_DURACTION = 2000;
+    private static final int FLING_STEPS = 10;
     private final UiObject2 mHotseat;
 
     Workspace(LauncherInstrumentation launcher) {
@@ -180,9 +182,9 @@
      */
     public void flingForward() {
         final UiObject2 workspace = verifyActiveContainer();
-        workspace.setGestureMargins(0, 0, mLauncher.getEdgeSensitivityWidth(), 0);
-        workspace.fling(Direction.RIGHT, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
-        mLauncher.waitForIdle();
+        mLauncher.scroll(workspace, Direction.RIGHT, 1f,
+                new Rect(0, 0, mLauncher.getEdgeSensitivityWidth(), 0),
+                FLING_STEPS);
         verifyActiveContainer();
     }
 
@@ -192,9 +194,9 @@
      */
     public void flingBackward() {
         final UiObject2 workspace = verifyActiveContainer();
-        workspace.setGestureMargins(mLauncher.getEdgeSensitivityWidth(), 0, 0, 0);
-        workspace.fling(Direction.LEFT, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
-        mLauncher.waitForIdle();
+        mLauncher.scroll(workspace, Direction.LEFT, 1f,
+                new Rect(mLauncher.getEdgeSensitivityWidth(), 0, 0, 0),
+                FLING_STEPS);
         verifyActiveContainer();
     }