Merging ub-launcher3-qt-dev, build 5595491

Test: Manual

Bug:122345781 P1 Inflation happens and a binder call during swipe up gesture, that may cause jank
Bug:123900446 P1 App to home animation should zoom into the app icon
Bug:124510042 P1 [Gesture Nav] Home animation polish
Bug:126744445 P1 Add chips support for Overview UI library
Bug:127783075 P1 When swiping up to recents, sometimes velocity is really wrong
Bug:129036789 P2 [a11y] Talkback doesn't indicate App paused in Home/Apps list.
Bug:131839392 P2 Ensure Go Launcher follows theming standards
Bug:132283018 P1 Shelf Jump
Bug:132356358 P1 Fix invocation animation for fling
Bug:132588097 P1 Launcher folder shadow and image flickers on going home
Bug:132716177 P4 Swiping right at home shows alphabet index
Bug:132900132 P1 Apparently, tests start running while provisioning is still in progress
Bug:132917885 P1 Reduce swipe-up gesture region height in landscape
Bug:133009122 P2 Rare flake: dragged launchable to workspace, but the current state is not WORKSPACE; Can't find a launcher object; selector: BySelector [RES='\Qcom.google.android.apps.nexuslauncher:id/apps_view\E']
Bug:133010447 P2 Blueline: flake: test manages to click search box instead of starting an app
Bug:133010773 P2 qt-dev / crosshatch: flake: java.lang.AssertionError: http://go/tapl : want to switch from background to overview; Swipe failed to receive an event for the swipe end: 720, 2959, 720, 2050
Bug:133011252 P2 flake: Launching an app didn't open a new window: Calendar
Bug:133265591 P1 Blocked touches in thin region over home
Change-Id: Iac4013556a2a49418d1634762698ea59bbf95a75
diff --git a/go/quickstep/res/layout/clear_all_button.xml b/go/quickstep/res/layout/clear_all_button.xml
index 2f7c8ae..eef66ad 100644
--- a/go/quickstep/res/layout/clear_all_button.xml
+++ b/go/quickstep/res/layout/clear_all_button.xml
@@ -29,5 +29,6 @@
         android:text="@string/recents_clear_all"
         android:textAllCaps="false"
         android:textColor="@color/clear_all_button_text"
-        android:textSize="14sp"/>
+        android:textSize="14sp"
+        style="@style/TextTitle"/>
 </FrameLayout>
diff --git a/go/quickstep/res/layout/icon_recents_root_view.xml b/go/quickstep/res/layout/icon_recents_root_view.xml
index 595a380..8381ebc 100644
--- a/go/quickstep/res/layout/icon_recents_root_view.xml
+++ b/go/quickstep/res/layout/icon_recents_root_view.xml
@@ -36,5 +36,6 @@
         android:text="@string/recents_empty_message"
         android:textColor="@android:color/white"
         android:textSize="25sp"
+        style="@style/TextTitle"
         android:visibility="gone"/>
 </com.android.quickstep.views.IconRecentsView>
\ No newline at end of file
diff --git a/go/quickstep/res/layout/task_item_view.xml b/go/quickstep/res/layout/task_item_view.xml
index ab2cf28..aeac477 100644
--- a/go/quickstep/res/layout/task_item_view.xml
+++ b/go/quickstep/res/layout/task_item_view.xml
@@ -41,5 +41,6 @@
         android:layout_gravity="center_vertical"
         android:singleLine="true"
         android:textColor="@android:color/white"
