Setup make icon-loader library
Bug: 115891474

Test: make -j10 icon-loader
Next step: Launcher will depend on icon-loader in next CL

Change-Id: I797ddb857cf8be79f3be6ca2f174c593ca3713a5
diff --git a/Android.bp b/Android.bp
index 2608280..4b32702 100644
--- a/Android.bp
+++ b/Android.bp
@@ -28,3 +28,23 @@
     ],
     platform_apis: true,
 }
+
+
+android_library {
+    name: "icon-loader",
+    sdk_version: "28",
+    static_libs: [
+        "androidx.core_core",
+    ],
+    resource_dirs: [
+        "res",
+    ],
+    srcs: [
+        "src/com/android/launcher3/icons/BaseIconFactory.java",
+        "src/com/android/launcher3/icons/BitmapInfo.java",
+        "src/com/android/launcher3/icons/IconNormalizer.java",
+        "src/com/android/launcher3/icons/FixedScaleDrawable.java",
+        "src/com/android/launcher3/icons/ShadowGenerator.java",
+        "src/com/android/launcher3/icons/ColorExtractor.java",
+    ],
+}
diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java
index 7190f12..851454b 100644
--- a/src/com/android/launcher3/InstallShortcutReceiver.java
+++ b/src/com/android/launcher3/InstallShortcutReceiver.java
@@ -480,7 +480,7 @@
                 final LauncherAppState app = LauncherAppState.getInstance(mContext);
                 // Set default values until proper values is loaded.
                 appInfo.title = "";
-                app.getIconCache().getDefaultIcon(user).applyTo(appInfo);
+                appInfo.applyFrom(app.getIconCache().getDefaultIcon(user));
                 final ShortcutInfo si = appInfo.makeShortcut();
                 if (Looper.myLooper() == LauncherModel.getWorkerLooper()) {
                     app.getIconCache().getTitleAndIcon(si, activityInfo, false /* useLowResIcon */);
@@ -495,7 +495,7 @@
             } else if (shortcutInfo != null) {
                 ShortcutInfo si = new ShortcutInfo(shortcutInfo, mContext);
                 LauncherIcons li = LauncherIcons.obtain(mContext);
-                li.createShortcutIcon(shortcutInfo).applyTo(si);
+                si.applyFrom(li.createShortcutIcon(shortcutInfo));
                 li.recycle();
                 return Pair.create((ItemInfo) si, (Object) shortcutInfo);
             } else if (providerInfo != null) {
@@ -656,7 +656,7 @@
         if (iconInfo == null) {
             iconInfo = app.getIconCache().getDefaultIcon(info.user);
         }
-        iconInfo.applyTo(info);
+        info.applyFrom(iconInfo);
 
         info.title = Utilities.trim(name);
         info.contentDescription = UserManagerCompat.getInstance(app.getContext())
diff --git a/src/com/android/launcher3/ItemInfoWithIcon.java b/src/com/android/launcher3/ItemInfoWithIcon.java
index 6d453c9..e29f927 100644
--- a/src/com/android/launcher3/ItemInfoWithIcon.java
+++ b/src/com/android/launcher3/ItemInfoWithIcon.java
@@ -20,6 +20,8 @@
 
 import android.graphics.Bitmap;
 
+import com.android.launcher3.icons.BitmapInfo;
+
 /**
  * Represents an ItemInfo which also holds an icon.
  */
@@ -118,4 +120,10 @@
     public boolean usingLowResIcon() {
         return iconBitmap == LOW_RES_ICON;
     }
+
+    public void applyFrom(BitmapInfo info) {
+        iconBitmap = info.icon;
+        iconColor = info.color;
+    }
+
 }
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index cbfde25..8e9021f 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -657,7 +657,7 @@
         updateAndBindShortcutInfo(() -> {
             si.updateFromDeepShortcutInfo(info, mApp.getContext());
             LauncherIcons li = LauncherIcons.obtain(mApp.getContext());
-            li.createShortcutIcon(info).applyTo(si);
+            si.applyFrom(li.createShortcutIcon(info));
             li.recycle();
             return si;
         });
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatVO.java b/src/com/android/launcher3/compat/LauncherAppsCompatVO.java
index fb44660..82617fe 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompatVO.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompatVO.java
@@ -139,7 +139,7 @@
             ShortcutInfo info = new ShortcutInfo(compat, context);
             // Apply the unbadged icon and fetch the actual icon asynchronously.
             LauncherIcons li = LauncherIcons.obtain(context);
