Updates to app to icon animation, and turns on ADAPTIVE_ICON_WINDOW_ANIM flag.

- getFirstMatchForAppClose now only looks at the current page, since switching
  pages is disruptive and the animation for app closing to an icon on a
  different page is unclear.
- Searches for package name and user id (in case of work profile app)
  instead of component name to handle shortcuts and trampoline activities.

- Adaptive icon background drawable is now always centered

- Fix crash that occurs when ADAPTIVE_ICON_WINDOW_ANIM is off. We were trying
  to set FolderAdaptiveIcon as the background drawable. Simplest solution is
  to not use folder as a search criteria when the flag is off.

- Similar to DragView, FloatingIconView now uses BubbleTextView icon when
  adaptive icon support is not available. This handles legacy-treated apps.

Bug: 123900446
Change-Id: Idaf292bb39d78db511cf2ee04a16b191454846b3
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 9650a53..971987a 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
@@ -29,11 +29,11 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
-import android.content.ComponentName;
 import android.content.Context;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Region;
+import android.os.UserHandle;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.animation.Interpolator;
@@ -102,9 +102,10 @@
         final RecentsView recentsView = activity.getOverviewPanel();
         final TaskView runningTaskView = recentsView.getRunningTaskView();
         final View workspaceView;
-        if (runningTaskView != null) {
-            ComponentName component = runningTaskView.getTask().key.sourceComponent;
-            workspaceView = activity.getWorkspace().getFirstMatchForAppClose(component);
+        if (runningTaskView != null && runningTaskView.getTask().key.getComponent() != null) {
+            workspaceView = activity.getWorkspace().getFirstMatchForAppClose(
+                    runningTaskView.getTask().key.getComponent().getPackageName(),
+                    UserHandle.of(runningTaskView.getTask().key.userId));
         } else {
             workspaceView = null;
         }
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 7eee8af..09eb6d9 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -19,9 +19,13 @@
 import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
 import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
 import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_TRANSITION_MS;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
 import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.LauncherState.SPRING_LOADED;
+import static com.android.launcher3.config.FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM;
 import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_OVERLAY;
 
 import android.animation.Animator;
@@ -34,7 +38,6 @@
 import android.app.WallpaperManager;
 import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetProviderInfo;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
@@ -47,6 +50,7 @@
 import android.os.Message;
 import android.os.Parcelable;
 import android.os.UserHandle;
+import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.SparseArray;
@@ -99,8 +103,6 @@
 
 import java.util.ArrayList;
 import java.util.HashSet;
-import java.util.Objects;
-import java.util.Set;
 import java.util.function.Predicate;
 
 /**
@@ -1612,7 +1614,7 @@
 
         boolean aboveShortcut = (dropOverView.getTag() instanceof ShortcutInfo);
         boolean willBecomeShortcut =
-                (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
+                (info.itemType == ITEM_TYPE_APPLICATION ||
                         info.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT ||
                         info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT);
 
@@ -2520,7 +2522,7 @@
             View view;
 
             switch (info.itemType) {
-            case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
+            case ITEM_TYPE_APPLICATION:
             case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
             case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
                 if (info.container == NO_ID && info instanceof AppInfo) {
@@ -2896,51 +2898,29 @@
     }
 
     /**
-     * Returns a list of all the CellLayouts on the Homescreen, starting with
-     * {@param startPage}, then going outward alternating between pages prior to the startPage,
-     * and then the pages after the startPage.
-     * ie. if there are 5 pages [0, 1, 2, 3, 4] and startPage is 1, we return [1, 0, 2, 3, 4].
-     */
-    private CellLayout[] getWorkspaceCellLayouts(int startPage) {
-        int screenCount = getChildCount();
-        final CellLayout[] layouts = new CellLayout[screenCount];
-        int screen = 0;
-
-        layouts[screen] = (CellLayout) getChildAt(startPage);
-        screen++;
-
-        for (int i = 1; screen < screenCount; ++i) {
-            CellLayout prevPage = (CellLayout) getChildAt(startPage - i);
-            CellLayout nextPage = (CellLayout) getChildAt(startPage + i);
-
-            if (prevPage != null) {
-                layouts[screen] = prevPage;
-                screen++;
-            }
-            if (nextPage != null) {
-                layouts[screen] = nextPage;
-                screen++;
-            }
-        }
-        return layouts;
-    }
-
-    /**
      * Similar to {@link #getFirstMatch} but optimized to finding a suitable view for the app close
      * animation.
      *
-     * @param component The component of the task being dismissed.
+     * @param packageName The package name of the app to match.
+     * @param user The user of the app to match.
      */
-    public View getFirstMatchForAppClose(ComponentName component) {
+    public View getFirstMatchForAppClose(String packageName, UserHandle user) {
         final int curPage = getCurrentPage();
         final CellLayout currentPage = (CellLayout) getPageAt(curPage);
-        final Workspace.ItemOperator isItemComponent = (info, view) ->
-                info != null && Objects.equals(info.getTargetComponent(), component);
-        final Workspace.ItemOperator isItemInFolder = (info, view) -> {
+        final Workspace.ItemOperator packageAndUser = (ItemInfo info, View view) -> info != null
+                && info.getTargetComponent() != null
+                && TextUtils.equals(info.getTargetComponent().getPackageName(), packageName)
+                && info.user.equals(user);
+        final Workspace.ItemOperator packageAndUserAndApp = (ItemInfo info, View view) ->
+                packageAndUser.evaluate(info, view) && info.itemType == ITEM_TYPE_APPLICATION;
+        final Workspace.ItemOperator packageAndUserAndShortcut = (ItemInfo info, View view) ->
+                packageAndUser.evaluate(info, view) && (info.itemType == ITEM_TYPE_SHORTCUT
+                        || info.itemType == ITEM_TYPE_DEEP_SHORTCUT);
+        final Workspace.ItemOperator packageAndUserInFolder = (info, view) -> {
             if (info instanceof FolderInfo) {
                 FolderInfo folderInfo = (FolderInfo) info;
                 for (ShortcutInfo shortcutInfo : folderInfo.contents) {
-                    if (Objects.equals(shortcutInfo.getTargetComponent(), component)) {
+                    if (packageAndUser.evaluate(shortcutInfo, view)) {
                         return true;
                     }
                 }
@@ -2948,33 +2928,16 @@
             return false;
         };
 
-        CellLayout[] hotseatAndCurrentPage = new CellLayout[] { getHotseat(), currentPage };
-        // First we look if the app itself is in the hotseat or on the current workspace page.
-        View icon = getFirstMatch(hotseatAndCurrentPage, isItemComponent);
-        if (icon != null) {
-            return icon;
+        // Order: App icons, shortcuts, app/shortcut in folder. Items in hotseat get returned first.
+        if (ADAPTIVE_ICON_WINDOW_ANIM.get()) {
+            return getFirstMatch(new CellLayout[] { getHotseat(), currentPage },
+                    packageAndUserAndApp, packageAndUserAndShortcut, packageAndUserInFolder);
+        } else {
+            // Do not use Folder as a criteria, since it'll cause a crash when trying to draw
+            // FolderAdaptiveIcon as the background.
+            return getFirstMatch(new CellLayout[] { getHotseat(), currentPage },
+                    packageAndUserAndApp, packageAndUserAndShortcut);
         }
-        // Then we look if the app is in a folder on the hotseat or current workspace page.
-        icon = getFirstMatch(hotseatAndCurrentPage, isItemInFolder);
-        if (icon != null) {
-            return icon;
-        }
-        // Continue searching for the app or for a folder with the app on other pages of the
-        // workspace. We skip the current page, since we already searched above.
-        CellLayout[] allPages = getWorkspaceCellLayouts(curPage);
-        CellLayout[] page = new CellLayout[1];
-        for (int i = 1; i < allPages.length; ++i) {
-            page[0] = allPages[i];
-            icon = getFirstMatch(page, isItemComponent);
-            if (icon != null) {
-                return icon;
-            }
-            icon = getFirstMatch(page, isItemInFolder);
-            if (icon != null) {
-                return icon;
-            }
-        }
-        return null;
     }
 
     public View getHomescreenIconByItemId(final int id) {
@@ -3002,21 +2965,38 @@
         return value[0];
     }
 
-    private View getFirstMatch(CellLayout[] cellLayouts, final ItemOperator operator) {
-        final View[] value = new View[1];
+    /**
+     * @param cellLayouts List of CellLayouts to scan, in order of preference.
+     * @param operators List of operators, in order starting from best matching operator.
+     * @return
+     */
+    private View getFirstMatch(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(MAP_NO_RECURSE, cellLayout, (info, v) -> {
-                if (operator.evaluate(info, v)) {
-                    value[0] = v;
-                    return true;
+                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;
+                        }
+                    }
                 }
                 return false;
             });
-            if (value[0] != null) {
+            if (matches[0] != null) {
                 break;
             }
         }
-        return value[0];
+        for (View match : matches) {
+            if (match != null) {
+                return match;
+            }
+        }
+        return null;
     }
 
     void clearDropTargets() {
diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java
index b350767..d6e450a 100644
--- a/src/com/android/launcher3/config/BaseFlags.java
+++ b/src/com/android/launcher3/config/BaseFlags.java
@@ -102,7 +102,7 @@
             false, "Enable springs for quickstep animations");
 
     public static final TogglableFlag ADAPTIVE_ICON_WINDOW_ANIM = new TogglableFlag(
-            "ADAPTIVE_ICON_WINDOW_ANIM", false,
+            "ADAPTIVE_ICON_WINDOW_ANIM", true,
             "Use adaptive icons for window animations.");
 
     public static final TogglableFlag ENABLE_QUICKSTEP_LIVE_TILE = new TogglableFlag(
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 23ddd98..ec0462b 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -35,6 +35,7 @@
 import android.view.ViewGroup;
 import android.view.ViewOutlineProvider;
 
+import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.InsettableFrameLayout.LayoutParams;
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.Launcher;
@@ -81,7 +82,7 @@
 
     private final Rect mFinalDrawableBounds = new Rect();
     private final Rect mBgDrawableBounds = new Rect();
-    private final float mBgDrawableStartScale = 5f; // Magic number that can be tuned later.
+    private float mBgDrawableStartScale = 1f;
 
     private FloatingIconView(Context context) {
         super(context);
@@ -188,12 +189,19 @@
     private void getIcon(Launcher launcher, View v, ItemInfo info, boolean useDrawableAsIs,
             float aspectRatio) {
         final LayoutParams lp = (LayoutParams) getLayoutParams();
-        mDrawable = Utilities.getFullDrawable(launcher, info, lp.width, lp.height, useDrawableAsIs,
-                new Object[1]);
 
-        if (ADAPTIVE_ICON_WINDOW_ANIM.get() && !useDrawableAsIs
-                && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
-                && mDrawable instanceof AdaptiveIconDrawable) {
+        boolean supportsAdaptiveIcons = ADAPTIVE_ICON_WINDOW_ANIM.get() && !useDrawableAsIs
+                && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
+        if (!supportsAdaptiveIcons && v instanceof BubbleTextView) {
+            // Similar to DragView, we simply use the BubbleTextView icon here.
+            mDrawable = ((BubbleTextView) v).getIcon();
+        }
+        if (mDrawable == null) {
+            mDrawable = Utilities.getFullDrawable(launcher, info, lp.width, lp.height,
+                    useDrawableAsIs, new Object[1]);
+        }
+
+        if (supportsAdaptiveIcons && mDrawable instanceof AdaptiveIconDrawable) {
             mIsAdaptiveIcon = true;
 
             AdaptiveIconDrawable adaptiveIcon = (AdaptiveIconDrawable) mDrawable;
@@ -227,8 +235,9 @@
                 lp.height = (int) Math.max(lp.height, lp.width * aspectRatio);
                 layout(lp.leftMargin, lp.topMargin, lp.leftMargin + lp.width, lp.topMargin
                         + lp.height);
-                setBackgroundDrawableBounds(mBgDrawableStartScale);
             }
+            mBgDrawableStartScale = (float) lp.height / mOriginalHeight;
+            setBackgroundDrawableBounds(mBgDrawableStartScale);
 
             // Set up outline
             mOutline.set(0, 0, lp.width, lp.height);
@@ -252,6 +261,9 @@
     private void setBackgroundDrawableBounds(float scale) {
         mBgDrawableBounds.set(mFinalDrawableBounds);
         Utilities.scaleRectAboutCenter(mBgDrawableBounds, scale);
+        // Since the drawable is at the top of the view, we need to offset to keep it centered.
+        mBgDrawableBounds.offsetTo(mBgDrawableBounds.left,
+                (int) (mFinalDrawableBounds.top * scale));
         mBackground.setBounds(mBgDrawableBounds);
     }