Moving some common functionality to IconLoaderLib

Bug: 183641907
Test: Manual
Change-Id: Icfc7ebb140e4e1678b0715beee2e0e513e707b9e
diff --git a/Android.bp b/Android.bp
index 92cc36b..2c9d664 100644
--- a/Android.bp
+++ b/Android.bp
@@ -44,6 +44,7 @@
         "src/com/android/launcher3/ResourceUtils.java",
         "src/com/android/launcher3/testing/TestProtocol.java",
     ],
+    resource_dirs: [ ],
     manifest: "tests/tapl/AndroidManifest.xml",
     platform_apis: true,
 }
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 64b22d4..82a83fc 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -68,6 +68,7 @@
 import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
 import com.android.launcher3.anim.AnimationSuccessListener;
 import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.icons.FastBitmapDrawable;
 import com.android.launcher3.shortcuts.DeepShortcutView;
 import com.android.launcher3.statehandlers.DepthController;
 import com.android.launcher3.util.ActivityOptionsWrapper;
diff --git a/quickstep/src/com/android/quickstep/TaskIconCache.java b/quickstep/src/com/android/quickstep/TaskIconCache.java
index dd0ed8f..08503cf 100644
--- a/quickstep/src/com/android/quickstep/TaskIconCache.java
+++ b/quickstep/src/com/android/quickstep/TaskIconCache.java
@@ -15,7 +15,6 @@
  */
 package com.android.quickstep;
 
-import static com.android.launcher3.FastBitmapDrawable.newIcon;
 import static com.android.launcher3.uioverrides.QuickstepLauncher.GO_LOW_RAM_RECENTS_ENABLED;
 
 import android.app.ActivityManager.TaskDescription;
@@ -34,7 +33,6 @@
 
 import androidx.annotation.WorkerThread;
 
-import com.android.launcher3.FastBitmapDrawable;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.icons.BitmapInfo;
@@ -137,11 +135,12 @@
         // TODO: Load icon resource (b/143363444)
         Bitmap icon = TaskDescriptionCompat.getIcon(desc, key.userId);
         if (icon != null) {
-            entry.icon = new FastBitmapDrawable(getBitmapInfo(
+            /* isInstantApp */
+            entry.icon = getBitmapInfo(
                     new BitmapDrawable(mContext.getResources(), icon),
                     key.userId,
                     desc.getPrimaryColor(),
-                    false /* isInstantApp */));
+                    false /* isInstantApp */).newIcon(mContext);
         } else {
             activityInfo = PackageManagerWrapper.getInstance().getActivityInfo(
                     key.getComponent(), key.userId);
@@ -151,7 +150,7 @@
                         key.userId,
                         desc.getPrimaryColor(),
                         activityInfo.applicationInfo.isInstantApp());
-                entry.icon = newIcon(mContext, bitmapInfo);
+                entry.icon = bitmapInfo.newIcon(mContext);
             } else {
                 entry.icon = getDefaultIcon(key.userId);
             }
@@ -199,7 +198,7 @@
                 }
                 mDefaultIcons.put(userId, info);
             }
-            return new FastBitmapDrawable(info);
+            return info.newIcon(mContext);
         }
     }
 
diff --git a/quickstep/src/com/android/quickstep/views/IconView.java b/quickstep/src/com/android/quickstep/views/IconView.java
index 7cc00b7..ed642df 100644
--- a/quickstep/src/com/android/quickstep/views/IconView.java
+++ b/quickstep/src/com/android/quickstep/views/IconView.java
@@ -21,26 +21,14 @@
 import android.util.AttributeSet;
 import android.view.View;
 
-import androidx.annotation.NonNull;
-
-import com.android.launcher3.FastBitmapDrawable;
-
-import java.util.ArrayList;
-
 /**
  * A view which draws a drawable stretched to fit its size. Unlike ImageView, it avoids relayout
  * when the drawable changes.
  */
 public class IconView extends View {
 
-    public interface OnScaleUpdateListener {
-        public void onScaleUpdate(float scale);
-    }
-
     private Drawable mDrawable;
 
-    private ArrayList<OnScaleUpdateListener> mScaleListeners;
-
     public IconView(Context context) {
         super(context);
     }
@@ -94,16 +82,6 @@
     }
 
     @Override
