Tweak ordering of first match search

- Tweak iteration for finding first match, go by operator priority and
  check each cell layout by order to return the first view that matches
- Also reset the launch cookie in cases where we're launching a task
  that doesn't support cookies (ie. via prediction), otherwise we may
  still try to associate it with the last launched cookie later

Fixes: 187720286
Test: Swipe up from various icon types across hotseat/workspace
Change-Id: I71c4c13c442b0884b2247589685f976eaaeb30a4
Signed-off-by: Winson Chung <winsonc@google.com>
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index e777ee7..25e2359 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -20,6 +20,7 @@
 import static com.android.launcher3.LauncherState.FLAG_HIDE_BACK_BUTTON;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.LauncherState.NO_OFFSET;
+import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
 import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
@@ -499,6 +500,8 @@
                     // Also allow swiping to folders
                     break;
                 }
+                // Reset any existing launch cookies associated with the cookie
+                opts.setLaunchCookie(ObjectWrapper.wrap(NO_MATCHING_ID));
                 return;
         }
         switch (info.itemType) {
@@ -509,6 +512,8 @@
                 // Fall through and continue if it's an app, shortcut, or widget
                 break;
             default:
+                // Reset any existing launch cookies associated with the cookie
+                opts.setLaunchCookie(ObjectWrapper.wrap(NO_MATCHING_ID));
                 return;
         }
         opts.setLaunchCookie(ObjectWrapper.wrap(new Integer(info.id)));
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index 811af7e..1bae1c5 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -21,6 +21,7 @@
 import static com.android.launcher3.Utilities.boundToRange;
 import static com.android.launcher3.Utilities.dpToPx;
 import static com.android.launcher3.config.FeatureFlags.PROTOTYPE_APP_CLOSE;
+import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
 import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
 import static com.android.launcher3.views.FloatingIconView.getFloatingIconView;
 
@@ -234,7 +235,7 @@
 
         // Find the associated item info for the launch cookie (if available), note that predicted
         // apps actually have an id of -1, so use another default id here
-        int launchCookieItemId = -2;
+        int launchCookieItemId = NO_MATCHING_ID;
         for (IBinder cookie : launchCookies) {
             Integer itemId = ObjectWrapper.unwrap(cookie);
             if (itemId != null) {
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 5ba7623..98d80fe 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -2953,10 +2953,11 @@
         };
         final Workspace.ItemOperator packageAndUserAndApp = (ItemInfo info, View view) ->
                 info != null
-                        && info.getTargetComponent() != null
-                        && TextUtils.equals(info.getTargetComponent().getPackageName(), packageName)
+                        && info.itemType == ITEM_TYPE_APPLICATION
                         && info.user.equals(user)
-                        && info.itemType == ITEM_TYPE_APPLICATION;
+                        && info.getTargetComponent() != null
+                        && TextUtils.equals(info.getTargetComponent().getPackageName(),
+                                packageName);
         final Workspace.ItemOperator packageAndUserAndAppInFolder = (info, view) -> {
             if (info instanceof FolderInfo) {
                 FolderInfo folderInfo = (FolderInfo) info;
@@ -2973,7 +2974,7 @@
         cellLayouts.add(getHotseat());
         forEachVisiblePage(page -> cellLayouts.add((CellLayout) page));
 
-        // Order: App icons, app in folder. Items in hotseat get returned first.
+        // Order: Preferred item, App icons in hotseat/workspace, app in folder in hotseat/workspace
         if (ADAPTIVE_ICON_WINDOW_ANIM.get()) {
             return getFirstMatch(cellLayouts, preferredItem, preferredItemInFolder,
                     packageAndUserAndApp, packageAndUserAndAppInFolder);
@@ -3010,34 +3011,17 @@
     }
 
     /**
+     * Finds the first view matching the ordered operators across the given cell layouts by order.
      * @param cellLayouts List of CellLayouts to scan, in order of preference.
      * @param operators List of operators, in order starting from best matching operator.
-     * @return
      */
     View getFirstMatch(Iterable<CellLayout> cellLayouts, final ItemOperator... operators) {
-        // This array is filled with the first match for each operator.
-        final View[] matches = new View[operators.length];
-        // For efficiency, the outer loop should be CellLayout.
-        for (CellLayout cellLayout : cellLayouts) {
-            mapOverCellLayout(cellLayout, (info, v) -> {
-                for (int i = 0; i < operators.length; ++i) {
-                    if (matches[i] == null && operators[i].evaluate(info, v)) {
-                        matches[i] = v;
-                        if (i == 0) {
-                            // We can return since this is the best match possible.
-                            return true;
-                        }
-                    }
+        for (ItemOperator operator : operators) {
+            for (CellLayout cellLayout : cellLayouts) {
+                View match = mapOverCellLayout(cellLayout, operator);
+                if (match != null) {
+                    return match;
                 }
-                return false;
-            });
-            if (matches[0] != null) {
-                break;
-            }
-        }
-        for (View match : matches) {
-            if (match != null) {
-                return match;
             }
         }
         return null;
@@ -3111,16 +3095,16 @@
      */
     public void mapOverItems(ItemOperator op) {
         for (CellLayout layout : getWorkspaceAndHotseatCellLayouts()) {
-            if (mapOverCellLayout(layout, op)) {
+            if (mapOverCellLayout(layout, op) != null) {
                 return;
             }
         }
     }
 
-    private boolean mapOverCellLayout(CellLayout layout, ItemOperator op) {
+    private View mapOverCellLayout(CellLayout layout, ItemOperator op) {
         // TODO(b/128460496) Potential race condition where layout is not yet loaded
         if (layout == null) {
-            return false;
+            return null;
         }
         ShortcutAndWidgetContainer container = layout.getShortcutsAndWidgets();
         // map over all the shortcuts on the workspace
@@ -3128,10 +3112,10 @@
         for (int itemIdx = 0; itemIdx < itemCount; itemIdx++) {
             View item = container.getChildAt(itemIdx);
             if (op.evaluate((ItemInfo) item.getTag(), item)) {
-                return true;
+                return item;
             }
         }
-        return false;
+        return null;
     }
 
     void updateShortcuts(List<WorkspaceItemInfo> shortcuts) {
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index e388965..3abcc2b 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -68,6 +68,8 @@
 
     public static final boolean DEBUG = false;
     public static final int NO_ID = -1;
+    // An id that doesn't match any item, including predicted apps with have an id=NO_ID
+    public static final int NO_MATCHING_ID = Integer.MIN_VALUE;
 
     /**
      * The id in the settings database for this item