-        android:textSize="24sp"/>
+        android:textSize="24sp"
+        style="@style/TextTitle"/>
 </com.android.quickstep.views.TaskItemView>
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
index ebae1cd..336cdc9 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
@@ -76,8 +76,13 @@
 
         @Override
         public void mapInsets(Context context, Rect insets, Rect out) {
+            // If there is a display cutout, the top insets in portrait would also include the
+            // cutout, which we will get as the left inset in landscape. Using the max of left and
+            // top allows us to cover both cases (with or without cutout).
             if (SysUINavigationMode.getMode(context) == NO_BUTTON) {
-                out.set(insets);
+                out.top = Math.max(insets.top, insets.left);
+                out.bottom = Math.max(insets.right, insets.bottom);
+                out.left = out.right = 0;
             } else {
                 out.top = Math.max(insets.top, insets.left);
                 out.bottom = insets.right;
@@ -99,7 +104,9 @@
         @Override
         public void mapInsets(Context context, Rect insets, Rect out) {
             if (SysUINavigationMode.getMode(context) == NO_BUTTON) {
-                out.set(insets);
+                out.top = Math.max(insets.top, insets.right);
+                out.bottom = Math.max(insets.left, insets.bottom);
+                out.left = out.right = 0;
             } else {
                 out.top = Math.max(insets.top, insets.right);
                 out.bottom = insets.left;
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
index f429ce5..a662d74 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
@@ -17,6 +17,7 @@
 
 import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
 
+import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.allapps.AllAppsTransitionController;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
@@ -42,6 +43,13 @@
     }
 
     @Override
+    public void onStateEnabled(Launcher launcher) {
+        RecentsView rv = launcher.getOverviewPanel();
+        rv.setOverviewStateEnabled(true);
+        AbstractFloatingView.closeAllOpenViews(launcher, false);
+    }
+
+    @Override
     public float getVerticalProgress(Launcher launcher) {
         if (launcher.getDeviceProfile().isVerticalBarLayout()) {
             return super.getVerticalProgress(launcher);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
index 90b5536..4b2e487 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
@@ -118,7 +118,8 @@
         final RectF iconLocation = new RectF();
         boolean canUseWorkspaceView = workspaceView != null && workspaceView.isAttachedToWindow();
         FloatingIconView floatingIconView = canUseWorkspaceView
-                ? recentsView.getFloatingIconView(activity, workspaceView, iconLocation)
+                ? FloatingIconView.getFloatingIconView(activity, workspaceView,
+                        true /* hideOriginal */, iconLocation, false /* isOpening */)
                 : null;
 
         return new HomeAnimationFactory() {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
index 0fd74bb..0c997dd 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -331,21 +331,29 @@
         defaultDisplay.getRealSize(realSize);
         mSwipeTouchRegion.set(0, 0, realSize.x, realSize.y);
         if (mMode == Mode.NO_BUTTON) {
-            mSwipeTouchRegion.top = mSwipeTouchRegion.bottom - getNavbarSize(
-                    ResourceUtils.NAVBAR_VERTICAL_SIZE);
+            switch (defaultDisplay.getRotation()) {
+                case Surface.ROTATION_90:
+                case Surface.ROTATION_270:
+                    mSwipeTouchRegion.top = mSwipeTouchRegion.bottom - getNavbarSize(
+                            ResourceUtils.NAVBAR_LANDSCAPE_BOTTOM_SIZE);
+                    break;
+                default:
+                    mSwipeTouchRegion.top = mSwipeTouchRegion.bottom - getNavbarSize(
+                            ResourceUtils.NAVBAR_PORTRAIT_BOTTOM_SIZE);
+            }
         } else {
             switch (defaultDisplay.getRotation()) {
                 case Surface.ROTATION_90:
                     mSwipeTouchRegion.left = mSwipeTouchRegion.right
-                            - getNavbarSize(ResourceUtils.NAVBAR_HORIZONTAL_SIZE);
+                            - getNavbarSize(ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE);
                     break;
                 case Surface.ROTATION_270:
                     mSwipeTouchRegion.right = mSwipeTouchRegion.left
-                            + getNavbarSize(ResourceUtils.NAVBAR_HORIZONTAL_SIZE);
+                            + getNavbarSize(ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE);
                     break;
                 default:
                     mSwipeTouchRegion.top = mSwipeTouchRegion.bottom
-                            - getNavbarSize(ResourceUtils.NAVBAR_VERTICAL_SIZE);
+                            - getNavbarSize(ResourceUtils.NAVBAR_PORTRAIT_BOTTOM_SIZE);
             }
         }
     }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
index d69262e..2ff5c0c 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -902,7 +902,7 @@
             float minFlingVelocity = mContext.getResources()
                     .getDimension(R.dimen.quickstep_fling_min_velocity);
             if (Math.abs(endVelocity) > minFlingVelocity && mTransitionDragLength > 0) {
-                if (endTarget == RECENTS) {
+                if (endTarget == RECENTS && mMode != Mode.NO_BUTTON) {
                     Interpolators.OvershootParams overshoot = new Interpolators.OvershootParams(
                             startShift, endShift, endShift, velocityPxPerMs.y,
                             mTransitionDragLength);
@@ -918,6 +918,10 @@
                     // derivative of the scroll interpolator at zero, ie. 2.
                     long baseDuration = Math.round(Math.abs(distanceToTravel / velocityPxPerMs.y));
                     duration = Math.min(MAX_SWIPE_DURATION, 2 * baseDuration);
+
+                    if (endTarget == RECENTS) {
+                        interpolator = OVERSHOOT_1_2;
+                    }
                 }
             }
         }
@@ -932,7 +936,8 @@
         } else if (endTarget == RECENTS) {
             mLiveTileOverlay.startIconAnimation();
             if (mRecentsView != null) {
-                duration = Math.max(duration, mRecentsView.getScroller().getDuration());
+                duration = Utilities.boundToRange(mRecentsView.getScroller().getDuration(),
+                        duration, MAX_SWIPE_DURATION);
             }
             if (mMode == Mode.NO_BUTTON) {
                 setShelfState(ShelfAnimState.OVERVIEW, interpolator, duration);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantTouchConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantTouchConsumer.java
index 20ea3a1..bf276e1 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantTouchConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantTouchConsumer.java
@@ -23,6 +23,7 @@
 import static android.view.MotionEvent.ACTION_POINTER_UP;
 import static android.view.MotionEvent.ACTION_UP;
 
+import static com.android.launcher3.Utilities.squaredHypot;
 import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction.UPLEFT;
 import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction.UPRIGHT;
 import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.FLING;
@@ -40,6 +41,7 @@
 import android.util.Log;
 import android.view.HapticFeedbackConstants;
 import android.view.MotionEvent;
+import android.view.ViewConfiguration;
 
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.R;
@@ -81,7 +83,7 @@
     private final float mDistThreshold;
     private final long mTimeThreshold;
     private final int mAngleThreshold;
-    private final float mSlop;
+    private final float mSquaredSlop;
     private final ISystemUiProxy mSysUiProxy;
     private final Context mContext;
     private final SwipeDetector mSwipeDetector;
@@ -96,7 +98,10 @@
         mDistThreshold = res.getDimension(R.dimen.gestures_assistant_drag_threshold);
         mTimeThreshold = res.getInteger(R.integer.assistant_gesture_min_time_threshold);
         mAngleThreshold = res.getInteger(R.integer.assistant_gesture_corner_deg_threshold);
-        mSlop = QuickStepContract.getQuickStepDragSlopPx();
+
+        float slop = ViewConfiguration.get(context).getScaledTouchSlop();
+
+        mSquaredSlop = slop * slop;
         mActivityControlHelper = activityControlHelper;
         mSwipeDetector = new SwipeDetector(mContext, this, SwipeDetector.VERTICAL);
         mSwipeDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_POSITIVE, false);
@@ -155,7 +160,8 @@
 
                 if (!mPassedSlop) {
                     // Normal gesture, ensure we pass the slop before we start tracking the gesture
-                    if (Math.hypot(mLastPos.x - mDownPos.x, mLastPos.y - mDownPos.y) > mSlop) {
+                    if (squaredHypot(mLastPos.x - mDownPos.x, mLastPos.y - mDownPos.y)
+                            > mSquaredSlop) {
 
                         mPassedSlop = true;
                         mStartDragPos.set(mLastPos.x, mLastPos.y);
@@ -218,31 +224,35 @@
     private void updateAssistantProgress() {
         if (!mLaunchedAssistant) {
             mLastProgress = Math.min(mDistance * 1f / mDistThreshold, 1) * mTimeFraction;
-            updateAssistant(SWIPE);
+            try {
+                if (mDistance >= mDistThreshold && mTimeFraction >= 1) {
+                    mSysUiProxy.onAssistantGestureCompletion(0);
+                    startAssistantInternal(SWIPE);
+
+                    Bundle args = new Bundle();
+                    args.putInt(INVOCATION_TYPE_KEY, INVOCATION_TYPE_GESTURE);
+                    mSysUiProxy.startAssistant(args);
+                    mLaunchedAssistant = true;
+                } else {
+                    mSysUiProxy.onAssistantProgress(mLastProgress);
+                }
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed to send SysUI start/send assistant progress: " + mLastProgress,
+                    e);
+            }
         }
     }
 
-    private void updateAssistant(int gestureType) {
-        try {
-            mSysUiProxy.onAssistantProgress(mLastProgress);
-            if (gestureType == FLING || (mDistance >= mDistThreshold && mTimeFraction >= 1)) {
-                UserEventDispatcher.newInstance(mContext)
-                    .logActionOnContainer(gestureType, mDirection, NAVBAR);
-                Bundle args = new Bundle();
-                args.putInt(INVOCATION_TYPE_KEY, INVOCATION_TYPE_GESTURE);
+    private void startAssistantInternal(int gestureType) {
+        UserEventDispatcher.newInstance(mContext)
+            .logActionOnContainer(gestureType, mDirection, NAVBAR);
 
-                BaseDraggingActivity launcherActivity = mActivityControlHelper.getCreatedActivity();
-                if (launcherActivity != null) {
-                    launcherActivity.getRootView().performHapticFeedback(
-                        13, // HapticFeedbackConstants.GESTURE_END
-                        HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
-                }
-
-                mSysUiProxy.startAssistant(args);
-                mLaunchedAssistant = true;
-            }
-        } catch (RemoteException e) {
-            Log.w(TAG, "Failed to send SysUI start/send assistant progress: " + mLastProgress, e);
+        BaseDraggingActivity launcherActivity = mActivityControlHelper
+            .getCreatedActivity();
+        if (launcherActivity != null) {
+            launcherActivity.getRootView().performHapticFeedback(
+                13, // HapticFeedbackConstants.GESTURE_END
+                HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
         }
     }
 
@@ -266,9 +276,20 @@
 
     @Override
     public void onDragEnd(float velocity, boolean fling) {
-        if (fling && !mLaunchedAssistant) {
+        if (fling && !mLaunchedAssistant && mState != STATE_DELEGATE_ACTIVE) {
             mLastProgress = 1;
-            updateAssistant(FLING);
+            try {
+                mSysUiProxy.onAssistantGestureCompletion(velocity);
+                startAssistantInternal(FLING);
+
+                Bundle args = new Bundle();
+                args.putInt(INVOCATION_TYPE_KEY, INVOCATION_TYPE_GESTURE);
+                mSysUiProxy.startAssistant(args);
+                mLaunchedAssistant = true;
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed to send SysUI start/send assistant progress: " + mLastProgress,
+                    e);
+            }
         }
     }
 }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
index b1d175d..d01b5ec 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
@@ -15,11 +15,13 @@
  */
 package com.android.quickstep.inputconsumers;
 
+import static com.android.launcher3.Utilities.squaredHypot;
+import static com.android.launcher3.Utilities.squaredTouchSlop;
+
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.PointF;
 import android.view.MotionEvent;
-import android.view.ViewConfiguration;
 
 /**
  * A dummy input consumer used when the device is still locked, e.g. from secure camera.
@@ -32,8 +34,7 @@
 
     public DeviceLockedInputConsumer(Context context) {
         mContext = context;
-        float touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
-        mTouchSlopSquared = touchSlop * touchSlop;
+        mTouchSlopSquared = squaredTouchSlop(context);
     }
 
     @Override
@@ -48,9 +49,7 @@
         if (ev.getAction() == MotionEvent.ACTION_DOWN) {
             mTouchDown.set(x, y);
         } else if (ev.getAction() == MotionEvent.ACTION_MOVE) {
-            float xSquared = (x - mTouchDown.x) * (x - mTouchDown.x);
-            float ySquared = (y - mTouchDown.y) * (y - mTouchDown.y);
-            if (xSquared + ySquared > mTouchSlopSquared) {
+            if (squaredHypot(x - mTouchDown.x, y - mTouchDown.y) > mTouchSlopSquared) {
                 // For now, just start the home intent so user is prompted to unlock the device.
                 mContext.startActivity(new Intent(Intent.ACTION_MAIN)
                         .addCategory(Intent.CATEGORY_HOME)
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index eb5366c..b0acffa 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -23,6 +23,7 @@
 import static android.view.MotionEvent.ACTION_UP;
 import static android.view.MotionEvent.INVALID_POINTER_ID;
 import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
+import static com.android.launcher3.Utilities.squaredHypot;
 import static com.android.launcher3.uioverrides.RecentsUiFactory.ROTATION_LANDSCAPE;
 import static com.android.launcher3.uioverrides.RecentsUiFactory.ROTATION_SEASCAPE;
 import static com.android.launcher3.util.RaceConditionTracker.ENTER;
@@ -109,7 +110,7 @@
     private int mActivePointerId = INVALID_POINTER_ID;
 
     private final float mDragSlop;
-    private final float mTouchSlop;
+    private final float mSquaredTouchSlop;
 
     // Slop used to check when we start moving window.
     private boolean mPassedDragSlop;
@@ -157,7 +158,8 @@
 
         mDisplayRotation = getSystemService(WindowManager.class).getDefaultDisplay().getRotation();
         mDragSlop = QuickStepContract.getQuickStepDragSlopPx();
-        mTouchSlop = QuickStepContract.getQuickStepTouchSlopPx();
+        float slop = QuickStepContract.getQuickStepTouchSlopPx();
+        mSquaredTouchSlop = slop * slop;
 
         mPassedTouchSlop = mPassedDragSlop = continuingPreviousGesture;
     }
@@ -256,7 +258,7 @@
                 }
 
                 if (!mPassedTouchSlop) {
-                    if (Math.hypot(displacementX, mLastPos.y - mDownPos.y) >= mTouchSlop) {
+                    if (squaredHypot(displacementX, mLastPos.y - mDownPos.y) >= mSquaredTouchSlop) {
                         mPassedTouchSlop = true;
 
                         if (mIsDeferredDownTarget) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
index a835680..1e1007e 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
@@ -20,6 +20,8 @@
 import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_ICON_PARAMS;
 import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
 import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
+import static com.android.launcher3.Utilities.squaredHypot;
+import static com.android.launcher3.Utilities.squaredTouchSlop;
 import static com.android.launcher3.anim.Interpolators.ACCEL;
 import static com.android.launcher3.anim.Interpolators.ACCEL_2;
 import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
@@ -64,7 +66,6 @@
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewConfiguration;
 import android.view.ViewDebug;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
@@ -75,7 +76,6 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Insettable;
 import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAnimUtils.ViewProgressProperty;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.PagedView;
@@ -93,7 +93,6 @@
 import com.android.launcher3.util.PendingAnimation;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.util.ViewPool;
-import com.android.launcher3.views.FloatingIconView;
 import com.android.quickstep.RecentsAnimationWrapper;
 import com.android.quickstep.RecentsModel;
 import com.android.quickstep.RecentsModel.TaskThumbnailChangeListener;
@@ -281,7 +280,7 @@
     private boolean mHandleTaskStackChanges;
     private boolean mSwipeDownShouldLaunchApp;
     private boolean mTouchDownToStartHome;
-    private final int mTouchSlop;
+    private final float mSquaredTouchSlop;
     private int mDownX;
     private int mDownY;
 
@@ -306,8 +305,6 @@
     private Layout mEmptyTextLayout;
     private LiveTileOverlay mLiveTileOverlay;
 
-    private FloatingIconView mFloatingIconView;
-
     private BaseActivity.MultiWindowModeChangedListener mMultiWindowModeChangedListener =
             (inMultiWindowMode) -> {
         if (!inMultiWindowMode && mOverviewStateEnabled) {
@@ -339,7 +336,7 @@
         setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
         mTaskTopMargin = getResources()
                 .getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
-        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+        mSquaredTouchSlop = squaredTouchSlop(context);
 
         mEmptyIcon = context.getDrawable(R.drawable.ic_empty_recents);
         mEmptyIcon.setCallback(this);
@@ -496,7 +493,8 @@
             case MotionEvent.ACTION_MOVE:
                 // Passing the touch slop will not allow dismiss to home
                 if (mTouchDownToStartHome &&
-                        (isHandlingTouch() || Math.hypot(mDownX - x, mDownY - y) > mTouchSlop)) {
+                        (isHandlingTouch() ||
+                                squaredHypot(mDownX - x, mDownY - y) > mSquaredTouchSlop)) {
                     mTouchDownToStartHome = false;
                 }
                 break;
@@ -1684,12 +1682,6 @@
         }
     }
 
-    public FloatingIconView getFloatingIconView(Launcher launcher, View view, RectF iconLocation) {
-        mFloatingIconView = FloatingIconView.getFloatingIconView(launcher, view,
-                true /* hideOriginal */, iconLocation, false /* isOpening */, mFloatingIconView);
-        return  mFloatingIconView;
-    }
-
     public ClipAnimationHelper getTempClipAnimationHelper() {
         return mTempClipAnimationHelper;
     }
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index ecf1b0a..ba4ea8b 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -36,6 +36,7 @@
         android:importantForAccessibility="no" />
 
     <LinearLayout
+        android:id="@+id/task_footer_container"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:orientation="vertical"
@@ -43,7 +44,7 @@
         <FrameLayout
             android:id="@+id/proactive_suggest_container"
             android:layout_width="match_parent"
-            android:layout_height="36dp"
+            android:layout_height="48dp"
             android:gravity="center"
             android:visibility="gone"
             />
diff --git a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
index 91c4601..95ae312 100644
--- a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
@@ -142,7 +142,6 @@
     private final float mClosingWindowTransY;
 
     private DeviceProfile mDeviceProfile;
-    private FloatingIconView mFloatingView;
 
     private RemoteAnimationProvider mRemoteAnimationProvider;
 
@@ -411,15 +410,15 @@
     private ValueAnimator getOpeningWindowAnimators(View v, RemoteAnimationTargetCompat[] targets,
             Rect windowTargetBounds, boolean toggleVisibility) {
         RectF bounds = new RectF();
-        mFloatingView = FloatingIconView.getFloatingIconView(mLauncher, v, toggleVisibility,
-                bounds, true /* isOpening */, mFloatingView);
+        FloatingIconView floatingView = FloatingIconView.getFloatingIconView(mLauncher, v,
+                toggleVisibility, bounds, true /* isOpening */);
         Rect crop = new Rect();
         Matrix matrix = new Matrix();
 
         RemoteAnimationTargetSet openingTargets = new RemoteAnimationTargetSet(targets,
                 MODE_OPENING);
         SyncRtSurfaceTransactionApplierCompat surfaceApplier =
-                new SyncRtSurfaceTransactionApplierCompat(mFloatingView);
+                new SyncRtSurfaceTransactionApplierCompat(floatingView);
         openingTargets.addDependentTransactionApplier(surfaceApplier);
 
         // Scale the app icon to take up the entire screen. This simplifies the math when
@@ -463,7 +462,7 @@
         ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
         appAnimator.setDuration(APP_LAUNCH_DURATION);
         appAnimator.setInterpolator(LINEAR);
-        appAnimator.addListener(mFloatingView);
+        appAnimator.addListener(floatingView);
         appAnimator.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
@@ -557,7 +556,7 @@
                         } else {
                             currentBounds.bottom -= croppedHeight;
                         }
-                        mFloatingView.update(currentBounds, mIconAlpha.value, percent, 0f,
+                        floatingView.update(currentBounds, mIconAlpha.value, percent, 0f,
                                 cornerRadius * scale, true /* isOpening */);
                     } else {
                         matrix.setTranslate(target.position.x, target.position.y);
diff --git a/quickstep/src/com/android/quickstep/TestInformationProvider.java b/quickstep/src/com/android/quickstep/TestInformationProvider.java
index b37ddda..d96f9af 100644
--- a/quickstep/src/com/android/quickstep/TestInformationProvider.java
+++ b/quickstep/src/com/android/quickstep/TestInformationProvider.java
@@ -111,6 +111,14 @@
                     response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, (int) distance);
                     break;
                 }
+
+                case TestProtocol.REQUEST_ENABLE_DEBUG_TRACING:
+                    TestProtocol.sDebugTracing = true;
+                    break;
+
+                case TestProtocol.REQUEST_DISABLE_DEBUG_TRACING:
+                    TestProtocol.sDebugTracing = false;
+                    break;
             }
             return response;
         }
diff --git a/res/layout/floating_icon_view.xml b/res/layout/floating_icon_view.xml
new file mode 100644
index 0000000..240c486
--- /dev/null
+++ b/res/layout/floating_icon_view.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<com.android.launcher3.views.FloatingIconView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content" />
diff --git a/res/values/config.xml b/res/values/config.xml
index 83aea8b..984729b 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -86,7 +86,6 @@
 
     <!-- View IDs to store item highlight information -->
     <item type="id" name="view_unhighlight_background" />
-    <item type="id" name="view_highlighted" />
 
     <!-- Menu id for feature flags -->
     <item type="id" name="menu_apply_flags" />
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index 7f72242..424ffde 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -36,6 +36,7 @@
 import com.android.launcher3.uioverrides.UiFactory;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.launcher3.util.SystemUiController;
+import com.android.launcher3.util.ViewCache;
 import com.android.launcher3.views.ActivityContext;
 
 import java.io.FileDescriptor;
@@ -102,6 +103,12 @@
     // animation
     @InvisibilityFlags private int mForceInvisible;
 
+    private final ViewCache mViewCache = new ViewCache();
+
+    public ViewCache getViewCache() {
+        return mViewCache;
+    }
+
     @Override
     public DeviceProfile getDeviceProfile() {
         return mDeviceProfile;
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index ccd9e25..bd6ac90 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -134,6 +134,10 @@
 
     public boolean startActivitySafely(View v, Intent intent, @Nullable ItemInfo item,
             @Nullable String sourceContainer) {
+        if (com.android.launcher3.TestProtocol.sDebugTracing) {
+            android.util.Log.d(com.android.launcher3.TestProtocol.NO_START_TAG,
+                    "startActivitySafely 1");
+        }
         if (mIsSafeModeEnabled && !Utilities.isSystemApp(this, intent)) {
             Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
             return false;
@@ -157,6 +161,10 @@
                 startShortcutIntentSafely(intent, optsBundle, item, sourceContainer);
             } else if (user == null || user.equals(Process.myUserHandle())) {
                 // Could be launching some bookkeeping activity
+                if (com.android.launcher3.TestProtocol.sDebugTracing) {
+                    android.util.Log.d(com.android.launcher3.TestProtocol.NO_START_TAG,
+                            "startActivitySafely 2");
+                }
                 startActivity(intent, optsBundle);
                 AppLaunchTracker.INSTANCE.get(this).onStartApp(intent.getComponent(),
                         Process.myUserHandle(), sourceContainer);
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index bff7f42..2f801e0 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -51,7 +51,6 @@
 import com.android.launcher3.icons.DotRenderer;
 import com.android.launcher3.icons.IconCache.IconLoadRequest;
 import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver;
-import com.android.launcher3.icons.LauncherIcons;
 import com.android.launcher3.model.PackageItemInfo;
 import com.android.launcher3.views.ActivityContext;
 
@@ -561,7 +560,10 @@
                 }
             }
             if (itemInfo.contentDescription != null) {
-                if (hasDot()) {
+                if (itemInfo.isDisabled()) {
+                    setContentDescription(getContext().getString(R.string.disabled_app_label,
+                            itemInfo.contentDescription));
+                } else if (hasDot()) {
                     int count = mDotInfo.getNotificationCount();
                     setContentDescription(getContext().getResources().getQuantityString(
                             R.plurals.dotted_app_label, count, itemInfo.contentDescription, count));
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 40eb912..a59189b 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1782,6 +1782,10 @@
 
     public boolean startActivitySafely(View v, Intent intent, ItemInfo item,
             @Nullable String sourceContainer) {
+        if (com.android.launcher3.TestProtocol.sDebugTracing) {
+            android.util.Log.d(com.android.launcher3.TestProtocol.NO_START_TAG,
+                    "startActivitySafely outer");
+        }
         boolean success = super.startActivitySafely(v, intent, item, sourceContainer);
         if (success && v instanceof BubbleTextView) {
             // This is set to the view that launched the activity that navigated the user away
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java
index b1a3fc9..49ae338 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/LauncherStateManager.java
@@ -447,6 +447,10 @@
     }
 
     private void onStateTransitionStart(LauncherState state) {
+        if (com.android.launcher3.TestProtocol.sDebugTracing) {
+            android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
+                    "onStateTransitionStart");
+        }
         if (mState != state) {
             mState.onStateDisabled(mLauncher);
         }
@@ -572,6 +576,10 @@
         private final AnimatorSet mAnim;
 
         public StartAnimRunnable(AnimatorSet anim) {
+            if (com.android.launcher3.TestProtocol.sDebugTracing) {
+                android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
+                        "StartAnimRunnable");
+            }
             mAnim = anim;
         }
 
diff --git a/src/com/android/launcher3/ResourceUtils.java b/src/com/android/launcher3/ResourceUtils.java
index 8df3290..0c80d13 100644
--- a/src/com/android/launcher3/ResourceUtils.java
+++ b/src/com/android/launcher3/ResourceUtils.java
@@ -21,8 +21,10 @@
 import android.util.TypedValue;
 
 public class ResourceUtils {
-    public static final String NAVBAR_VERTICAL_SIZE = "navigation_bar_frame_height";
-    public static final String NAVBAR_HORIZONTAL_SIZE = "navigation_bar_width";
+    public static final String NAVBAR_PORTRAIT_BOTTOM_SIZE = "navigation_bar_frame_height";
+    public static final String NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE = "navigation_bar_width";
+    public static final String NAVBAR_LANDSCAPE_BOTTOM_SIZE
+            = "navigation_bar_frame_height_landscape";
 
     public static int getNavbarSize(String resName, Resources res) {
         return getDimenByName(resName, res, 48);
diff --git a/src/com/android/launcher3/TestProtocol.java b/src/com/android/launcher3/TestProtocol.java
index eefecda..a0440e8 100644
--- a/src/com/android/launcher3/TestProtocol.java
+++ b/src/com/android/launcher3/TestProtocol.java
@@ -64,4 +64,9 @@
             "all-apps-to-overview-swipe-height";
     public static final String REQUEST_HOME_TO_ALL_APPS_SWIPE_HEIGHT =
             "home-to-all-apps-swipe-height";
+    public static boolean sDebugTracing = false;
+    public static final String REQUEST_ENABLE_DEBUG_TRACING = "enable-debug-tracing";
+    public static final String REQUEST_DISABLE_DEBUG_TRACING = "disable-debug-tracing";
+    public static final String NO_DRAG_TAG = "b/133009122";
+    public static final String NO_START_TAG = "b/132900132";
 }
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 796fd25..cc9bda7 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -61,6 +61,7 @@
 import android.util.TypedValue;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewConfiguration;
 import android.view.animation.Interpolator;
 
 import com.android.launcher3.compat.LauncherAppsCompat;
@@ -726,6 +727,15 @@
         return str.toString();
     }
 
+    public static float squaredHypot(float x, float y) {
+        return x * x + y * y;
+    }
+
+    public static float squaredTouchSlop(Context context) {
+        float slop = ViewConfiguration.get(context).getScaledTouchSlop();
+        return slop * slop;
+    }
+
     private static class FixedSizeEmptyDrawable extends ColorDrawable {
 
         private final int mSize;
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index a508ce5..d19f9cd 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -371,6 +371,10 @@
 
     @Override
     public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
+        if (com.android.launcher3.TestProtocol.sDebugTracing) {
+            android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
+                    "onDragStart 1");
+        }
         if (ENFORCE_DRAG_EVENT_ORDER) {
             enforceDragParity("onDragStart", 0, 0);
         }
@@ -421,6 +425,10 @@
         }
 
         // Always enter the spring loaded mode
+        if (com.android.launcher3.TestProtocol.sDebugTracing) {
+            android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
+                    "onDragStart 2");
+        }
         mLauncher.getStateManager().goToState(SPRING_LOADED);
     }
 
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 41252aa..63682c7 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -41,6 +41,7 @@
 import com.android.launcher3.InsettableFrameLayout;
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
 import com.android.launcher3.R;
 import com.android.launcher3.TestProtocol;
 import com.android.launcher3.Utilities;
@@ -193,11 +194,18 @@
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
+
+        // The AllAppsContainerView houses the QSB and is hence visible from the Workspace
+        // Overview states. We shouldn't intercept for the scrubber in these cases.
+        if (!mLauncher.isInState(LauncherState.ALL_APPS)) return false;
+
         if (ev.getAction() == MotionEvent.ACTION_DOWN) {
             AllAppsRecyclerView rv = getActiveRecyclerView();
             if (rv != null &&
                     rv.getScrollbar().isHitInParent(ev.getX(), ev.getY(), mFastScrollerOffset)) {
                 mTouchHandler = rv.getScrollbar();
+            } else {
+                mTouchHandler = null;
             }
         }
         if (mTouchHandler != null) {
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index f92e00a..bf692fe 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -472,6 +472,10 @@
     }
 
     private void handleMoveEvent(int x, int y) {
+        if (com.android.launcher3.TestProtocol.sDebugTracing) {
+            android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
+                    "handleMoveEvent 1");
+        }
         mDragObject.dragView.move(x, y);
 
         // Drop on someone?
@@ -488,6 +492,10 @@
 
         if (mIsInPreDrag && mOptions.preDragCondition != null
                 && mOptions.preDragCondition.shouldStartDrag(mDistanceSinceScroll)) {
+            if (com.android.launcher3.TestProtocol.sDebugTracing) {
+                android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
+                        "handleMoveEvent 2");
+            }
             callOnDragStart();
         }
     }
@@ -525,6 +533,10 @@
      * Call this from a drag source view.
      */
     public boolean onControllerTouchEvent(MotionEvent ev) {
+        if (com.android.launcher3.TestProtocol.sDebugTracing) {
+            android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
+                    "onControllerTouchEvent");
+        }
         if (mDragDriver == null || mOptions == null || mOptions.isAccessibleDrag) {
             return false;
         }
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index 7af12c5..9d46cf2 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -44,7 +44,6 @@
 import com.android.launcher3.FastBitmapDrawable;
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherModel;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.LauncherStateManager;
@@ -55,6 +54,7 @@
 import com.android.launcher3.icons.LauncherIcons;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.util.Thunk;
+import com.android.launcher3.util.UiThreadHelper;
 
 import java.util.Arrays;
 
@@ -210,8 +210,7 @@
             return;
         }
         // Load the adaptive icon on a background thread and add the view in ui thread.
-        final Looper workerLooper = LauncherModel.getWorkerLooper();
-        new Handler(workerLooper).postAtFrontOfQueue(new Runnable() {
+        new Handler(UiThreadHelper.getBackgroundLooper()).postAtFrontOfQueue(new Runnable() {
             @Override
             public void run() {
                 Object[] outObj = new Object[1];
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 389e852..2ef6d70 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -593,6 +593,10 @@
     protected void handleClose(boolean animate) {
         mIsOpen = false;
 
+        if (!animate && mCurrentAnimator != null && mCurrentAnimator.isRunning()) {
+            mCurrentAnimator.cancel();
+        }
+
         if (isEditingName()) {
             mFolderName.dispatchBackKey();
         }
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index 8d9c520..250169c 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -102,7 +102,6 @@
     private List<BubbleTextView> mCurrentPreviewItems = new ArrayList<>();
 
     boolean mAnimating = false;
-    private Rect mTempBounds = new Rect();
 
     private float mSlop;
 
@@ -203,6 +202,10 @@
         mBackground.getBounds(outBounds);
     }
 
+    public float getBackgroundStrokeWidth() {
+        return mBackground.getStrokeWidth();
+    }
+
     public Folder getFolder() {
         return mFolder;
     }
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 047f486..7b14fa2 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -16,6 +16,8 @@
 
 package com.android.launcher3.popup;
 
+import static com.android.launcher3.Utilities.squaredHypot;
+import static com.android.launcher3.Utilities.squaredTouchSlop;
 import static com.android.launcher3.notification.NotificationMainView.NOTIFICATION_ITEM_INFO;
 import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS;
 import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS_IF_NOTIFICATIONS;
@@ -37,7 +39,6 @@
 import android.util.Pair;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.widget.ImageView;
 
@@ -51,6 +52,7 @@
 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;
@@ -136,8 +138,8 @@
             return true;
         }
         // Stop sending touch events to deep shortcut views if user moved beyond touch slop.
-        return Math.hypot(mInterceptTouchDown.x - ev.getX(), mInterceptTouchDown.y - ev.getY())
-                > ViewConfiguration.get(getContext()).getScaledTouchSlop();
+        return squaredHypot(mInterceptTouchDown.x - ev.getX(), mInterceptTouchDown.y - ev.getY())
+                > squaredTouchSlop(getContext());
     }
 
     @Override
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
index 0650001..99b9f25 100644
--- a/src/com/android/launcher3/touch/ItemClickHandler.java
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -66,14 +66,26 @@
     }
 
     private static void onClick(View v, String sourceContainer) {
+        if (com.android.launcher3.TestProtocol.sDebugTracing) {
+            android.util.Log.d(com.android.launcher3.TestProtocol.NO_START_TAG,
+                    "onClick 1");
+        }
         // Make sure that rogue clicks don't get through while allapps is launching, or after the
         // view has detached (it's possible for this to happen if the view is removed mid touch).
         if (v.getWindowToken() == null) {
+            if (com.android.launcher3.TestProtocol.sDebugTracing) {
+                android.util.Log.d(com.android.launcher3.TestProtocol.NO_START_TAG,
+                        "onClick 2");
+            }
             return;
         }
 
         Launcher launcher = Launcher.getLauncher(v.getContext());
         if (!launcher.getWorkspace().isFinishedSwitchingState()) {
+            if (com.android.launcher3.TestProtocol.sDebugTracing) {
+                android.util.Log.d(com.android.launcher3.TestProtocol.NO_START_TAG,
+                        "onClick 3");
+            }
             return;
         }
 
@@ -85,6 +97,10 @@
                 onClickFolderIcon(v);
             }
         } else if (tag instanceof AppInfo) {
+            if (com.android.launcher3.TestProtocol.sDebugTracing) {
+                android.util.Log.d(com.android.launcher3.TestProtocol.NO_START_TAG,
+                        "onClick 4");
+            }
             startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher,
                     sourceContainer == null ? CONTAINER_ALL_APPS: sourceContainer);
         } else if (tag instanceof LauncherAppWidgetInfo) {
@@ -216,6 +232,10 @@
 
     private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher,
             @Nullable String sourceContainer) {
+        if (com.android.launcher3.TestProtocol.sDebugTracing) {
+            android.util.Log.d(com.android.launcher3.TestProtocol.NO_START_TAG,
+                    "startAppShortcutOrInfoActivity");
+        }
         Intent intent;
         if (item instanceof PromiseAppInfo) {
             PromiseAppInfo promiseAppInfo = (PromiseAppInfo) item;
diff --git a/src/com/android/launcher3/util/ViewCache.java b/src/com/android/launcher3/util/ViewCache.java
new file mode 100644
index 0000000..08b8744
--- /dev/null
+++ b/src/com/android/launcher3/util/ViewCache.java
@@ -0,0 +1,73 @@
+/*
+ * 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.util;
+
+import android.content.Context;
+import android.util.SparseArray;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Utility class to cache views at an activity level
+ */
+public class ViewCache {
+
+    protected final SparseArray<CacheEntry> mCache = new SparseArray();
+
+    public void setCacheSize(int layoutId, int size) {
+        mCache.put(layoutId, new CacheEntry(size));
+    }
+
+    public <T extends View> T getView(int layoutId, Context context, ViewGroup parent) {
+        CacheEntry entry = mCache.get(layoutId);
+        if (entry == null) {
+            entry = new CacheEntry(1);
+            mCache.put(layoutId, entry);
+        }
+
+        if (entry.mCurrentSize > 0) {
+            entry.mCurrentSize --;
+            T result = (T) entry.mViews[entry.mCurrentSize];
+            entry.mViews[entry.mCurrentSize] = null;
+            return result;
+        }
+
+        return (T) LayoutInflater.from(context).inflate(layoutId, parent, false);
+    }
+
+    public void recycleView(int layoutId, View view) {
+        CacheEntry entry = mCache.get(layoutId);
+        if (entry != null && entry.mCurrentSize < entry.mMaxSize) {
+            entry.mViews[entry.mCurrentSize] = view;
+            entry.mCurrentSize++;
+        }
+    }
+
+    private static class CacheEntry {
+
+        final int mMaxSize;
+        final View[] mViews;
+
+        int mCurrentSize;
+
+        public CacheEntry(int maxSize) {
+            mMaxSize = maxSize;
+            mViews = new View[maxSize];
+            mCurrentSize = 0;
+        }
+    }
+}
diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java
index 3c81bcf..4964182 100644
--- a/src/com/android/launcher3/views/BaseDragLayer.java
+++ b/src/com/android/launcher3/views/BaseDragLayer.java
@@ -213,6 +213,10 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
+        if (com.android.launcher3.TestProtocol.sDebugTracing) {
+            android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
+                    "onTouchEvent " + ev);
+        }
         int action = ev.getAction();
         if (action == ACTION_UP || action == ACTION_CANCEL) {
             if (mTouchCompleteListener != null) {
@@ -222,6 +226,10 @@
         }
 
         if (mActiveController != null) {
+            if (com.android.launcher3.TestProtocol.sDebugTracing) {
+                android.util.Log.d(com.android.launcher3.TestProtocol.NO_DRAG_TAG,
+                        "onTouchEvent 1");
+            }
             return mActiveController.onControllerTouchEvent(ev);
         } else {
             // In case no child view handled the touch event, we may not get onIntercept anymore
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index e5c75c3..f63bcdd 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -27,6 +27,7 @@
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.annotation.TargetApi;
+import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Outline;
@@ -40,6 +41,7 @@
 import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.Looper;
+import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewOutlineProvider;
@@ -61,6 +63,7 @@
 import com.android.launcher3.icons.LauncherIcons;
 import com.android.launcher3.popup.SystemShortcut;
 import com.android.launcher3.shortcuts.DeepShortcutView;
+import com.android.launcher3.util.UiThreadHelper;
 
 import androidx.annotation.Nullable;
 import androidx.annotation.WorkerThread;
@@ -148,12 +151,20 @@
     private final SpringAnimation mFgSpringX;
     private float mFgTransX;
 
-    private FloatingIconView(Launcher launcher) {
-        super(launcher);
-        mLauncher = launcher;
+    public FloatingIconView(Context context) {
+        this(context, null);
+    }
+
+    public FloatingIconView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public FloatingIconView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mLauncher = Launcher.getLauncher(context);
         mBlurSizeOutline = getResources().getDimensionPixelSize(
                 R.dimen.blur_size_medium_outline);
-        mListenerView = new ListenerView(launcher, null);
+        mListenerView = new ListenerView(context, attrs);
 
         mFgSpringX = new SpringAnimation(this, mFgTransXProperty)
                 .setSpring(new SpringForce()
@@ -259,8 +270,6 @@
                 mFgSpringX.animateToFinalPosition(diffX);
                 mFgSpringY.animateToFinalPosition(diffY);
             }
-
-
         }
         invalidate();
         invalidateOutline();
@@ -352,6 +361,7 @@
     }
 
     @WorkerThread
+    @SuppressWarnings("WrongThread")
     private void getIcon(View v, ItemInfo info, boolean isOpening,
             Runnable onIconLoadedRunnable, CancellationSignal loadIconSignal) {
         final LayoutParams lp = (LayoutParams) getLayoutParams();
@@ -368,10 +378,13 @@
                 drawable = v.getBackground();
             }
         } else {
+            boolean isFolderIcon = v instanceof FolderIcon;
+            int width = isFolderIcon ? v.getWidth() : lp.width;
+            int height = isFolderIcon ? v.getHeight() : lp.height;
             if (supportsAdaptiveIcons) {
-                drawable = Utilities.getFullDrawable(mLauncher, info, lp.width, lp.height,
-                        false, sTmpObjArray);
-                if ((drawable instanceof AdaptiveIconDrawable)) {
+                drawable = Utilities.getFullDrawable(mLauncher, info, width, height, false,
+                        sTmpObjArray);
+                if (drawable instanceof AdaptiveIconDrawable) {
                     mBadge = getBadge(mLauncher, info, sTmpObjArray[0]);
                 } else {
                     // The drawable we get back is not an adaptive icon, so we need to use the
@@ -383,8 +396,8 @@
                     // Similar to DragView, we simply use the BubbleTextView icon here.
                     drawable = btvIcon;
                 } else {
-                    drawable = Utilities.getFullDrawable(mLauncher, info, lp.width, lp.height,
-                            false, sTmpObjArray);
+                    drawable = Utilities.getFullDrawable(mLauncher, info, width, height, false,
+                            sTmpObjArray);
                 }
             }
         }
@@ -395,7 +408,7 @@
                 && finalDrawable instanceof AdaptiveIconDrawable;
         int iconOffset = getOffsetForIconBounds(finalDrawable);
 
-        new Handler(Looper.getMainLooper()).post(() -> {
+        mLauncher.getMainExecutor().execute(() -> {
             if (isAdaptiveIcon) {
                 mIsAdaptiveIcon = true;
                 boolean isFolderIcon = finalDrawable instanceof FolderAdaptiveIcon;
@@ -412,13 +425,6 @@
                 }
                 mForeground = foreground;
 
-                if (mForeground instanceof ShiftedBitmapDrawable && v instanceof FolderIcon) {
-                    ShiftedBitmapDrawable sbd = (ShiftedBitmapDrawable) mForeground;
-                    ((FolderIcon) v).getPreviewBounds(sTmpRect);
-                    sbd.setShiftX(sbd.getShiftX() - sTmpRect.left);
-                    sbd.setShiftY(sbd.getShiftY() - sTmpRect.top);
-                }
-
                 final int originalHeight = lp.height;
                 final int originalWidth = lp.width;
 
@@ -434,13 +440,25 @@
 
                 if (mBadge != null) {
                     mBadge.setBounds(mStartRevealRect);
-                    if (!isOpening) {
+                    if (!isOpening && !isFolderIcon) {
                         DRAWABLE_ALPHA.set(mBadge, 0);
                     }
-
                 }
 
-                if (!isFolderIcon) {
+                if (isFolderIcon) {
+                    ((FolderIcon) v).getPreviewBounds(sTmpRect);
+                    float bgStroke = ((FolderIcon) v).getBackgroundStrokeWidth();
+                    if (mForeground instanceof ShiftedBitmapDrawable) {
+                        ShiftedBitmapDrawable sbd = (ShiftedBitmapDrawable) mForeground;
+                        sbd.setShiftX(sbd.getShiftX() - sTmpRect.left - bgStroke);
+                        sbd.setShiftY(sbd.getShiftY() - sTmpRect.top - bgStroke);
+                    }
+                    if (mBadge instanceof ShiftedBitmapDrawable) {
+                        ShiftedBitmapDrawable sbd = (ShiftedBitmapDrawable) mBadge;
+                        sbd.setShiftX(sbd.getShiftX() - sTmpRect.left - bgStroke);
+                        sbd.setShiftY(sbd.getShiftY() - sTmpRect.top - bgStroke);
+                    }
+                } else {
                     Utilities.scaleRectAboutCenter(mStartRevealRect,
                             IconShape.getNormalizationScale());
                 }
@@ -475,6 +493,7 @@
                 setClipToOutline(true);
             } else {
                 setBackground(finalDrawable);
+                setClipToOutline(false);
             }
 
             if (!loadIconSignal.isCanceled()) {
@@ -498,6 +517,7 @@
     }
 
     @WorkerThread
+    @SuppressWarnings("WrongThread")
     private int getOffsetForIconBounds(Drawable drawable) {
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O ||
                 !(drawable instanceof AdaptiveIconDrawable)) {
@@ -508,7 +528,7 @@
         Rect bounds = new Rect(0, 0, lp.width + mBlurSizeOutline, lp.height + mBlurSizeOutline);
         bounds.inset(mBlurSizeOutline / 2, mBlurSizeOutline / 2);
 
-        try (LauncherIcons li = LauncherIcons.obtain(getContext())) {
+        try (LauncherIcons li = LauncherIcons.obtain(mLauncher)) {
             Utilities.scaleRectAboutCenter(bounds, li.getNormalizer().getScale(drawable, null));
         }
 
@@ -597,11 +617,14 @@
      * @param isOpening True if this view replaces the icon for app open animation.
      */
     public static FloatingIconView getFloatingIconView(Launcher launcher, View originalView,
-            boolean hideOriginal, RectF positionOut, boolean isOpening, FloatingIconView recycle) {
-        if (recycle != null) {
-            recycle.recycle();
-        }
-        FloatingIconView view = recycle != null ? recycle : new FloatingIconView(launcher);
+            boolean hideOriginal, RectF positionOut, boolean isOpening) {
+        final DragLayer dragLayer = launcher.getDragLayer();
+        ViewGroup parent = (ViewGroup) dragLayer.getParent();
+
+        FloatingIconView view = launcher.getViewCache().getView(R.layout.floating_icon_view,
+                launcher, parent);
+        view.recycle();
+
         view.mIsVerticalBarLayout = launcher.getDeviceProfile().isVerticalBarLayout();
 
         view.mOriginalIcon = originalView;
@@ -619,16 +642,15 @@
                 originalView.setVisibility(INVISIBLE);
             };
             CancellationSignal loadIconSignal = view.mLoadIconSignal;
-            new Handler(LauncherModel.getWorkerLooper()).postAtFrontOfQueue(() -> {
+            new Handler(UiThreadHelper.getBackgroundLooper()).postAtFrontOfQueue(() -> {
                 view.getIcon(originalView, (ItemInfo) originalView.getTag(), isOpening,
                         onIconLoaded, loadIconSignal);
             });
         }
 
         // We need to add it to the overlay, but keep it invisible until animation starts..
-        final DragLayer dragLayer = launcher.getDragLayer();
         view.setVisibility(INVISIBLE);
-        ((ViewGroup) dragLayer.getParent()).addView(view);
+        parent.addView(view);
         dragLayer.addView(view.mListenerView);
         view.mListenerView.setListener(view::onListenerViewClosed);
 
@@ -665,7 +687,7 @@
             }
         });
 
-        if (mBadge != null) {
+        if (mBadge != null && !(mOriginalIcon instanceof FolderIcon)) {
             ObjectAnimator badgeFade = ObjectAnimator.ofInt(mBadge, DRAWABLE_ALPHA, 255);
             badgeFade.addUpdateListener(valueAnimator -> invalidate());
             fade.play(badgeFade);
@@ -691,7 +713,6 @@
                 @Override
                 public void onAnimationEnd(Animator animation) {
                     folderIcon.setBackgroundVisible(true);
-                    folderIcon.animateBgShadowAndStroke();
                     if (folderIcon.hasDot()) {
                         folderIcon.animateDotScale(0, 1f);
                     }
@@ -708,6 +729,7 @@
         ((ViewGroup) dragLayer.getParent()).removeView(this);
         dragLayer.removeView(mListenerView);
         recycle();
+        mLauncher.getViewCache().recycleView(R.layout.floating_icon_view, this);
     }
 
     private void recycle() {
@@ -746,5 +768,6 @@
         mFgTransX = 0;
         mFgSpringY.cancel();
         mBadge = null;
+        sTmpObjArray[0] = null;
     }
 }
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index ca6d968..74cece8 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -243,7 +243,7 @@
      */
     protected UiObject2 scrollAndFind(UiObject2 container, BySelector condition) {
         final int margin = ResourceUtils.getNavbarSize(
-                ResourceUtils.NAVBAR_VERTICAL_SIZE, mLauncher.getResources()) + 1;
+                ResourceUtils.NAVBAR_PORTRAIT_BOTTOM_SIZE, mLauncher.getResources()) + 1;
         container.setGestureMargins(0, 0, 0, margin);
 
         int i = 0;
diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
index a296975..70405fe 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -18,6 +18,7 @@
 
 import static com.android.launcher3.tapl.LauncherInstrumentation.NavigationModel.ZERO_BUTTON;
 
+import android.graphics.Point;
 import android.graphics.Rect;
 
 import androidx.annotation.NonNull;
@@ -48,12 +49,34 @@
         return LauncherInstrumentation.ContainerType.ALL_APPS;
     }
 
-    private boolean hasClickableIcon(UiObject2 allAppsContainer, BySelector appIconSelector) {
-        final UiObject2 icon = allAppsContainer.findObject(appIconSelector);
-        if (icon == null) return false;
-        if (mLauncher.getNavigationModel() == ZERO_BUTTON) return true;
-        final UiObject2 navBar = mLauncher.waitForSystemUiObject("navigation_bar_frame");
-        return icon.getVisibleBounds().bottom < navBar.getVisibleBounds().top;
+    private boolean hasClickableIcon(
+            UiObject2 allAppsContainer, UiObject2 appListRecycler, BySelector appIconSelector) {
+        final UiObject2 icon = appListRecycler.findObject(appIconSelector);
+        if (icon == null) {
+            LauncherInstrumentation.log("hasClickableIcon: icon not visible");
+            return false;
+        }
+        final Rect iconBounds = icon.getVisibleBounds();
+        LauncherInstrumentation.log("hasClickableIcon: icon bounds: " + iconBounds);
+        if (mLauncher.getNavigationModel() != ZERO_BUTTON) {
+            final UiObject2 navBar = mLauncher.waitForSystemUiObject("navigation_bar_frame");
+            if (iconBounds.bottom >= navBar.getVisibleBounds().top) {
+                LauncherInstrumentation.log("hasClickableIcon: icon intersects with nav bar");
+                return false;
+            }
+        }
+        if (iconCenterInSearchBox(allAppsContainer, icon)) {
+            LauncherInstrumentation.log("hasClickableIcon: icon center is under search box");
+            return false;
+        }
+        LauncherInstrumentation.log("hasClickableIcon: icon is clickable");
+        return true;
+    }
+
+    private boolean iconCenterInSearchBox(UiObject2 allAppsContainer, UiObject2 icon) {
+        final Point iconCenter = icon.getVisibleCenter();
+        return getSearchBox(allAppsContainer).getVisibleBounds().contains(
+                iconCenter.x, iconCenter.y);
     }
 
     /**
@@ -66,17 +89,22 @@
     @NonNull
     public AppIcon getAppIcon(String appName) {
         try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
-                "want to get app icon on all apps")) {
+                "want to get app icon " + appName + " on all apps")) {
             final UiObject2 allAppsContainer = verifyActiveContainer();
-            allAppsContainer.setGestureMargins(0, 0, 0,
-                    ResourceUtils.getNavbarSize(ResourceUtils.NAVBAR_VERTICAL_SIZE,
+            final UiObject2 appListRecycler = mLauncher.waitForObjectInContainer(allAppsContainer,
+                    "apps_list_view");
+            allAppsContainer.setGestureMargins(
+                    0,
+                    getSearchBox(allAppsContainer).getVisibleBounds().bottom + 1,
+                    0,
+                    ResourceUtils.getNavbarSize(ResourceUtils.NAVBAR_PORTRAIT_BOTTOM_SIZE,
                             mLauncher.getResources()) + 1);
             final BySelector appIconSelector = AppIcon.getAppIconSelector(appName, mLauncher);
-            if (!hasClickableIcon(allAppsContainer, appIconSelector)) {
+            if (!hasClickableIcon(allAppsContainer, appListRecycler, appIconSelector)) {
                 scrollBackToBeginning();
                 int attempts = 0;
                 try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("scrolled")) {
-                    while (!hasClickableIcon(allAppsContainer, appIconSelector) &&
+                    while (!hasClickableIcon(allAppsContainer, appListRecycler, appIconSelector) &&
                             allAppsContainer.scroll(Direction.DOWN, 0.8f)) {
                         mLauncher.assertTrue(
                                 "Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS,
@@ -89,7 +117,7 @@
 
             final UiObject2 appIcon = mLauncher.getObjectInContainer(allAppsContainer,
                     appIconSelector);
-            ensureIconVisible(appIcon, allAppsContainer);
+            ensureIconVisible(appIcon, allAppsContainer, appListRecycler);
             return new AppIcon(mLauncher, appIcon);
         }
     }
@@ -97,10 +125,9 @@
     private void scrollBackToBeginning() {
         try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
                 "want to scroll back in all apps")) {
+            LauncherInstrumentation.log("Scrolling to the beginning");
             final UiObject2 allAppsContainer = verifyActiveContainer();
-            final UiObject2 searchBox =
-                    mLauncher.waitForObjectInContainer(allAppsContainer,
-                            "search_container_all_apps");
+            final UiObject2 searchBox = getSearchBox(allAppsContainer);
 
             int attempts = 0;
             final Rect margins = new Rect(0, searchBox.getVisibleBounds().bottom + 1, 0, 5);
@@ -128,19 +155,26 @@
                 getInt(TestProtocol.SCROLL_Y_FIELD, -1);
     }
 
-    private void ensureIconVisible(UiObject2 appIcon, UiObject2 allAppsContainer) {
+    private void ensureIconVisible(
+            UiObject2 appIcon, UiObject2 allAppsContainer, UiObject2 appListRecycler) {
         final int appHeight = appIcon.getVisibleBounds().height();
         if (appHeight < MIN_INTERACT_SIZE) {
             // Try to figure out how much percentage of the container needs to be scrolled in order
             // to reveal the app icon to have the MIN_INTERACT_SIZE
             final float pct = Math.max(((float) (MIN_INTERACT_SIZE - appHeight)) / mHeight, 0.2f);
-            mLauncher.scroll(allAppsContainer, Direction.DOWN, pct, null, 10);
+            mLauncher.scroll(appListRecycler, Direction.DOWN, pct, null, 10);
             try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
                     "scrolled an icon in all apps to make it visible - and then")) {
                 mLauncher.waitForIdle();
                 verifyActiveContainer();
             }
         }
+        mLauncher.assertTrue("Couldn't scroll app icon to not intersect with the search box",
+                !iconCenterInSearchBox(allAppsContainer, appIcon));
+    }
+
+    private UiObject2 getSearchBox(UiObject2 allAppsContainer) {
+        return mLauncher.waitForObjectInContainer(allAppsContainer, "search_container_all_apps");
     }
 
     /**
diff --git a/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java b/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java
index c3b671b..a472d31 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java
@@ -53,9 +53,9 @@
                     TestProtocol.REQUEST_ALL_APPS_TO_OVERVIEW_SWIPE_HEIGHT).
                     getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
 
-            final int endY = start.y + swipeHeight + mLauncher.getTouchSlop();
+            final int endY = start.y + swipeHeight;
             LauncherInstrumentation.log("AllAppsFromOverview.switchBackToOverview before swipe");
-            mLauncher.swipe(start.x, start.y, start.x, endY, OVERVIEW_STATE_ORDINAL);
+            mLauncher.swipeToState(start.x, start.y, start.x, endY, 60, OVERVIEW_STATE_ORDINAL);
 
             try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("swiped down")) {
                 return new Overview(mLauncher);
diff --git a/tests/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java
index 8f5e7fe..55e14cc 100644
--- a/tests/tapl/com/android/launcher3/tapl/Background.java
+++ b/tests/tapl/com/android/launcher3/tapl/Background.java
@@ -86,9 +86,10 @@
                 final int swipeHeight = mLauncher.getTestInfo(getSwipeHeightRequestName()).
                         getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
 
-                mLauncher.swipe(
+                mLauncher.swipeToState(
                         centerX, startY, centerX,
                         startY - swipeHeight - mLauncher.getTouchSlop(),
+                        60,
                         expectedState);
                 break;
             }
diff --git a/tests/tapl/com/android/launcher3/tapl/Launchable.java b/tests/tapl/com/android/launcher3/tapl/Launchable.java
index 1b372ec..3295ddb 100644
--- a/tests/tapl/com/android/launcher3/tapl/Launchable.java
+++ b/tests/tapl/com/android/launcher3/tapl/Launchable.java
@@ -24,6 +24,8 @@
 import androidx.test.uiautomator.UiObject2;
 import androidx.test.uiautomator.Until;
 
+import com.android.launcher3.TestProtocol;
+
 /**
  * Ancestor for AppIcon and AppMenuItem.
  */
@@ -51,9 +53,11 @@
     private Background launch(BySelector selector) {
         LauncherInstrumentation.log("Launchable.launch before click " +
                 mObject.getVisibleCenter());
+        mLauncher.getTestInfo(TestProtocol.REQUEST_ENABLE_DEBUG_TRACING);
         mLauncher.assertTrue(
                 "Launching an app didn't open a new window: " + mObject.getText(),
                 mObject.clickAndWait(Until.newWindow(), LauncherInstrumentation.WAIT_TIME_MS));
+        mLauncher.getTestInfo(TestProtocol.REQUEST_DISABLE_DEBUG_TRACING);
         mLauncher.assertTrue(
                 "App didn't start: " + selector,
                 mLauncher.getDevice().wait(Until.hasObject(selector),
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 57fd4b9..a4711f5 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -584,18 +584,15 @@
         return mDevice;
     }
 
-    void swipe(int startX, int startY, int endX, int endY, int expectedState) {
-        swipe(startX, startY, endX, endY, expectedState, 60);
-    }
-
-    void swipe(int startX, int startY, int endX, int endY, int expectedState, int steps) {
-        changeStateViaGesture(startX, startY, endX, endY, expectedState,
-                () -> mDevice.swipe(startX, startY, endX, endY, steps));
-    }
-
     void swipeToState(int startX, int startY, int endX, int endY, int steps, int expectedState) {
-        changeStateViaGesture(startX, startY, endX, endY, expectedState,
-                () -> linearGesture(startX, startY, endX, endY, steps));
+        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);
+        assertEquals("Swipe switched launcher to a wrong state;",
+                TestProtocol.stateOrdinalToString(expectedState),
+                TestProtocol.stateOrdinalToString(parcel.getInt(TestProtocol.STATE_FIELD)));
     }
 
     void scroll(UiObject2 container, Direction direction, float percent, Rect margins, int steps) {
@@ -652,18 +649,6 @@
         sendPointer(downTime, endTime, MotionEvent.ACTION_UP, end);
     }
 
-    private void changeStateViaGesture(int startX, int startY, int endX, int endY,
-            int expectedState, Runnable gesture) {
-        final Bundle parcel = (Bundle) executeAndWaitForEvent(
-                gesture,
-                event -> TestProtocol.SWITCHED_TO_STATE_MESSAGE.equals(event.getClassName()),
-                "Swipe failed to receive an event for the swipe end: " + startX + ", " + startY
-                        + ", " + endX + ", " + endY);
-        assertEquals("Swipe switched launcher to a wrong state;",
-                TestProtocol.stateOrdinalToString(expectedState),
-                TestProtocol.stateOrdinalToString(parcel.getInt(TestProtocol.STATE_FIELD)));
-    }
-
     void waitForIdle() {
         mDevice.waitForIdle();
     }
diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java
index f7e0b6c..b780df4 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widgets.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java
@@ -41,7 +41,7 @@
             LauncherInstrumentation.log("Widgets.flingForward enter");
             final UiObject2 widgetsContainer = verifyActiveContainer();
             widgetsContainer.setGestureMargins(0, 0, 0,
-                    ResourceUtils.getNavbarSize(ResourceUtils.NAVBAR_VERTICAL_SIZE,
+                    ResourceUtils.getNavbarSize(ResourceUtils.NAVBAR_PORTRAIT_BOTTOM_SIZE,
                             mLauncher.getResources()) + 1);
             widgetsContainer.fling(Direction.DOWN,
                     (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 11c0794..10b253d 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -148,6 +148,7 @@
     static void dragIconToWorkspace(
             LauncherInstrumentation launcher, Launchable launchable, Point dest,
             String longPressIndicator) {
+        launcher.getTestInfo(TestProtocol.REQUEST_ENABLE_DEBUG_TRACING);
         LauncherInstrumentation.log("dragIconToWorkspace: begin");
         final Point launchableCenter = launchable.getObject().getVisibleCenter();
         final long downTime = SystemClock.uptimeMillis();
@@ -162,6 +163,7 @@
                 downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, dest);
         LauncherInstrumentation.log("dragIconToWorkspace: end");
         launcher.waitUntilGone("drop_target_bar");
+        launcher.getTestInfo(TestProtocol.REQUEST_DISABLE_DEBUG_TRACING);
     }
 
     /**