-    public void invalidateDrawable(@NonNull Drawable drawable) {
-        super.invalidateDrawable(drawable);
-        if (drawable instanceof FastBitmapDrawable && mScaleListeners != null) {
-            for (OnScaleUpdateListener listener : mScaleListeners) {
-                listener.onScaleUpdate(((FastBitmapDrawable) drawable).getScale());
-            }
-        }
-    }
-
-    @Override
     protected void onDraw(Canvas canvas) {
         if (mDrawable != null) {
             mDrawable.draw(canvas);
@@ -115,22 +93,6 @@
         return false;
     }
 
-    public void addUpdateScaleListener(OnScaleUpdateListener listener) {
-        if (mScaleListeners == null) {
-            mScaleListeners = new ArrayList<>();
-        }
-        mScaleListeners.add(listener);
-        if (mDrawable instanceof FastBitmapDrawable) {
-            listener.onScaleUpdate(((FastBitmapDrawable) mDrawable).getScale());
-        }
-    }
-
-    public void removeUpdateScaleListener(OnScaleUpdateListener listener) {
-        if (mScaleListeners != null) {
-            mScaleListeners.remove(listener);
-        }
-    }
-
     @Override
     public void setAlpha(float alpha) {
         super.setAlpha(alpha);
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index c1c8f01..fc2b4bc 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -33,7 +33,6 @@
     <attr name="workspaceKeyShadowColor" format="color" />
     <attr name="workspaceStatusBarScrim" format="reference" />
     <attr name="widgetsTheme" format="reference" />
-    <attr name="loadingIconColor" format="color" />
     <attr name="iconOnlyShortcutColor" format="color" />
     <attr name="eduHalfSheetBGColor" format="color" />
 
@@ -44,7 +43,6 @@
     <attr name="folderTextColor" format="color" />
     <attr name="folderHintColor" format="color" />
     <attr name="workProfileOverlayTextColor" format="color" />
-    <attr name="disabledIconAlpha" format="float" />
 
     <!-- BubbleTextView specific attributes. -->
     <declare-styleable name="BubbleTextView">
diff --git a/res/values/config.xml b/res/values/config.xml
index 65e2ab3..57f626c 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -87,8 +87,6 @@
 
     <!-- Default packages -->
     <string name="wallpaper_picker_package" translatable="false"></string>
-    <string name="calendar_component_name" translatable="false"></string>
-    <string name="clock_component_name" translatable="false"></string>
     <string name="local_colors_extraction_class" translatable="false"></string>
 
     <!-- Accessibility actions -->
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 2b58fb6..d333b49 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -16,7 +16,6 @@
 
 package com.android.launcher3;
 
-import static com.android.launcher3.FastBitmapDrawable.newIcon;
 import static com.android.launcher3.graphics.IconShape.getShape;
 import static com.android.launcher3.graphics.PreloadIconDrawable.newPendingIcon;
 import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
@@ -57,11 +56,12 @@
 import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.graphics.IconPalette;
 import com.android.launcher3.graphics.IconShape;
-import com.android.launcher3.graphics.PlaceHolderIconDrawable;
 import com.android.launcher3.graphics.PreloadIconDrawable;
 import com.android.launcher3.icons.DotRenderer;
+import com.android.launcher3.icons.FastBitmapDrawable;
 import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver;
 import com.android.launcher3.icons.LauncherIcons;
+import com.android.launcher3.icons.PlaceHolderIconDrawable;
 import com.android.launcher3.icons.cache.HandlerRunnable;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.ItemInfo;
@@ -92,12 +92,9 @@
     private static final int[] STATE_PRESSED = new int[]{android.R.attr.state_pressed};
     private static final float HIGHLIGHT_SCALE = 1.16f;
 
-
     private final PointF mTranslationForReorderBounce = new PointF(0, 0);
     private final PointF mTranslationForReorderPreview = new PointF(0, 0);
 
-    private static final int ICON_UPDATE_ANIMATION_DURATION = 375;
-
     private float mScaleForReorderBounce = 1f;
 
     protected final Paint mHighlightPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
@@ -335,7 +332,7 @@
 
     @UiThread
     protected void applyIconAndLabel(ItemInfoWithIcon info) {
-        FastBitmapDrawable iconDrawable = newIcon(getContext(), info);
+        FastBitmapDrawable iconDrawable = info.newIcon(getContext());
         mDotParams.color = IconPalette.getMutedColor(info.bitmap.color, 0.54f);
 
         setIcon(iconDrawable);
@@ -933,7 +930,7 @@
 
     private void resetIconScale() {
         if (mIcon instanceof FastBitmapDrawable) {
-            ((FastBitmapDrawable) mIcon).setScale(1f);
+            ((FastBitmapDrawable) mIcon).resetScale();
         }
     }
 
diff --git a/src/com/android/launcher3/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java
deleted file mode 100644
index 0027a50..0000000
--- a/src/com/android/launcher3/FastBitmapDrawable.java
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * Copyright (C) 2008 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;
-
-import static com.android.launcher3.anim.Interpolators.ACCEL;
-import static com.android.launcher3.anim.Interpolators.DEACCEL;
-
-import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.ColorFilter;
-import android.graphics.ColorMatrix;
-import android.graphics.ColorMatrixColorFilter;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.util.Property;
-
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.graphics.PlaceHolderIconDrawable;
-import com.android.launcher3.icons.BitmapInfo;
-import com.android.launcher3.model.data.ItemInfoWithIcon;
-import com.android.launcher3.util.Themes;
-
-
-public class FastBitmapDrawable extends Drawable {
-
-    private static final float PRESSED_SCALE = 1.1f;
-
-    private static final float DISABLED_DESATURATION = 1f;
-    private static final float DISABLED_BRIGHTNESS = 0.5f;
-
-    public static final int CLICK_FEEDBACK_DURATION = 200;
-
-    private static ColorFilter sDisabledFColorFilter;
-
-    protected final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG);
-    protected Bitmap mBitmap;
-    protected final int mIconColor;
-
-    @Nullable private ColorFilter mColorFilter;
-
-    private boolean mIsPressed;
-    private boolean mIsDisabled;
-    private float mDisabledAlpha = 1f;
-    private float mRoundedCornersRadius = 0f;
-    private final Path mClipPath = new Path();
-
-    // Animator and properties for the fast bitmap drawable's scale
-    private static final Property<FastBitmapDrawable, Float> SCALE
-            = new Property<FastBitmapDrawable, Float>(Float.TYPE, "scale") {
-        @Override
-        public Float get(FastBitmapDrawable fastBitmapDrawable) {
-            return fastBitmapDrawable.mScale;
-        }
-
-        @Override
-        public void set(FastBitmapDrawable fastBitmapDrawable, Float value) {
-            fastBitmapDrawable.mScale = value;
-            fastBitmapDrawable.invalidateSelf();
-        }
-    };
-    private ObjectAnimator mScaleAnimation;
-    private float mScale = 1;
-
-    private int mAlpha = 255;
-
-    public FastBitmapDrawable(Bitmap b) {
-        this(b, Color.TRANSPARENT);
-    }
-
-    public FastBitmapDrawable(BitmapInfo info) {
-        this(info.icon, info.color);
-    }
-
-    protected FastBitmapDrawable(Bitmap b, int iconColor) {
-        this(b, iconColor, false);
-    }
-
-    protected FastBitmapDrawable(Bitmap b, int iconColor, boolean isDisabled) {
-        mBitmap = b;
-        mIconColor = iconColor;
-        setFilterBitmap(true);
-        setIsDisabled(isDisabled);
-    }
-
-    @Override
-    public final void draw(Canvas canvas) {
-        if (mRoundedCornersRadius > 0) {
-            float radius = mRoundedCornersRadius * mScale;
-            mClipPath.reset();
-            mClipPath.addRoundRect(0, 0, getIntrinsicWidth(), getIntrinsicHeight(),
-                    radius, radius, Path.Direction.CCW);
-            canvas.clipPath(mClipPath);
-        }
-        if (mScale != 1f) {
-            int count = canvas.save();
-            Rect bounds = getBounds();
-            canvas.scale(mScale, mScale, bounds.exactCenterX(), bounds.exactCenterY());
-            drawInternal(canvas, bounds);
-            canvas.restoreToCount(count);
-        } else {
-            drawInternal(canvas, getBounds());
-        }
-    }
-
-    protected void drawInternal(Canvas canvas, Rect bounds) {
-        canvas.drawBitmap(mBitmap, null, bounds, mPaint);
-    }
-
-    @Override
-    public void setColorFilter(ColorFilter cf) {
-        mColorFilter = cf;
-        updateFilter();
-    }
-
-    @Override
-    public int getOpacity() {
-        return PixelFormat.TRANSLUCENT;
-    }
-
-    @Override
-    public void setAlpha(int alpha) {
-        if (mAlpha != alpha) {
-            mAlpha = alpha;
-            mPaint.setAlpha(alpha);
-            invalidateSelf();
-        }
-    }
-
-    @Override
-    public void setFilterBitmap(boolean filterBitmap) {
-        mPaint.setFilterBitmap(filterBitmap);
-        mPaint.setAntiAlias(filterBitmap);
-    }
-
-    public int getAlpha() {
-        return mAlpha;
-    }
-
-    public void setScale(float scale) {
-        if (mScaleAnimation != null) {
-            mScaleAnimation.cancel();
-            mScaleAnimation = null;
-        }
-        mScale = scale;
-        invalidateSelf();
-    }
-
-    public float getAnimatedScale() {
-        return mScaleAnimation == null ? 1 : mScale;
-    }
-
-    public float getScale() {
-        return mScale;
-    }
-
-    public void setRoundedCornersRadius(float radius) {
-        mRoundedCornersRadius = radius;
-    }
-
-    public float getRoundedCornersRadius() {
-        return mRoundedCornersRadius;
-    }
-
-    @Override
-    public int getIntrinsicWidth() {
-        return mBitmap.getWidth();
-    }
-
-    @Override
-    public int getIntrinsicHeight() {
-        return mBitmap.getHeight();
-    }
-
-    @Override
-    public int getMinimumWidth() {
-        return getBounds().width();
-    }
-
-    @Override
-    public int getMinimumHeight() {
-        return getBounds().height();
-    }
-
-    @Override
-    public boolean isStateful() {
-        return true;
-    }
-
-    @Override
-    public ColorFilter getColorFilter() {
-        return mPaint.getColorFilter();
-    }
-
-    @Override
-    protected boolean onStateChange(int[] state) {
-        boolean isPressed = false;
-        for (int s : state) {
-            if (s == android.R.attr.state_pressed) {
-                isPressed = true;
-                break;
-            }
-        }
-        if (mIsPressed != isPressed) {
-            mIsPressed = isPressed;
-
-            if (mScaleAnimation != null) {
-                mScaleAnimation.cancel();
-                mScaleAnimation = null;
-            }
-
-            if (mIsPressed) {
-                // Animate when going to pressed state
-                mScaleAnimation = ObjectAnimator.ofFloat(this, SCALE, PRESSED_SCALE);
-                mScaleAnimation.setDuration(CLICK_FEEDBACK_DURATION);
-                mScaleAnimation.setInterpolator(ACCEL);
-                mScaleAnimation.start();
-            } else {
-                if (isVisible()) {
-                    mScaleAnimation = ObjectAnimator.ofFloat(this, SCALE, 1f);
-                    mScaleAnimation.setDuration(CLICK_FEEDBACK_DURATION);
-                    mScaleAnimation.setInterpolator(DEACCEL);
-                    mScaleAnimation.start();
-                } else {
-                    mScale = 1f;
-                    invalidateSelf();
-                }
-            }
-            return true;
-        }
-        return false;
-    }
-
-    public void setIsDisabled(boolean isDisabled) {
-        if (mIsDisabled != isDisabled) {
-            mIsDisabled = isDisabled;
-            updateFilter();
-        }
-    }
-
-    protected boolean isDisabled() {
-        return mIsDisabled;
-    }
-
-    private ColorFilter getDisabledColorFilter() {
-        if (sDisabledFColorFilter == null) {
-            ColorMatrix tempBrightnessMatrix = new ColorMatrix();
-            ColorMatrix tempFilterMatrix = new ColorMatrix();
-
-            tempFilterMatrix.setSaturation(1f - DISABLED_DESATURATION);
-            float scale = 1 - DISABLED_BRIGHTNESS;
-            int brightnessI =   (int) (255 * DISABLED_BRIGHTNESS);
-            float[] mat = tempBrightnessMatrix.getArray();
-            mat[0] = scale;
-            mat[6] = scale;
-            mat[12] = scale;
-            mat[4] = brightnessI;
-            mat[9] = brightnessI;
-            mat[14] = brightnessI;
-            mat[18] = mDisabledAlpha;
-            tempFilterMatrix.preConcat(tempBrightnessMatrix);
-            sDisabledFColorFilter = new ColorMatrixColorFilter(tempFilterMatrix);
-        }
-        return sDisabledFColorFilter;
-    }
-
-    /**
-     * Updates the paint to reflect the current brightness and saturation.
-     */
-    protected void updateFilter() {
-        mPaint.setColorFilter(mIsDisabled ? getDisabledColorFilter() : mColorFilter);
-        invalidateSelf();
-    }
-
-    @Override
-    public ConstantState getConstantState() {
-        return new FastBitmapConstantState(mBitmap, mIconColor, mIsDisabled);
-    }
-
-    protected static class FastBitmapConstantState extends ConstantState {
-        protected final Bitmap mBitmap;
-        protected final int mIconColor;
-        protected final boolean mIsDisabled;
-
-        public FastBitmapConstantState(Bitmap bitmap, int color, boolean isDisabled) {
-            mBitmap = bitmap;
-            mIconColor = color;
-            mIsDisabled = isDisabled;
-        }
-
-        @Override
-        public FastBitmapDrawable newDrawable() {
-            return new FastBitmapDrawable(mBitmap, mIconColor, mIsDisabled);
-        }
-
-        @Override
-        public int getChangingConfigurations() {
-            return 0;
-        }
-    }
-
-    /**
-     * Interface to be implemented by custom {@link BitmapInfo} to handle drawable construction
-     */
-    public interface Factory {
-
-        /**
-         * Called to create a new drawable
-         */
-        FastBitmapDrawable newDrawable();
-    }
-
-    /**
-     * Returns a FastBitmapDrawable with the icon.
-     */
-    public static FastBitmapDrawable newIcon(Context context, ItemInfoWithIcon info) {
-        FastBitmapDrawable drawable = newIcon(context, info.bitmap);
-        drawable.setIsDisabled(info.isDisabled());
-        return drawable;
-    }
-
-    /**
-     * Creates a drawable for the provided BitmapInfo
-     */
-    public static FastBitmapDrawable newIcon(Context context, BitmapInfo info) {
-        final FastBitmapDrawable drawable;
-        if (info instanceof Factory) {
-            drawable = ((Factory) info).newDrawable();
-        } else if (info.isLowRes()) {
-            drawable = new PlaceHolderIconDrawable(info, context);
-        } else {
-            drawable = new FastBitmapDrawable(info);
-        }
-        drawable.mDisabledAlpha = Themes.getFloat(context, R.attr.disabledIconAlpha, 1f);
-        return drawable;
-    }
-}
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index e57844d..8825710 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -69,6 +69,7 @@
 import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
 import com.android.launcher3.graphics.GridCustomizationsProvider;
 import com.android.launcher3.graphics.TintedDrawableSpan;
+import com.android.launcher3.icons.FastBitmapDrawable;
 import com.android.launcher3.icons.IconProvider;
 import com.android.launcher3.icons.LauncherIcons;
 import com.android.launcher3.icons.ShortcutCachingLogic;
diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java
index 446c873..2f9c96e 100644
--- a/src/com/android/launcher3/WidgetPreviewLoader.java
+++ b/src/com/android/launcher3/WidgetPreviewLoader.java
@@ -37,6 +37,7 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.UiThread;
 
+import com.android.launcher3.icons.FastBitmapDrawable;
 import com.android.launcher3.icons.GraphicsUtils;
 import com.android.launcher3.icons.IconCache;
 import com.android.launcher3.icons.LauncherIcons;
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 6a16da9..bd17348 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -83,6 +83,7 @@
 import com.android.launcher3.graphics.PreloadIconDrawable;
 import com.android.launcher3.graphics.WorkspaceDragScrim;
 import com.android.launcher3.icons.BitmapRenderer;
+import com.android.launcher3.icons.FastBitmapDrawable;
 import com.android.launcher3.logger.LauncherAtom;
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index e2816f4..0f26ff4 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -44,7 +44,6 @@
 import androidx.dynamicanimation.animation.SpringAnimation;
 import androidx.dynamicanimation.animation.SpringForce;
 
-import com.android.launcher3.FastBitmapDrawable;
 import com.android.launcher3.FirstFrameAnimatorHelper;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherSettings;
@@ -52,6 +51,7 @@
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.icons.FastBitmapDrawable;
 import com.android.launcher3.icons.LauncherIcons;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.statemanager.StateManager.StateListener;
diff --git a/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java b/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java
index f543e47..29e7c18 100644
--- a/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java
+++ b/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java
@@ -28,7 +28,6 @@
 import android.os.Build;
 import android.os.Process;
 
-import com.android.launcher3.FastBitmapDrawable;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAnimUtils;
 import com.android.launcher3.LauncherAppState;
@@ -78,7 +77,7 @@
         Drawable d = mContext.getSystemService(LauncherApps.class)
                 .getShortcutIconDrawable(mInfo, LauncherAppState.getIDP(mContext).fillResIconDpi);
         if (d == null) {
-            d = new FastBitmapDrawable(cache.getDefaultIcon(Process.myUserHandle()));
+            d = cache.getDefaultIcon(Process.myUserHandle()).newIcon(mContext);
         }
         return d;
     }
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index 0235dfa..c1f4643 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -483,7 +483,7 @@
                 icon.verifyHighRes();
                 // Set the callback back to the actual icon, in case
                 // it was captured by the FolderIcon
-                Drawable d = icon.getCompoundDrawables()[1];
+                Drawable d = icon.getIcon();
                 if (d != null) {
                     d.setCallback(icon);
                 }
diff --git a/src/com/android/launcher3/folder/PreviewItemManager.java b/src/com/android/launcher3/folder/PreviewItemManager.java
index 9ae7faf..8244f01 100644
--- a/src/com/android/launcher3/folder/PreviewItemManager.java
+++ b/src/com/android/launcher3/folder/PreviewItemManager.java
@@ -16,7 +16,6 @@
 
 package com.android.launcher3.folder;
 
-import static com.android.launcher3.FastBitmapDrawable.newIcon;
 import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.ENTER_INDEX;
 import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.EXIT_INDEX;
 import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW;
@@ -33,10 +32,10 @@
 import android.graphics.drawable.Drawable;
 import android.util.FloatProperty;
 import android.view.View;
-import android.widget.TextView;
 
 import androidx.annotation.NonNull;
 
+import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.graphics.PreloadIconDrawable;
 import com.android.launcher3.model.data.ItemInfoWithIcon;
@@ -113,7 +112,7 @@
     }
 
     Drawable prepareCreateAnimation(final View destView) {
-        Drawable animateDrawable = ((TextView) destView).getCompoundDrawables()[1];
+        Drawable animateDrawable = ((BubbleTextView) destView).getIcon();
         computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(),
                 destView.getMeasuredWidth());
         mReferenceDrawable = animateDrawable;