-            li.createShortcutIcon(compat, false /* badged */).applyTo(info);
+            info.applyFrom(li.createShortcutIcon(compat, false /* badged */));
             li.recycle();
             LauncherAppState.getInstance(context).getModel()
                     .updateAndBindShortcutInfo(info, compat);
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index 6d1efd5..b6a8b50 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -204,7 +204,7 @@
             public void run() {
                 LauncherAppState appState = LauncherAppState.getInstance(mLauncher);
                 Object[] outObj = new Object[1];
-                final Drawable dr = getFullDrawable(info, appState, outObj);
+                Drawable dr = getFullDrawable(info, appState, outObj);
 
                 if (dr instanceof AdaptiveIconDrawable) {
                     int w = mBitmap.getWidth();
@@ -220,10 +220,20 @@
                     mBadge = getBadge(info, appState, outObj[0]);
                     mBadge.setBounds(badgeBounds);
 
-                    LauncherIcons li = LauncherIcons.obtain(mLauncher);
-                    Utilities.scaleRectAboutCenter(bounds,
-                            li.getNormalizer().getScale(dr, null, null, null));
-                    li.recycle();
+                    // Do not draw the background in case of folder as its translucent
+                    mDrawBitmap = !(dr instanceof FolderAdaptiveIcon);
+
+                    try (LauncherIcons li = LauncherIcons.obtain(mLauncher)) {
+                        Drawable nDr; // drawable to be normalized
+                        if (mDrawBitmap) {
+                            nDr = dr;
+                        } else {
+                            // Since we just want the scale, avoid heavy drawing operations
+                            nDr = new AdaptiveIconDrawable(new ColorDrawable(Color.BLACK), null);
+                        }
+                        Utilities.scaleRectAboutCenter(bounds,
+                                li.getNormalizer().getScale(nDr, null, null, null));
+                    }
                     AdaptiveIconDrawable adaptiveIcon = (AdaptiveIconDrawable) dr;
 
                     // Shrink very tiny bit so that the clip path is smaller than the original bitmap
@@ -259,9 +269,6 @@
                             // Assign the variable on the UI thread to avoid race conditions.
                             mScaledMaskPath = mask;
 
-                            // Do not draw the background in case of folder as its translucent
-                            mDrawBitmap = !(dr instanceof FolderAdaptiveIcon);
-
                             if (info.isDisabled()) {
                                 FastBitmapDrawable d = new FastBitmapDrawable((Bitmap) null);
                                 d.setIsDisabled(true);
diff --git a/src/com/android/launcher3/icons/BaseIconCache.java b/src/com/android/launcher3/icons/BaseIconCache.java
index 6433103..9198c24 100644
--- a/src/com/android/launcher3/icons/BaseIconCache.java
+++ b/src/com/android/launcher3/icons/BaseIconCache.java
@@ -261,7 +261,7 @@
     protected void applyCacheEntry(CacheEntry entry, ItemInfoWithIcon info) {
         info.title = Utilities.trim(entry.title);
         info.contentDescription = entry.contentDescription;
-        ((entry.icon == null) ? getDefaultIcon(info.user) : entry).applyTo(info);
+        info.applyFrom((entry.icon == null) ? getDefaultIcon(info.user) : entry);
     }
 
     public synchronized BitmapInfo getDefaultIcon(UserHandle user) {
diff --git a/src/com/android/launcher3/icons/BaseIconFactory.java b/src/com/android/launcher3/icons/BaseIconFactory.java
index db723b7..c8c9618 100644
--- a/src/com/android/launcher3/icons/BaseIconFactory.java
+++ b/src/com/android/launcher3/icons/BaseIconFactory.java
@@ -69,14 +69,14 @@
 
     public ShadowGenerator getShadowGenerator() {
         if (mShadowGenerator == null) {
-            mShadowGenerator = new ShadowGenerator(mContext);
+            mShadowGenerator = new ShadowGenerator(mIconBitmapSize);
         }
         return mShadowGenerator;
     }
 
     public IconNormalizer getNormalizer() {
         if (mNormalizer == null) {
-            mNormalizer = new IconNormalizer(mContext);
+            mNormalizer = new IconNormalizer(mContext, mIconBitmapSize);
         }
         return mNormalizer;
     }
diff --git a/src/com/android/launcher3/icons/BitmapInfo.java b/src/com/android/launcher3/icons/BitmapInfo.java
index ebe0511..245561e 100644
--- a/src/com/android/launcher3/icons/BitmapInfo.java
+++ b/src/com/android/launcher3/icons/BitmapInfo.java
@@ -18,8 +18,6 @@
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
 
-import com.android.launcher3.ItemInfoWithIcon;
-
 public class BitmapInfo {
 
     public static final Bitmap LOW_RES_ICON = Bitmap.createBitmap(1, 1, Config.ALPHA_8);
@@ -27,11 +25,6 @@
     public Bitmap icon;
     public int color;
 
-    public void applyTo(ItemInfoWithIcon info) {
-        info.iconBitmap = icon;
-        info.iconColor = color;
-    }
-
     public void applyTo(BitmapInfo info) {
         info.icon = icon;
         info.color = color;
diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java
index 4349455..41a53e5 100644
--- a/src/com/android/launcher3/icons/IconCache.java
+++ b/src/com/android/launcher3/icons/IconCache.java
@@ -139,7 +139,7 @@
         // null info means not installed, but if we have a component from the intent then
         // we should still look in the cache for restored app icons.
         if (info.getTargetComponent() == null) {
-            getDefaultIcon(info.user).applyTo(info);
+            info.applyFrom(getDefaultIcon(info.user));
             info.title = "";
             info.contentDescription = "";
         } else {
diff --git a/src/com/android/launcher3/icons/IconNormalizer.java b/src/com/android/launcher3/icons/IconNormalizer.java
index 7317782..4052a55 100644
--- a/src/com/android/launcher3/icons/IconNormalizer.java
+++ b/src/com/android/launcher3/icons/IconNormalizer.java
@@ -28,14 +28,9 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.drawable.AdaptiveIconDrawable;
-import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.util.Log;
 
-import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
-
 import java.nio.ByteBuffer;
 
 import androidx.annotation.NonNull;
@@ -84,9 +79,9 @@
     private final Matrix mMatrix;
 
     /** package private **/
-    IconNormalizer(Context context) {
+    IconNormalizer(Context context, int iconBitmapSize) {
         // Use twice the icon size as maximum size to avoid scaling down twice.
-        mMaxSize = LauncherAppState.getIDP(context).iconBitmapSize * 2;
+        mMaxSize = iconBitmapSize * 2;
         mBitmap = Bitmap.createBitmap(mMaxSize, mMaxSize, Bitmap.Config.ALPHA_8);
         mCanvas = new Canvas(mBitmap);
         mPixels = new byte[mMaxSize * mMaxSize];
@@ -193,17 +188,13 @@
      */
     public synchronized float getScale(@NonNull Drawable d, @Nullable RectF outBounds,
             @Nullable Path path, @Nullable boolean[] outMaskShape) {
-        if (Utilities.ATLEAST_OREO && d instanceof AdaptiveIconDrawable) {
+        if (BaseIconFactory.ATLEAST_OREO && d instanceof AdaptiveIconDrawable) {
             if (mAdaptiveIconScale != SCALE_NOT_INITIALIZED) {
                 if (outBounds != null) {
                     outBounds.set(mAdaptiveIconBounds);
                 }
                 return mAdaptiveIconScale;
             }
-            if (d instanceof FolderAdaptiveIcon) {
-                // Since we just want the scale, avoid heavy drawing operations
-                d = new AdaptiveIconDrawable(new ColorDrawable(Color.BLACK), null);
-            }
         }
         int width = d.getIntrinsicWidth();
         int height = d.getIntrinsicHeight();
@@ -314,7 +305,7 @@
         float areaScale = area / (width * height);
         // Use sqrt of the final ratio as the images is scaled across both width and height.
         float scale = areaScale > scaleRequired ? (float) Math.sqrt(scaleRequired / areaScale) : 1;
-        if (Utilities.ATLEAST_OREO && d instanceof AdaptiveIconDrawable &&
+        if (BaseIconFactory.ATLEAST_OREO && d instanceof AdaptiveIconDrawable &&
                 mAdaptiveIconScale == SCALE_NOT_INITIALIZED) {
             mAdaptiveIconScale = scale;
             mAdaptiveIconBounds.set(mBounds);
diff --git a/src/com/android/launcher3/icons/ShadowGenerator.java b/src/com/android/launcher3/icons/ShadowGenerator.java
index 57d463a..6491b7e 100644
--- a/src/com/android/launcher3/icons/ShadowGenerator.java
+++ b/src/com/android/launcher3/icons/ShadowGenerator.java
@@ -16,7 +16,6 @@
 
 package com.android.launcher3.icons;
 
-import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
 import android.graphics.BlurMaskFilter;
@@ -28,23 +27,19 @@
 import android.graphics.PorterDuffXfermode;
 import android.graphics.RectF;
 
-import com.android.launcher3.LauncherAppState;
-
 import androidx.core.graphics.ColorUtils;
 
 /**
  * Utility class to add shadows to bitmaps.
  */
 public class ShadowGenerator {
-
-    // Percent of actual icon size
-    private static final float HALF_DISTANCE = 0.5f;
     public static final float BLUR_FACTOR = 0.5f/48;
 
     // Percent of actual icon size
     public static final float KEY_SHADOW_DISTANCE = 1f/48;
     private static final int KEY_SHADOW_ALPHA = 61;
-
+    // Percent of actual icon size
+    private static final float HALF_DISTANCE = 0.5f;
     private static final int AMBIENT_SHADOW_ALPHA = 30;
 
     private final int mIconSize;
@@ -53,8 +48,8 @@
     private final Paint mDrawPaint;
     private final BlurMaskFilter mDefaultBlurMaskFilter;
 
-    public ShadowGenerator(Context context) {
-        mIconSize = LauncherAppState.getIDP(context).iconBitmapSize;
+    public ShadowGenerator(int iconSize) {
+        mIconSize = iconSize;
         mBlurPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
         mDrawPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
         mDefaultBlurMaskFilter = new BlurMaskFilter(mIconSize * BLUR_FACTOR, Blur.NORMAL);
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
index 94cf5c2..ea4d32b 100644
--- a/src/com/android/launcher3/model/LoaderCursor.java
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -153,7 +153,7 @@
         info.title = getTitle();
         // the fallback icon
         if (!loadIcon(info)) {
-            mIconCache.getDefaultIcon(info.user).applyTo(info);
+            info.applyFrom(mIconCache.getDefaultIcon(info.user));
         }
 
         // TODO: If there's an explicit component and we can't install that, delete it.
@@ -176,7 +176,7 @@
                 BitmapInfo iconInfo = li.createIconBitmap(info.iconResource);
                 li.recycle();
                 if (iconInfo != null) {
-                    iconInfo.applyTo(info);
+                    info.applyFrom(iconInfo);
                     return true;
                 }
             }
@@ -185,7 +185,7 @@
         // Failed to load from resource, try loading from DB.
         byte[] data = getBlob(iconIndex);
         try (LauncherIcons li = LauncherIcons.obtain(mContext)) {
-            li.createIconBitmap(BitmapFactory.decodeByteArray(data, 0, data.length)).applyTo(info);
+            info.applyFrom(li.createIconBitmap(BitmapFactory.decodeByteArray(data, 0, data.length)));
             return true;
         } catch (Exception e) {
             Log.e(TAG, "Failed to load icon for info " + info, e);
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 1ec7af2..405125e 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -498,8 +498,8 @@
                                             c.loadIcon(finalInfo) ? finalInfo.iconBitmap : null;
 
                                     LauncherIcons li = LauncherIcons.obtain(context);
-                                    li.createShortcutIcon(pinnedShortcut,
-                                            true /* badged */, fallbackIconProvider).applyTo(info);
+                                    info.applyFrom(li.createShortcutIcon(pinnedShortcut,
+                                            true /* badged */, fallbackIconProvider));
                                     li.recycle();
                                     if (pmHelper.isAppSuspended(
                                             pinnedShortcut.getPackage(), info.user)) {
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 201a63e..0f67f0c 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -194,7 +194,7 @@
                             BitmapInfo iconInfo = li.createIconBitmap(si.iconResource);
                             li.recycle();
                             if (iconInfo != null) {
-                                iconInfo.applyTo(si);
+                                si.applyFrom(iconInfo);
                                 infoUpdated = true;
                             }
                         }
diff --git a/src/com/android/launcher3/model/ShortcutsChangedTask.java b/src/com/android/launcher3/model/ShortcutsChangedTask.java
index 020bc41..47fcd9e 100644
--- a/src/com/android/launcher3/model/ShortcutsChangedTask.java
+++ b/src/com/android/launcher3/model/ShortcutsChangedTask.java
@@ -96,8 +96,8 @@
                     // If the shortcut is pinned but no longer has an icon in the system,
                     // keep the current icon instead of reverting to the default icon.
                     LauncherIcons li = LauncherIcons.obtain(context);
-                    li.createShortcutIcon(fullDetails, true, Provider.of(shortcutInfo.iconBitmap))
-                            .applyTo(shortcutInfo);
+                    shortcutInfo.applyFrom(li.createShortcutIcon(fullDetails, true,
+                            Provider.of(shortcutInfo.iconBitmap)));
                     li.recycle();
                     updatedShortcutInfos.add(shortcutInfo);
                 }
diff --git a/src/com/android/launcher3/model/UserLockStateChangedTask.java b/src/com/android/launcher3/model/UserLockStateChangedTask.java
index 9f02d4f..40c1912 100644
--- a/src/com/android/launcher3/model/UserLockStateChangedTask.java
+++ b/src/com/android/launcher3/model/UserLockStateChangedTask.java
@@ -95,7 +95,7 @@
                     // If the shortcut is pinned but no longer has an icon in the system,
                     // keep the current icon instead of reverting to the default icon.
                     LauncherIcons li = LauncherIcons.obtain(context);
-                    li.createShortcutIcon(shortcut, true, Provider.of(si.iconBitmap)).applyTo(si);
+                    si.applyFrom(li.createShortcutIcon(shortcut, true, Provider.of(si.iconBitmap)));
                     li.recycle();
                 } else {
                     si.runtimeStatusFlags |= FLAG_DISABLED_LOCKED_USER;
diff --git a/src/com/android/launcher3/popup/PopupPopulator.java b/src/com/android/launcher3/popup/PopupPopulator.java
index c14c00e..61113b8 100644
--- a/src/com/android/launcher3/popup/PopupPopulator.java
+++ b/src/com/android/launcher3/popup/PopupPopulator.java
@@ -150,7 +150,7 @@
                 final ShortcutInfo si = new ShortcutInfo(shortcut, launcher);
                 // Use unbadged icon for the menu.
                 LauncherIcons li = LauncherIcons.obtain(launcher);
-                li.createShortcutIcon(shortcut, false /* badged */).applyTo(si);
+                si.applyFrom(li.createShortcutIcon(shortcut, false /* badged */));
                 li.recycle();
                 si.rank = i;