Merge "Polish search result icons" into ub-launcher3-master
diff --git a/quickstep/robolectric_tests/src/com/android/quickstep/util/RecentsOrientedStateTest.java b/quickstep/robolectric_tests/src/com/android/quickstep/util/RecentsOrientedStateTest.java
new file mode 100644
index 0000000..656379f
--- /dev/null
+++ b/quickstep/robolectric_tests/src/com/android/quickstep/util/RecentsOrientedStateTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2020 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.quickstep.util;
+
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_180;
+import static android.view.Surface.ROTATION_90;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.content.Context;
+
+import com.android.quickstep.FallbackActivityInterface;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.LooperMode;
+import org.robolectric.annotation.LooperMode.Mode;
+
+/**
+ * Tests for {@link RecentsOrientedState}
+ */
+@RunWith(RobolectricTestRunner.class)
+@LooperMode(Mode.PAUSED)
+public class RecentsOrientedStateTest {
+
+    private RecentsOrientedState mR1, mR2;
+
+    @Before
+    public void setup() {
+        Context context = RuntimeEnvironment.application;
+        mR1 = new RecentsOrientedState(context, FallbackActivityInterface.INSTANCE, i -> { });
+        mR2 = new RecentsOrientedState(context, FallbackActivityInterface.INSTANCE, i -> { });
+        assertEquals(mR1.getStateId(), mR2.getStateId());
+    }
+
+    @Test
+    public void stateId_changesWithFlags() {
+        mR1.setGestureActive(true);
+        mR2.setGestureActive(false);
+        assertNotEquals(mR1.getStateId(), mR2.getStateId());
+
+        mR2.setGestureActive(true);
+        assertEquals(mR1.getStateId(), mR2.getStateId());
+    }
+
+    @Test
+    public void stateId_changesWithRecentsRotation() {
+        mR1.setRecentsRotation(ROTATION_90);
+        mR2.setRecentsRotation(ROTATION_180);
+        assertNotEquals(mR1.getStateId(), mR2.getStateId());
+
+        mR2.setRecentsRotation(ROTATION_90);
+        assertEquals(mR1.getStateId(), mR2.getStateId());
+    }
+
+    @Test
+    public void stateId_changesWithDisplayRotation() {
+        mR1.update(ROTATION_0, ROTATION_90);
+        mR2.update(ROTATION_0, ROTATION_180);
+        assertNotEquals(mR1.getStateId(), mR2.getStateId());
+
+        mR2.update(ROTATION_90, ROTATION_90);
+        assertNotEquals(mR1.getStateId(), mR2.getStateId());
+
+        mR2.update(ROTATION_90, ROTATION_0);
+        assertNotEquals(mR1.getStateId(), mR2.getStateId());
+
+        mR2.update(ROTATION_0, ROTATION_90);
+        assertEquals(mR1.getStateId(), mR2.getStateId());
+    }
+}
diff --git a/quickstep/robolectric_tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java b/quickstep/robolectric_tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
index 6c88e55..688f323 100644
--- a/quickstep/robolectric_tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
+++ b/quickstep/robolectric_tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
@@ -148,7 +148,7 @@
             if (mAppRotation < 0) {
                 mAppRotation = launcherRotation;
             }
-            tvs.setLayoutRotation(launcherRotation, mAppRotation);
+            tvs.getOrientationState().update(launcherRotation, mAppRotation);
             if (mAppInsets == null) {
                 mAppInsets = new Rect(mLauncherInsets);
             }
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 43c088b..041f679 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -378,7 +378,7 @@
         if (mStateCallback.hasStates(STATE_HANDLER_INVALIDATED)) {
             return;
         }
-        mTaskViewSimulator.setRecentsRotation(mActivity.getDisplay().getRotation());
+        mTaskViewSimulator.setOrientationState(mRecentsView.getPagedViewOrientedState());
 
         // If we've already ended the gesture and are going home, don't prepare recents UI,
         // as that will set the state as BACKGROUND_APP, overriding the animation to NORMAL.