@@ -401,7 +400,7 @@
             drawable.setLevel(item.getProgressLevel());
             p.drawable = drawable;
         } else {
-            p.drawable = newIcon(mContext, item);
+            p.drawable = item.newIcon(mContext);
         }
         p.drawable.setBounds(0, 0, mIconSize, mIconSize);
         p.item = item;
diff --git a/src/com/android/launcher3/graphics/DragPreviewProvider.java b/src/com/android/launcher3/graphics/DragPreviewProvider.java
index 9bc5444..0e61b98 100644
--- a/src/com/android/launcher3/graphics/DragPreviewProvider.java
+++ b/src/com/android/launcher3/graphics/DragPreviewProvider.java
@@ -30,13 +30,13 @@
 import android.view.View;
 
 import com.android.launcher3.BubbleTextView;
-import com.android.launcher3.FastBitmapDrawable;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.dragndrop.AppWidgetHostViewDrawable;
 import com.android.launcher3.dragndrop.DraggableView;
 import com.android.launcher3.icons.BitmapRenderer;
+import com.android.launcher3.icons.FastBitmapDrawable;
 import com.android.launcher3.util.SafeCloseable;
 import com.android.launcher3.widget.LauncherAppWidgetHostView;
 
diff --git a/src/com/android/launcher3/graphics/PlaceHolderIconDrawable.java b/src/com/android/launcher3/graphics/PlaceHolderIconDrawable.java
deleted file mode 100644
index b6d25c4..0000000
--- a/src/com/android/launcher3/graphics/PlaceHolderIconDrawable.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2018 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.graphics;
-
-import static androidx.core.graphics.ColorUtils.compositeColors;
-
-import static com.android.launcher3.graphics.IconShape.getShapePath;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Path;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-
-import androidx.core.graphics.ColorUtils;
-
-import com.android.launcher3.FastBitmapDrawable;
-import com.android.launcher3.R;
-import com.android.launcher3.icons.BitmapInfo;
-import com.android.launcher3.util.Themes;
-
-/**
- * Subclass which draws a placeholder icon when the actual icon is not yet loaded
- */
-public class PlaceHolderIconDrawable extends FastBitmapDrawable {
-
-    // Path in [0, 100] bounds.
-    private final Path mProgressPath;
-
-    public PlaceHolderIconDrawable(BitmapInfo info, Context context) {
-        super(info);
-
-        mProgressPath = getShapePath();
-        mPaint.setColor(compositeColors(
-                Themes.getAttrColor(context, R.attr.loadingIconColor), info.color));
-    }
-
-    @Override
-    protected void drawInternal(Canvas canvas, Rect bounds) {
-        int saveCount = canvas.save();
-        canvas.translate(bounds.left, bounds.top);
-        canvas.scale(bounds.width() / 100f, bounds.height() / 100f);
-        canvas.drawPath(mProgressPath, mPaint);
-        canvas.restoreToCount(saveCount);
-    }
-
-    /** Updates this placeholder to {@code newIcon} with animation. */
-    public void animateIconUpdate(Drawable newIcon) {
-        int placeholderColor = mPaint.getColor();
-        int originalAlpha = Color.alpha(placeholderColor);
-
-        ValueAnimator iconUpdateAnimation = ValueAnimator.ofInt(originalAlpha, 0);
-        iconUpdateAnimation.setDuration(375);
-        iconUpdateAnimation.addUpdateListener(valueAnimator -> {
-            int newAlpha = (int) valueAnimator.getAnimatedValue();
-            int newColor = ColorUtils.setAlphaComponent(placeholderColor, newAlpha);
-
-            newIcon.setColorFilter(new PorterDuffColorFilter(newColor, PorterDuff.Mode.SRC_ATOP));
-        });
-        iconUpdateAnimation.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                newIcon.setColorFilter(null);
-            }
-        });
-        iconUpdateAnimation.start();
-    }
-
-}
diff --git a/src/com/android/launcher3/graphics/PreloadIconDrawable.java b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
index ce824df..ac0ec5f 100644
--- a/src/com/android/launcher3/graphics/PreloadIconDrawable.java
+++ b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
@@ -37,8 +37,8 @@
 import android.util.SparseArray;
 import android.view.ContextThemeWrapper;
 