@@ -686,6 +686,7 @@
             dp.updateInsets(targets.homeContentInsets);
             dp.updateIsSeascape(mContext);
             initTransitionEndpoints(dp);
+            mTaskViewSimulator.getOrientationState().setMultiWindowMode(dp.isMultiWindowMode);
         }
 
         // Notify when the animation starts
diff --git a/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java b/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java
index 55f5424..efd4530 100644
--- a/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java
+++ b/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java
@@ -132,9 +132,8 @@
 
         TaskViewSimulator tsv = new TaskViewSimulator(mActivity, mRecentsView.getSizeStrategy());
         tsv.setDp(mActivity.getDeviceProfile());
+        tsv.setOrientationState(mRecentsView.getPagedViewOrientedState());
         tsv.setPreview(runningTaskTarget);
-        tsv.setLayoutRotation(mRecentsView.getPagedViewOrientedState().getTouchRotation(),
-                mRecentsView.getPagedViewOrientedState().getDisplayRotation());
 
         TransformParams params = new TransformParams()
                 .setTargetSet(targets)
diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
index 8f7ec3b..4bb1bb5 100644
--- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
+++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
@@ -79,7 +79,7 @@
         mTaskViewSimulator = new TaskViewSimulator(context, gestureState.getActivityInterface());
         mTransformParams = transformParams;
 
-        mTaskViewSimulator.setLayoutRotation(
+        mTaskViewSimulator.getOrientationState().update(
                 mDeviceState.getRotationTouchHelper().getCurrentActiveRotation(),
                 mDeviceState.getRotationTouchHelper().getDisplayRotation());
         mTaskViewSimulator.setDrawsBelowRecents(true);
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index ed761cf..2aed76a 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -179,16 +179,17 @@
 
         Context context = v.getContext();
         DeviceProfile dp = BaseActivity.fromContext(context).getDeviceProfile();
-        // RecentsView never updates the display rotation until swipe-up so the value may be stale.
-        // Use the display value instead.
-        int displayRotation = DisplayController.getDefaultDisplay(context).getInfo().rotation;
-
         TaskViewSimulator topMostSimulator = null;
 
         if (tsv == null && targets.apps.length > 0) {
             tsv = new TaskViewSimulator(context, recentsView.getSizeStrategy());
             tsv.setDp(dp);
-            tsv.setLayoutRotation(displayRotation, displayRotation);
+
+            // RecentsView never updates the display rotation until swipe-up so the value may
+            // be stale. Use the display value instead.
+            int displayRotation = DisplayController.getDefaultDisplay(context).getInfo().rotation;
+            tsv.getOrientationState().update(displayRotation, displayRotation);
+
             tsv.setPreview(targets.apps[targets.apps.length - 1]);
             tsv.fullScreenProgress.value = 0;
             tsv.recentsViewScale.value = 1;
diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
index bb84380..e273aeb 100644
--- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
+++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
@@ -72,7 +72,6 @@
 
     private static final String TAG = "RecentsOrientedState";
     private static final boolean DEBUG = false;
-    private static final String DELIMITER_DOT = "\\.";
 
     private ContentObserver mSystemAutoRotateObserver =
             newContentObserver(new Handler(), t -> updateAutoRotateSetting());
@@ -129,6 +128,9 @@
     private int mFlags;
     private int mPreviousRotation = ROTATION_0;
 
+    // Combined int which encodes the full state.
+    private int mStateId = 0;
+
     /**
      * @param rotationChangeListener Callback for receiving rotation events when rotation watcher
      *                              is enabled
@@ -169,7 +171,7 @@
      */
     public boolean setRecentsRotation(@SurfaceRotation int recentsRotation) {
         mRecentsRotation = recentsRotation;
-        return update(mTouchRotation, mDisplayRotation);
+        return updateHandler();
     }
 
     /**
@@ -183,8 +185,7 @@
      * Sets if the swipe up gesture is currently running or not
      */
     public boolean setGestureActive(boolean isGestureActive) {
-        setFlag(FLAG_SWIPE_UP_NOT_RUNNING, !isGestureActive);
-        return update(mTouchRotation, mDisplayRotation);
+        return setFlag(FLAG_SWIPE_UP_NOT_RUNNING, !isGestureActive);
     }
 
     /**
@@ -201,14 +202,13 @@
         mDisplayRotation = displayRotation;
         mTouchRotation = touchRotation;
         mPreviousRotation = touchRotation;
+        return updateHandler();
+    }
 
-        PagedOrientationHandler oldHandler = mOrientationHandler;
+    private boolean updateHandler() {
         if (mRecentsActivityRotation == mTouchRotation
                 || (canRecentsActivityRotate() && (mFlags & FLAG_SWIPE_UP_NOT_RUNNING) != 0)) {
             mOrientationHandler = PagedOrientationHandler.PORTRAIT;
-            if (DEBUG) {
-                Log.d(TAG, "current RecentsOrientedState: " + this);
-            }
         } else if (mTouchRotation == ROTATION_90) {
             mOrientationHandler = PagedOrientationHandler.LANDSCAPE;
         } else if (mTouchRotation == ROTATION_270) {
@@ -219,19 +219,26 @@
         if (DEBUG) {
             Log.d(TAG, "current RecentsOrientedState: " + this);
         }
-        return oldHandler != mOrientationHandler;
+
+        int oldStateId = mStateId;
+        // Each SurfaceRotation value takes two bits
+        mStateId = (((((mFlags << 2)
+                | mDisplayRotation) << 2)
+                | mTouchRotation) << 3)
+                | (mRecentsRotation < 0 ? 7 : mRecentsRotation);
+        return mStateId != oldStateId;
     }
 
     @SurfaceRotation
     private int inferRecentsActivityRotation(@SurfaceRotation int displayRotation) {
         if (isRecentsActivityRotationAllowed()) {
-            return mRecentsRotation < ROTATION_0 ? displayRotation : mRecentsRotation;
+            return mRecentsRotation < 0 ? displayRotation : mRecentsRotation;
         } else {
             return ROTATION_0;
         }
     }
 
-    private void setFlag(int mask, boolean enabled) {
+    private boolean setFlag(int mask, boolean enabled) {
         boolean wasRotationEnabled = !TestProtocol.sDisableSensorRotation
                 && (mFlags & VALUE_ROTATION_WATCHER_ENABLED) == VALUE_ROTATION_WATCHER_ENABLED
                 && !canRecentsActivityRotate();
@@ -253,6 +260,7 @@
                 }
             });
         }
+        return updateHandler();
     }
 
     @Override
@@ -327,6 +335,13 @@
         return mRecentsActivityRotation;
     }
 
+    /**
+     * Returns an id that can be used to tracking internal changes
+     */
+    public int getStateId() {
+        return mStateId;
+    }
+
     public boolean isMultipleOrientationSupportedByDevice() {
         return (mFlags & MASK_MULTIPLE_ORIENTATION_SUPPORTED_BY_DEVICE)
                 == MASK_MULTIPLE_ORIENTATION_SUPPORTED_BY_DEVICE;
@@ -509,14 +524,15 @@
     public String toString() {
         boolean systemRotationOn = (mFlags & FLAG_SYSTEM_ROTATION_ALLOWED) != 0;
         return "["
-                + "this=" + extractObjectNameAndAddress(super.toString())
-                + " mOrientationHandler=" +
-                    extractObjectNameAndAddress(mOrientationHandler.toString())
+                + "this=" + nameAndAddress(this)
+                + " mOrientationHandler=" + nameAndAddress(mOrientationHandler)
                 + " mDisplayRotation=" + mDisplayRotation
                 + " mTouchRotation=" + mTouchRotation
                 + " mRecentsActivityRotation=" + mRecentsActivityRotation
+                + " mRecentsRotation=" + mRecentsRotation
                 + " isRecentsActivityRotationAllowed=" + isRecentsActivityRotationAllowed()
                 + " mSystemRotation=" + systemRotationOn
+                + " mStateId=" + mStateId
                 + " mFlags=" + mFlags
                 + "]";
     }
@@ -533,13 +549,7 @@
                 : idp.portraitProfile;
     }
 
-    /**
-     * String conversion for only the helpful parts of {@link Object#toString()} method
-     * @param stringToExtract "foo.bar.baz.MyObject@1234"
-     * @return "MyObject@1234"
-     */
-    private static String extractObjectNameAndAddress(String stringToExtract) {
-        int index = stringToExtract.lastIndexOf(DELIMITER_DOT);
-        return index >= 0 ? stringToExtract.substring(index) : "";
+    private static String nameAndAddress(Object obj) {
+        return obj.getClass().getSimpleName() + "@" + obj.hashCode();
     }
 }
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index 61ba411..2f4bb8e 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -23,7 +23,6 @@
 
 import android.animation.TimeInterpolator;
 import android.content.Context;
-import android.content.res.Configuration;
 import android.graphics.Matrix;
 import android.graphics.Point;
 import android.graphics.PointF;
@@ -31,6 +30,8 @@
 import android.graphics.RectF;
 import android.util.IntProperty;
 
+import androidx.annotation.NonNull;
+
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.PendingAnimation;
@@ -67,10 +68,12 @@
     private final RectF mTempRectF = new RectF();
     private final float[] mTempPoint = new float[2];
 
-    private final RecentsOrientedState mOrientationState;
     private final Context mContext;
     private final BaseActivityInterface mSizeStrategy;
 
+    @NonNull
+    private RecentsOrientedState mOrientationState;
+
     private final Rect mTaskRect = new Rect();
     private boolean mDrawsBelowRecents;
     private final PointF mPivot = new PointF();
@@ -100,6 +103,7 @@
     // Cached calculations
     private boolean mLayoutValid = false;
     private boolean mScrollValid = false;
+    private int mOrientationStateId;
 
     public TaskViewSimulator(Context context, BaseActivityInterface sizeStrategy) {
         mContext = context;
@@ -107,8 +111,8 @@
 
         mOrientationState = new RecentsOrientedState(context, sizeStrategy, i -> { });
         mOrientationState.setGestureActive(true);
-
         mCurrentFullscreenParams = new FullscreenDrawParams(context);
+        mOrientationStateId = mOrientationState.getStateId();
     }
 
     /**
@@ -116,23 +120,14 @@
      */
     public void setDp(DeviceProfile dp) {
         mDp = dp;
-        mOrientationState.setMultiWindowMode(mDp.isMultiWindowMode);
         mLayoutValid = false;
     }
 
     /**
-     * @see com.android.quickstep.views.RecentsView#setLayoutRotation(int, int)
+     * Sets the orientation state used for this animation
      */
-    public void setLayoutRotation(int touchRotation, int displayRotation) {
-        mOrientationState.update(touchRotation, displayRotation);
-        mLayoutValid = false;
-    }
-
-    /**
-     * @see com.android.quickstep.views.RecentsView#onConfigurationChanged(Configuration)
-     */
-    public void setRecentsRotation(int recentsRotation) {
-        mOrientationState.setRecentsRotation(recentsRotation);
+    public void setOrientationState(@NonNull RecentsOrientedState orientationState) {
+        mOrientationState = orientationState;
         mLayoutValid = false;
     }
 
@@ -251,8 +246,9 @@
         if (mDp == null || mThumbnailPosition.isEmpty()) {
             return;
         }
-        if (!mLayoutValid) {
+        if (!mLayoutValid || mOrientationStateId != mOrientationState.getStateId()) {
             mLayoutValid = true;
+            mOrientationStateId = mOrientationState.getStateId();
 
             getFullScreenScale();
             mThumbnailData.rotation = mOrientationState.getDisplayRotation();
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 7efa5bd..f281296 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -89,6 +89,7 @@
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.BaseActivity;
+import com.android.launcher3.BaseActivity.MultiWindowModeChangedListener;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Insettable;
 import com.android.launcher3.InvariantDeviceProfile;
@@ -239,7 +240,7 @@
                 }
             };
 
-    protected RecentsOrientedState mOrientationState;
+    protected final RecentsOrientedState mOrientationState;
     protected final BaseActivityInterface mSizeStrategy;
     protected RecentsAnimationController mRecentsAnimationController;
     protected SurfaceTransactionApplier mSyncTransactionApplier;
@@ -408,17 +409,18 @@
     private int mTaskViewStartIndex = 0;
     private OverviewActionsView mActionsView;
 
-    private BaseActivity.MultiWindowModeChangedListener mMultiWindowModeChangedListener =
-            (inMultiWindowMode) -> {
-                if (mOrientationState != null) {
+    private MultiWindowModeChangedListener mMultiWindowModeChangedListener =
+            new MultiWindowModeChangedListener() {
+                @Override
+                public void onMultiWindowModeChanged(boolean inMultiWindowMode) {
                     mOrientationState.setMultiWindowMode(inMultiWindowMode);
                     setLayoutRotation(mOrientationState.getTouchRotation(),
                             mOrientationState.getDisplayRotation());
                     updateChildTaskOrientations();
-                }
-                if (!inMultiWindowMode && mOverviewStateEnabled) {
-                    // TODO: Re-enable layout transitions for addition of the unpinned task
-                    reloadIfNeeded();
+                    if (!inMultiWindowMode && mOverviewStateEnabled) {
+                        // TODO: Re-enable layout transitions for addition of the unpinned task
+                        reloadIfNeeded();
+                    }
                 }
             };
 
@@ -476,9 +478,7 @@
 
         mLiveTileTaskViewSimulator = new TaskViewSimulator(getContext(), getSizeStrategy());
         mLiveTileTaskViewSimulator.recentsViewScale.value = 1;
-        mLiveTileTaskViewSimulator.setLayoutRotation(getPagedViewOrientedState().getTouchRotation(),
-                getPagedViewOrientedState().getDisplayRotation());
-        mLiveTileTaskViewSimulator.setRecentsRotation(rotation);
+        mLiveTileTaskViewSimulator.setOrientationState(mOrientationState);
         mLiveTileTaskViewSimulator.setDrawsBelowRecents(true);
     }
 
@@ -1763,7 +1763,7 @@
         if (mOrientationState.setRecentsRotation(rotation)) {
             updateOrientationHandler();
         }
-        mLiveTileTaskViewSimulator.setRecentsRotation(rotation);
+
         // If overview is in modal state when rotate, reset it to overview state without running
         // animation.
         if (mActivity.isInState(OVERVIEW_MODAL_TASK)) {
@@ -1798,8 +1798,6 @@
         requestLayout();
         // Reapply the current page to update page scrolls.
         setCurrentPage(mCurrentPage);
-        mLiveTileTaskViewSimulator.setLayoutRotation(getPagedViewOrientedState().getTouchRotation(),
-                getPagedViewOrientedState().getDisplayRotation());
     }
 
     public RecentsOrientedState getPagedViewOrientedState() {
diff --git a/res/layout/search_result_settings_row.xml b/res/layout/search_result_settings_row.xml
index 05f7561..22c08bf 100644
--- a/res/layout/search_result_settings_row.xml
+++ b/res/layout/search_result_settings_row.xml
@@ -44,6 +44,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_marginBottom="@dimen/search_line_spacing"
+            android:maxLines="1"
             android:textColor="?android:attr/textColorPrimary"
             android:textSize="@dimen/search_hero_title_size" />
 
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 38ebe14..aa123f6 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -2497,6 +2497,7 @@
     @Override
     public void bindAllApplications(AppInfo[] apps, int flags) {
         mAppsView.getAppsStore().setApps(apps, flags);
+        PopupContainerWithArrow.dismissInvalidPopup(this);
     }
 
     /**
@@ -2528,6 +2529,7 @@
     public void bindWorkspaceItemsChanged(List<WorkspaceItemInfo> updated) {
         if (!updated.isEmpty()) {
             mWorkspace.updateShortcuts(updated);
+            PopupContainerWithArrow.dismissInvalidPopup(this);
         }
     }
 
@@ -2552,6 +2554,7 @@
     public void bindWorkspaceComponentsRemoved(final ItemInfoMatcher matcher) {
         mWorkspace.removeItemsByMatcher(matcher);
         mDragController.onAppsRemoved(matcher);
+        PopupContainerWithArrow.dismissInvalidPopup(this);
     }
 
     @Override
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index 5b42681..d049352 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -184,8 +184,7 @@
                     || viewType == VIEW_TYPE_SEARCH_THUMBNAIL
                     || viewType == VIEW_TYPE_SEARCH_ICON_ROW
                     || viewType == VIEW_TYPE_SEARCH_ICON
-                    || viewType == VIEW_TYPE_SEARCH_SUGGEST
-                    || viewType == VIEW_TYPE_SEARCH_WIDGET_LIVE;
+                    || viewType == VIEW_TYPE_SEARCH_SUGGEST;
         }
     }
 
diff --git a/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java b/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java
index 3c81811..1d31975 100644
--- a/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java
+++ b/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java
@@ -98,7 +98,8 @@
                     mAppsView.getActiveRecyclerView().getLayoutManager();
             if (layoutManager.findFirstVisibleItemPosition() <= index
                     && index < parent.getChildCount()) {
-                decorationHandler.onFocusDraw(c, parent.getChildAt(index));
+                RecyclerView.ViewHolder vh = parent.findViewHolderForAdapterPosition(index);
+                if (vh != null) decorationHandler.onFocusDraw(c, vh.itemView);
             }
         }
         decorationHandler.reset();
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 6d92b8b..59930ff 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -600,6 +600,17 @@
     }
 
     /**
+     * Dismisses the popup if it is no longer valid
+     */
+    public static void dismissInvalidPopup(BaseDraggingActivity activity) {
+        PopupContainerWithArrow popup = getOpen(activity);
+        if (popup != null && (!popup.mOriginalIcon.isAttachedToWindow()
+                || !canShow(popup.mOriginalIcon, (ItemInfo) popup.mOriginalIcon.getTag()))) {
+            popup.animateClose();
+        }
+    }
+
+    /**
      * Handler to control drag-and-drop for popup items
      */
     public interface PopupItemDragHandler extends OnLongClickListener, OnTouchListener { }
diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java
index 2b04365..2adf8ce 100644
--- a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java
+++ b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java
@@ -39,6 +39,7 @@
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
 import com.android.launcher3.model.data.PromiseAppInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.popup.PopupContainerWithArrow;
 import com.android.launcher3.popup.PopupDataProvider;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.IntArray;
@@ -296,6 +297,7 @@
     @Override
     public void bindAllApplications(AppInfo[] apps, int flags) {
         mAppsView.getAppsStore().setApps(apps, flags);
+        PopupContainerWithArrow.dismissInvalidPopup(this);
     }
 
     public PopupDataProvider getPopupDataProvider() {
diff --git a/src/com/android/launcher3/views/SearchResultWidget.java b/src/com/android/launcher3/views/SearchResultWidget.java
index 65131be..7d53955 100644
--- a/src/com/android/launcher3/views/SearchResultWidget.java
+++ b/src/com/android/launcher3/views/SearchResultWidget.java
@@ -18,18 +18,25 @@
 import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.Context;
+import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.view.GestureDetector;
 import android.view.MotionEvent;
+import android.view.View;
 import android.widget.RelativeLayout;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.AppWidgetResizeFrame;
+import com.android.launcher3.CheckLongPressHelper;
+import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.allapps.search.AllAppsSearchBarController;
 import com.android.launcher3.allapps.search.SearchEventTracker;
 import com.android.launcher3.allapps.search.SearchWidgetInfoContainer;
+import com.android.launcher3.dragndrop.DraggableView;
+import com.android.launcher3.touch.ItemLongClickListener;
 import com.android.launcher3.widget.PendingAddWidgetInfo;
 import com.android.systemui.plugins.shared.SearchTarget;
 import com.android.systemui.plugins.shared.SearchTargetEvent;
@@ -39,14 +46,19 @@
  * provider
  */
 public class SearchResultWidget extends RelativeLayout implements
-        AllAppsSearchBarController.SearchTargetHandler {
+        AllAppsSearchBarController.SearchTargetHandler, DraggableView, View.OnLongClickListener {
 
     private static final String TAG = "SearchResultWidget";
 
     public static final String TARGET_TYPE_WIDGET_LIVE = "widget";
 
+    private final Rect mWidgetOffset = new Rect();
+
     private final Launcher mLauncher;
+    private final CheckLongPressHelper mLongPressHelper;
+    private final GestureDetector mClickDetector;
     private final AppWidgetHostView mHostView;
+    private final float mScaleToFit;
 
     private SearchTarget mSearchTarget;
     private AppWidgetProviderInfo mProviderInfo;
@@ -65,8 +77,18 @@
     public SearchResultWidget(@NonNull Context context, @Nullable AttributeSet attrs,
             int defStyleAttr) {
         super(context, attrs, defStyleAttr);
-        mHostView = new AppWidgetHostView(context);
         mLauncher = Launcher.getLauncher(context);
+        mHostView = new AppWidgetHostView(context);
+        DeviceProfile grid = mLauncher.getDeviceProfile();
+        mScaleToFit = Math.min(grid.appWidgetScale.x, grid.appWidgetScale.y);
+
+        // detect tap event on widget container for search target event reporting
+        mClickDetector = new GestureDetector(context,
+                new ClickListener(() -> handleSelection(SearchTargetEvent.CHILD_SELECT)));
+
+        mLongPressHelper = new CheckLongPressHelper(this);
+        mLongPressHelper.setLongPressTimeoutFactor(1);
+        setOnLongClickListener(this);
     }
 
     @Override
@@ -106,8 +128,7 @@
         AppWidgetResizeFrame.updateWidgetSizeRanges(mHostView, mLauncher, info.spanX,
                 info.spanY);
         mHostView.requestLayout();
-
-
+        setTag(info);
     }
 
     /**
@@ -127,9 +148,55 @@
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
-        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+        mLongPressHelper.onTouchEvent(ev);
+        mClickDetector.onTouchEvent(ev);
+        if (ev.getAction() == MotionEvent.ACTION_UP && !mLongPressHelper.hasPerformedLongPress()) {
             handleSelection(SearchTargetEvent.CHILD_SELECT);
         }
         return super.onInterceptTouchEvent(ev);
     }
+
+
+    @Override
+    public void cancelLongPress() {
+        super.cancelLongPress();
+        mLongPressHelper.cancelLongPress();
+    }
+
+    @Override
+    public int getViewType() {
+        return DraggableView.DRAGGABLE_WIDGET;
+    }
+
+    @Override
+    public void getSourceVisualDragBounds(Rect bounds) {
+        mHostView.getHitRect(mWidgetOffset);
+        int width = (int) (mHostView.getMeasuredWidth() * mScaleToFit);
+        int height = (int) (mHostView.getMeasuredHeight() * mScaleToFit);
+        bounds.set(mWidgetOffset.left,
+                mWidgetOffset.top,
+                width + mWidgetOffset.left,
+                height + mWidgetOffset.top);
+    }
+
+    @Override
+    public boolean onLongClick(View view) {
+        ItemLongClickListener.INSTANCE_ALL_APPS.onLongClick(view);
+        handleSelection(SearchTargetEvent.LONG_PRESS);
+        return false;
+    }
+
+    static class ClickListener extends GestureDetector.SimpleOnGestureListener {
+        private final Runnable mCb;
+
+        ClickListener(Runnable cb) {
+            mCb = cb;
+        }
+
+        @Override
+        public boolean onSingleTapConfirmed(MotionEvent e) {
+            mCb.run();
+            return super.onSingleTapConfirmed(e);
+        }
+    }
 }