-import com.android.launcher3.FastBitmapDrawable;
 import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.icons.FastBitmapDrawable;
 import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.util.Themes;
 
diff --git a/src/com/android/launcher3/icons/ClockDrawableWrapper.java b/src/com/android/launcher3/icons/ClockDrawableWrapper.java
deleted file mode 100644
index 1bd252b..0000000
--- a/src/com/android/launcher3/icons/ClockDrawableWrapper.java
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- * 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.icons;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.graphics.drawable.AdaptiveIconDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Process;
-import android.os.SystemClock;
-import android.util.Log;
-
-import com.android.launcher3.FastBitmapDrawable;
-
-import java.util.Calendar;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Wrapper over {@link AdaptiveIconDrawable} to intercept icon flattening logic for dynamic
- * clock icons
- */
-@TargetApi(Build.VERSION_CODES.O)
-public class ClockDrawableWrapper extends AdaptiveIconDrawable implements BitmapInfo.Extender {
-
-    private static final String TAG = "ClockDrawableWrapper";
-
-    private static final boolean DISABLE_SECONDS = true;
-
-    // Time after which the clock icon should check for an update. The actual invalidate
-    // will only happen in case of any change.
-    public static final long TICK_MS = DISABLE_SECONDS ? TimeUnit.MINUTES.toMillis(1) : 200L;
-
-    private static final String LAUNCHER_PACKAGE = "com.android.launcher3";
-    private static final String ROUND_ICON_METADATA_KEY = LAUNCHER_PACKAGE
-            + ".LEVEL_PER_TICK_ICON_ROUND";
-    private static final String HOUR_INDEX_METADATA_KEY = LAUNCHER_PACKAGE + ".HOUR_LAYER_INDEX";
-    private static final String MINUTE_INDEX_METADATA_KEY = LAUNCHER_PACKAGE
-            + ".MINUTE_LAYER_INDEX";
-    private static final String SECOND_INDEX_METADATA_KEY = LAUNCHER_PACKAGE
-            + ".SECOND_LAYER_INDEX";
-    private static final String DEFAULT_HOUR_METADATA_KEY = LAUNCHER_PACKAGE
-            + ".DEFAULT_HOUR";
-    private static final String DEFAULT_MINUTE_METADATA_KEY = LAUNCHER_PACKAGE
-            + ".DEFAULT_MINUTE";
-    private static final String DEFAULT_SECOND_METADATA_KEY = LAUNCHER_PACKAGE
-            + ".DEFAULT_SECOND";
-
-    /* Number of levels to jump per second for the second hand */
-    private static final int LEVELS_PER_SECOND = 10;
-
-    public static final int INVALID_VALUE = -1;
-
-    private final AnimationInfo mAnimationInfo = new AnimationInfo();
-    private int mTargetSdkVersion;
-
-    public ClockDrawableWrapper(AdaptiveIconDrawable base) {
-        super(base.getBackground(), base.getForeground());
-    }
-
-    /**
-     * Loads and returns the wrapper from the provided package, or returns null
-     * if it is unable to load.
-     */
-    public static ClockDrawableWrapper forPackage(Context context, String pkg, int iconDpi) {
-        try {
-            PackageManager pm = context.getPackageManager();
-            ApplicationInfo appInfo =  pm.getApplicationInfo(pkg,
-                    PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.GET_META_DATA);
-            final Bundle metadata = appInfo.metaData;
-            if (metadata == null) {
-                return null;
-            }
-            int drawableId = metadata.getInt(ROUND_ICON_METADATA_KEY, 0);
-            if (drawableId == 0) {
-                return null;
-            }
-
-            Drawable drawable = pm.getResourcesForApplication(appInfo).getDrawableForDensity(
-                    drawableId, iconDpi).mutate();
-            if (!(drawable instanceof AdaptiveIconDrawable)) {
-                return null;
-            }
-
-            ClockDrawableWrapper wrapper =
-                    new ClockDrawableWrapper((AdaptiveIconDrawable) drawable);
-            wrapper.mTargetSdkVersion = appInfo.targetSdkVersion;
-            AnimationInfo info = wrapper.mAnimationInfo;
-
-            info.baseDrawableState = drawable.getConstantState();
-
-            info.hourLayerIndex = metadata.getInt(HOUR_INDEX_METADATA_KEY, INVALID_VALUE);
-            info.minuteLayerIndex = metadata.getInt(MINUTE_INDEX_METADATA_KEY, INVALID_VALUE);
-            info.secondLayerIndex = metadata.getInt(SECOND_INDEX_METADATA_KEY, INVALID_VALUE);
-
-            info.defaultHour = metadata.getInt(DEFAULT_HOUR_METADATA_KEY, 0);
-            info.defaultMinute = metadata.getInt(DEFAULT_MINUTE_METADATA_KEY, 0);
-            info.defaultSecond = metadata.getInt(DEFAULT_SECOND_METADATA_KEY, 0);
-
-            LayerDrawable foreground = (LayerDrawable) wrapper.getForeground();
-            int layerCount = foreground.getNumberOfLayers();
-            if (info.hourLayerIndex < 0 || info.hourLayerIndex >= layerCount) {
-                info.hourLayerIndex = INVALID_VALUE;
-            }
-            if (info.minuteLayerIndex < 0 || info.minuteLayerIndex >= layerCount) {
-                info.minuteLayerIndex = INVALID_VALUE;
-            }
-            if (info.secondLayerIndex < 0 || info.secondLayerIndex >= layerCount) {
-                info.secondLayerIndex = INVALID_VALUE;
-            } else if (DISABLE_SECONDS) {
-                foreground.setDrawable(info.secondLayerIndex, null);
-                info.secondLayerIndex = INVALID_VALUE;
-            }
-            return wrapper;
-        } catch (Exception e) {
-            Log.d(TAG, "Unable to load clock drawable info", e);
-        }
-        return null;
-    }
-
-    @Override
-    public BitmapInfo getExtendedInfo(Bitmap bitmap, int color, BaseIconFactory iconFactory) {
-        iconFactory.disableColorExtraction();
-        float [] scale = new float[1];
-        AdaptiveIconDrawable background = new AdaptiveIconDrawable(
-                getBackground().getConstantState().newDrawable(), null);
-        BitmapInfo bitmapInfo = iconFactory.createBadgedIconBitmap(background,
-                Process.myUserHandle(), mTargetSdkVersion, false, scale);
-
-        return new ClockBitmapInfo(bitmap, color, scale[0], mAnimationInfo, bitmapInfo.icon);
-    }
-
-    @Override
-    public void prepareToDrawOnUi() {
-        mAnimationInfo.applyTime(Calendar.getInstance(), (LayerDrawable) getForeground());
-    }
-
-    private static class AnimationInfo {
-
-        public ConstantState baseDrawableState;
-
-        public int hourLayerIndex;
-        public int minuteLayerIndex;
-        public int secondLayerIndex;
-        public int defaultHour;
-        public int defaultMinute;
-        public int defaultSecond;
-
-        boolean applyTime(Calendar time, LayerDrawable foregroundDrawable) {
-            time.setTimeInMillis(System.currentTimeMillis());
-
-            // We need to rotate by the difference from the default time if one is specified.
-            int convertedHour = (time.get(Calendar.HOUR) + (12 - defaultHour)) % 12;
-            int convertedMinute = (time.get(Calendar.MINUTE) + (60 - defaultMinute)) % 60;
-            int convertedSecond = (time.get(Calendar.SECOND) + (60 - defaultSecond)) % 60;
-
-            boolean invalidate = false;
-            if (hourLayerIndex != INVALID_VALUE) {
-                final Drawable hour = foregroundDrawable.getDrawable(hourLayerIndex);
-                if (hour.setLevel(convertedHour * 60 + time.get(Calendar.MINUTE))) {
-                    invalidate = true;
-                }
-            }
-
-            if (minuteLayerIndex != INVALID_VALUE) {
-                final Drawable minute = foregroundDrawable.getDrawable(minuteLayerIndex);
-                if (minute.setLevel(time.get(Calendar.HOUR) * 60 + convertedMinute)) {
-                    invalidate = true;
-                }
-            }
-
-            if (secondLayerIndex != INVALID_VALUE) {
-                final Drawable second = foregroundDrawable.getDrawable(secondLayerIndex);
-                if (second.setLevel(convertedSecond * LEVELS_PER_SECOND)) {
-                    invalidate = true;
-                }
-            }
-
-            return invalidate;
-        }
-    }
-
-    private static class ClockBitmapInfo extends BitmapInfo implements FastBitmapDrawable.Factory {
-
-        public final float scale;
-        public final int offset;
-        public final AnimationInfo animInfo;
-        public final Bitmap mFlattenedBackground;
-
-        ClockBitmapInfo(Bitmap icon, int color, float scale, AnimationInfo animInfo,
-                Bitmap background) {
-            super(icon, color);
-            this.scale = scale;
-            this.animInfo = animInfo;
-            this.offset = (int) Math.ceil(ShadowGenerator.BLUR_FACTOR * icon.getWidth());
-            this.mFlattenedBackground = background;
-        }
-
-        @Override
-        public FastBitmapDrawable newDrawable() {
-            return new ClockIconDrawable(this);
-        }
-    }
-
-    private static class ClockIconDrawable extends FastBitmapDrawable implements Runnable {
-
-        private final Calendar mTime = Calendar.getInstance();
-
-        private final ClockBitmapInfo mInfo;
-
-        private final AdaptiveIconDrawable mFullDrawable;
-        private final LayerDrawable mForeground;
-
-        ClockIconDrawable(ClockBitmapInfo clockInfo) {
-            super(clockInfo);
-
-            mInfo = clockInfo;
-
-            mFullDrawable = (AdaptiveIconDrawable) mInfo.animInfo.baseDrawableState.newDrawable();
-            mForeground = (LayerDrawable) mFullDrawable.getForeground();
-        }
-
-        @Override
-        protected void onBoundsChange(Rect bounds) {
-            super.onBoundsChange(bounds);
-            mFullDrawable.setBounds(bounds);
-        }
-
-        @Override
-        public void drawInternal(Canvas canvas, Rect bounds) {
-            if (mInfo == null) {
-                super.drawInternal(canvas, bounds);
-                return;
-            }
-            // draw the background that is already flattened to a bitmap
-            canvas.drawBitmap(mInfo.mFlattenedBackground, null, bounds, mPaint);
-
-            // prepare and draw the foreground
-            mInfo.animInfo.applyTime(mTime, mForeground);
-
-            canvas.scale(mInfo.scale, mInfo.scale,
-                    bounds.exactCenterX() + mInfo.offset, bounds.exactCenterY() + mInfo.offset);
-            canvas.clipPath(mFullDrawable.getIconMask());
-            mForeground.draw(canvas);
-
-            reschedule();
-        }
-
-        @Override
-        protected void updateFilter() {
-            super.updateFilter();
-            mFullDrawable.setColorFilter(mPaint.getColorFilter());
-        }
-
-        @Override
-        public void run() {
-            if (mInfo.animInfo.applyTime(mTime, mForeground)) {
-                invalidateSelf();
-            } else {
-                reschedule();
-            }
-        }
-
-        @Override
-        public boolean setVisible(boolean visible, boolean restart) {
-            boolean result = super.setVisible(visible, restart);
-            if (visible) {
-                reschedule();
-            } else {
-                unscheduleSelf(this);
-            }
-            return result;
-        }
-
-        private void reschedule() {
-            if (!isVisible()) {
-                return;
-            }
-
-            unscheduleSelf(this);
-            final long upTime = SystemClock.uptimeMillis();
-            final long step = TICK_MS; /* tick every 200 ms */
-            scheduleSelf(this, upTime - ((upTime % step)) + step);
-        }
-
-        @Override
-        public ConstantState getConstantState() {
-            return new ClockConstantState(mInfo, isDisabled());
-        }
-
-        private static class ClockConstantState extends FastBitmapConstantState {
-
-            private final ClockBitmapInfo mInfo;
-
-            ClockConstantState(ClockBitmapInfo info, boolean isDisabled) {
-                super(info.icon, info.color, isDisabled);
-                mInfo = info;
-            }
-
-            @Override
-            public FastBitmapDrawable newDrawable() {
-                ClockIconDrawable drawable = new ClockIconDrawable(mInfo);
-                drawable.setIsDisabled(mIsDisabled);
-                return drawable;
-            }
-        }
-    }
-}
diff --git a/src/com/android/launcher3/icons/IconProvider.java b/src/com/android/launcher3/icons/IconProvider.java
deleted file mode 100644
index 1468b27..0000000
--- a/src/com/android/launcher3/icons/IconProvider.java
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * 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.icons;
-
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ActivityInfo;
-import android.content.pm.LauncherActivityInfo;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Process;
-import android.os.UserHandle;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.launcher3.R;
-import com.android.launcher3.icons.BitmapInfo.Extender;
-import com.android.launcher3.pm.UserCache;
-import com.android.launcher3.util.ComponentKey;
-import com.android.launcher3.util.SafeCloseable;
-
-import java.util.Calendar;
-import java.util.function.BiConsumer;
-import java.util.function.BiFunction;
-
-/**
- * Class to handle icon loading from different packages
- */
-public class IconProvider {
-
-    private static final String TAG = "IconProvider";
-    private static final boolean DEBUG = false;
-
-    private static final String ICON_METADATA_KEY_PREFIX = ".dynamic_icons";
-
-    private static final String SYSTEM_STATE_SEPARATOR = " ";
-
-    // Default value returned if there are problems getting resources.
-    private static final int NO_ID = 0;
-
-    private static final BiFunction<LauncherActivityInfo, Integer, Drawable> LAI_LOADER =
-            LauncherActivityInfo::getIcon;
-
-    private static final BiFunction<ActivityInfo, PackageManager, Drawable> AI_LOADER =
-            ActivityInfo::loadUnbadgedIcon;
-
-
-    private final Context mContext;
-    private final ComponentName mCalendar;
-    private final ComponentName mClock;
-
-    public IconProvider(Context context) {
-        mContext = context;
-        mCalendar = parseComponentOrNull(context, R.string.calendar_component_name);
-        mClock = parseComponentOrNull(context, R.string.clock_component_name);
-    }
-
-    /**
-     * Adds any modification to the provided systemState for dynamic icons. This system state
-     * is used by caches to check for icon invalidation.
-     */
-    public String getSystemStateForPackage(String systemState, String packageName) {
-        if (mCalendar != null && mCalendar.getPackageName().equals(packageName)) {
-            return systemState + SYSTEM_STATE_SEPARATOR + getDay();
-        } else {
-            return systemState;
-        }
-    }
-
-    /**
-     * Loads the icon for the provided LauncherActivityInfo such that it can be drawn directly
-     * on the UI
-     */
-    public Drawable getIconForUI(LauncherActivityInfo info, int iconDpi) {
-        Drawable icon = getIcon(info, iconDpi);
-        if (icon instanceof BitmapInfo.Extender) {
-            ((Extender) icon).prepareToDrawOnUi();
-        }
-        return icon;
-    }
-
-    /**
-     * Loads the icon for the provided LauncherActivityInfo
-     */
-    public Drawable getIcon(LauncherActivityInfo info, int iconDpi) {
-        return getIcon(info.getApplicationInfo().packageName, info.getUser(),
-                info, iconDpi, LAI_LOADER);
-    }
-
-    /**
-     * Loads the icon for the provided activity info
-     */
-    public Drawable getIcon(ActivityInfo info, UserHandle user) {
-        return getIcon(info.applicationInfo.packageName, user, info, mContext.getPackageManager(),
-                AI_LOADER);
-    }
-
-    private <T, P> Drawable getIcon(String packageName, UserHandle user, T obj, P param,
-            BiFunction<T, P, Drawable> loader) {
-        Drawable icon = null;
-        if (mCalendar != null && mCalendar.getPackageName().equals(packageName)) {
-            icon = loadCalendarDrawable(0);
-        } else if (mClock != null
-                && mClock.getPackageName().equals(packageName)
-                && Process.myUserHandle().equals(user)) {
-            icon = loadClockDrawable(0);
-        }
-        return icon == null ? loader.apply(obj, param) : icon;
-    }
-
-    private Drawable loadCalendarDrawable(int iconDpi) {
-        PackageManager pm = mContext.getPackageManager();
-        try {
-            final Bundle metadata = pm.getActivityInfo(
-                    mCalendar,
-                    PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_META_DATA)
-                    .metaData;
-            final Resources resources = pm.getResourcesForApplication(mCalendar.getPackageName());
-            final int id = getDynamicIconId(metadata, resources);
-            if (id != NO_ID) {
-                if (DEBUG) Log.d(TAG, "Got icon #" + id);
-                return resources.getDrawableForDensity(id, iconDpi, null /* theme */);
-            }
-        } catch (PackageManager.NameNotFoundException e) {
-            if (DEBUG) {
-                Log.d(TAG, "Could not get activityinfo or resources for package: "
-                        + mCalendar.getPackageName());
-            }
-        }
-        return null;
-    }
-
-    private Drawable loadClockDrawable(int iconDpi) {
-        return ClockDrawableWrapper.forPackage(mContext, mClock.getPackageName(), iconDpi);
-    }
-
-    protected boolean isClockIcon(ComponentKey key) {
-        return mClock != null && mClock.equals(key.componentName)
-                && Process.myUserHandle().equals(key.user);
-    }
-
-    /**
-     * @param metadata metadata of the default activity of Calendar
-     * @param resources from the Calendar package
-     * @return the resource id for today's Calendar icon; 0 if resources cannot be found.
-     */
-    private int getDynamicIconId(Bundle metadata, Resources resources) {
-        if (metadata == null) {
-            return NO_ID;
-        }
-        String key = mCalendar.getPackageName() + ICON_METADATA_KEY_PREFIX;
-        final int arrayId = metadata.getInt(key, NO_ID);
-        if (arrayId == NO_ID) {
-            return NO_ID;
-        }
-        try {
-            return resources.obtainTypedArray(arrayId).getResourceId(getDay(), NO_ID);
-        } catch (Resources.NotFoundException e) {
-            if (DEBUG) {
-                Log.d(TAG, "package defines '" + key + "' but corresponding array not found");
-            }
-            return NO_ID;
-        }
-    }
-
-    /**
-     * @return Today's day of the month, zero-indexed.
-     */
-    private int getDay() {
-        return Calendar.getInstance().get(Calendar.DAY_OF_MONTH) - 1;
-    }
-
-
-    /**
-     * Registers a callback to listen for calendar icon changes.
-     * The callback receives the packageName for the calendar icon
-     */
-    public static SafeCloseable registerIconChangeListener(Context context,
-            BiConsumer<String, UserHandle> callback, Handler handler) {
-        ComponentName calendar = parseComponentOrNull(context, R.string.calendar_component_name);
-        ComponentName clock = parseComponentOrNull(context, R.string.clock_component_name);
-
-        if (calendar == null && clock == null) {
-            return () -> { };
-        }
-
-        BroadcastReceiver receiver = new DateTimeChangeReceiver(callback);
-        final IntentFilter filter = new IntentFilter(Intent.ACTION_TIMEZONE_CHANGED);
-        if (calendar != null) {
-            filter.addAction(Intent.ACTION_TIME_CHANGED);
-            filter.addAction(Intent.ACTION_DATE_CHANGED);
-        }
-        context.registerReceiver(receiver, filter, null, handler);
-
-        return () -> context.unregisterReceiver(receiver);
-    }
-
-    private static class DateTimeChangeReceiver extends BroadcastReceiver {
-
-        private final BiConsumer<String, UserHandle> mCallback;
-
-        DateTimeChangeReceiver(BiConsumer<String, UserHandle> callback) {
-            mCallback = callback;
-        }
-
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (Intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
-                ComponentName clock = parseComponentOrNull(context, R.string.clock_component_name);
-                if (clock != null) {
-                    mCallback.accept(clock.getPackageName(), Process.myUserHandle());
-                }
-            }
-
-            ComponentName calendar =
-                    parseComponentOrNull(context, R.string.calendar_component_name);
-            if (calendar != null) {
-                for (UserHandle user : UserCache.INSTANCE.get(context).getUserProfiles()) {
-                    mCallback.accept(calendar.getPackageName(), user);
-                }
-            }
-
-        }
-    }
-
-    private static ComponentName parseComponentOrNull(Context context, int resId) {
-        String cn = context.getString(resId);
-        return TextUtils.isEmpty(cn) ? null : ComponentName.unflattenFromString(cn);
-
-    }
-}
diff --git a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
index d95e708..76b2ab0 100644
--- a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
+++ b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
@@ -23,6 +23,7 @@
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.icons.BitmapInfo;
+import com.android.launcher3.icons.FastBitmapDrawable;
 import com.android.launcher3.pm.PackageInstallInfo;
 import com.android.launcher3.util.PackageManagerHelper;
 
@@ -216,4 +217,14 @@
      * @return a copy of this
      */
     public abstract ItemInfoWithIcon clone();
+
+
+    /**
+     * Returns a FastBitmapDrawable with the icon.
+     */
+    public FastBitmapDrawable newIcon(Context context) {
+        FastBitmapDrawable drawable = bitmap.newIcon(context);
+        drawable.setIsDisabled(isDisabled());
+        return drawable;
+    }
 }
diff --git a/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java b/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java
index 530aaed..cecbb0d 100644
--- a/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java
+++ b/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java
@@ -23,12 +23,12 @@
 import android.graphics.drawable.Drawable;
 import android.view.View;
 
-import com.android.launcher3.FastBitmapDrawable;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.graphics.DragPreviewProvider;
 import com.android.launcher3.icons.BitmapRenderer;
+import com.android.launcher3.icons.FastBitmapDrawable;
 
 /**
  * Extension of {@link DragPreviewProvider} which generates bitmaps scaled to the default icon size.
diff --git a/src/com/android/launcher3/util/SafeCloseable.java b/src/com/android/launcher3/util/SafeCloseable.java
deleted file mode 100644
index ba8ee04..0000000
--- a/src/com/android/launcher3/util/SafeCloseable.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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;
-
-/**
- * Extension of closeable which does not throw an exception
- */
-public interface SafeCloseable extends AutoCloseable {
-
-    @Override
-    void close();
-}
diff --git a/src/com/android/launcher3/util/Themes.java b/src/com/android/launcher3/util/Themes.java
index 512a286..e8a0635 100644
--- a/src/com/android/launcher3/util/Themes.java
+++ b/src/com/android/launcher3/util/Themes.java
@@ -28,6 +28,7 @@
 
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.icons.GraphicsUtils;
 import com.android.launcher3.uioverrides.WallpaperColorInfo;
 
 /**
@@ -92,10 +93,7 @@
     }
 
     public static int getAttrColor(Context context, int attr) {
-        TypedArray ta = context.obtainStyledAttributes(new int[]{attr});
-        int colorAccent = ta.getColor(0, 0);
-        ta.recycle();
-        return colorAccent;
+        return GraphicsUtils.getAttrColor(context, attr);
     }
 
     public static boolean getAttrBoolean(Context context, int attr) {
@@ -120,23 +118,6 @@
     }
 
     /**
-     * Returns the alpha corresponding to the theme attribute {@param attr}, in the range [0, 255].
-     */
-    public static int getAlpha(Context context, int attr) {
-        return (int) (255 * getFloat(context, attr, 0) + 0.5f);
-    }
-
-    /**
-     * Returns the alpha corresponding to the theme attribute {@param attr}
-     */
-    public static float getFloat(Context context, int attr, float defValue) {
-        TypedArray ta = context.obtainStyledAttributes(new int[]{attr});
-        float value = ta.getFloat(0, defValue);
-        ta.recycle();
-        return value;
-    }
-
-    /**
      * Scales a color matrix such that, when applied to color R G B A, it produces R' G' B' A' where
      * R' = r * R
      * G' = g * G
diff --git a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
index 4b113d8..3308eec 100644
--- a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
@@ -16,7 +16,6 @@
 
 package com.android.launcher3.widget;
 
-import static com.android.launcher3.FastBitmapDrawable.newIcon;
 import static com.android.launcher3.graphics.PreloadIconDrawable.newPendingIcon;
 
 import android.content.Context;
@@ -37,8 +36,8 @@
 import android.widget.RemoteViews;
 
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.FastBitmapDrawable;
 import com.android.launcher3.R;
+import com.android.launcher3.icons.FastBitmapDrawable;
 import com.android.launcher3.icons.IconCache;
 import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver;
 import com.android.launcher3.model.data.ItemInfoWithIcon;
@@ -152,12 +151,12 @@
             //   2) Preload icon in the center
             //   3) Setup icon in the center and app icon in the top right corner.
             if (mDisabledForSafeMode) {
-                FastBitmapDrawable disabledIcon = newIcon(getContext(), info);
+                FastBitmapDrawable disabledIcon = info.newIcon(getContext());
                 disabledIcon.setIsDisabled(true);
                 mCenterDrawable = disabledIcon;
                 mSettingIconDrawable = null;
             } else if (isReadyForClickSetup()) {
-                mCenterDrawable = newIcon(getContext(), info);
+                mCenterDrawable = info.newIcon(getContext());
                 mSettingIconDrawable = getResources().getDrawable(R.drawable.ic_setting).mutate();
                 updateSettingColor(info.bitmap.color);
             } else {
diff --git a/src/com/android/launcher3/widget/PendingItemDragHelper.java b/src/com/android/launcher3/widget/PendingItemDragHelper.java
index 08bb662..ad0a401 100644
--- a/src/com/android/launcher3/widget/PendingItemDragHelper.java
+++ b/src/com/android/launcher3/widget/PendingItemDragHelper.java
@@ -29,7 +29,6 @@
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.DragSource;
-import com.android.launcher3.FastBitmapDrawable;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.PendingAddItemInfo;
@@ -38,6 +37,7 @@
 import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.dragndrop.DraggableView;
 import com.android.launcher3.graphics.DragPreviewProvider;
+import com.android.launcher3.icons.FastBitmapDrawable;
 import com.android.launcher3.icons.LauncherIcons;
 import com.android.launcher3.widget.dragndrop.AppWidgetHostViewDragListener;
 
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index 2b4b9ea..c11b68e 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -40,12 +40,12 @@
 import com.android.launcher3.BaseActivity;
 import com.android.launcher3.CheckLongPressHelper;
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.FastBitmapDrawable;
 import com.android.launcher3.R;
 import com.android.launcher3.WidgetPreviewLoader;
 import com.android.launcher3.dragndrop.AppWidgetHostViewDrawable;
 import com.android.launcher3.icons.BaseIconFactory;
 import com.android.launcher3.icons.BitmapRenderer;
+import com.android.launcher3.icons.FastBitmapDrawable;
 import com.android.launcher3.model.WidgetItem;
 
 /**
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
index 75dd409..497c72e 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
@@ -15,8 +15,6 @@
  */
 package com.android.launcher3.widget.picker;
 
-import static com.android.launcher3.FastBitmapDrawable.newIcon;
-
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -32,11 +30,11 @@
 import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.FastBitmapDrawable;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
-import com.android.launcher3.graphics.PlaceHolderIconDrawable;
+import com.android.launcher3.icons.FastBitmapDrawable;
 import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver;
+import com.android.launcher3.icons.PlaceHolderIconDrawable;
 import com.android.launcher3.icons.cache.HandlerRunnable;
 import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.model.data.PackageItemInfo;
@@ -145,7 +143,7 @@
     }
 
     private void setIcon(PackageItemInfo info) {
-        FastBitmapDrawable icon = newIcon(getContext(), info);
+        FastBitmapDrawable icon = info.newIcon(getContext());
         applyDrawables(icon);
         mIconDrawable = icon;
         if (mIconDrawable != null) {