Merge "Only add widgets system shortcut if widgets exist" into ub-launcher3-dorval
diff --git a/res/drawable-v26/adaptive_icon_drawable_wrapper.xml b/res/drawable-v26/adaptive_icon_drawable_wrapper.xml
index 7ad8e2c..2d78b69 100644
--- a/res/drawable-v26/adaptive_icon_drawable_wrapper.xml
+++ b/res/drawable-v26/adaptive_icon_drawable_wrapper.xml
@@ -15,7 +15,7 @@
      limitations under the License.
 -->
 <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
-    <background android:color="#FFE0E0E0"/>
+    <background android:drawable="@color/legacy_icon_background"/>
     <foreground>
         <com.android.launcher3.graphics.FixedScaleDrawable />
     </foreground>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 3ce7baa..f148cf2 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -45,5 +45,6 @@
     <!-- System shortcuts -->
     <color name="system_shortcuts_icon_color">@android:color/tertiary_text_light</color>
 
+    <color name="legacy_icon_background">#FFFFFF</color>
     <color name="icon_background">#E0E0E0</color> <!-- Gray 300 -->
 </resources>
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index 924b79b..2a8397c 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -767,7 +767,7 @@
     }
 
     private static final class IconDB extends SQLiteCacheHelper {
-        private final static int DB_VERSION = 11;
+        private final static int DB_VERSION = 12;
 
         private final static int RELEASE_VERSION = DB_VERSION +
                 (FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION ? 0 : 1);
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 3793bb5..5bde839 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -1259,6 +1259,10 @@
                         sBgDataModel.folders.remove(folderId);
                         sBgDataModel.itemsIdMap.remove(folderId);
                     }
+
+                    // Remove any ghost widgets
+                    LauncherSettings.Settings.call(contentResolver,
+                            LauncherSettings.Settings.METHOD_REMOVE_GHOST_WIDGETS);
                 }
 
                 // Unpin shortcuts that don't exist on the workspace.
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 6302744..7d85ac1 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -47,7 +47,6 @@
 import android.os.UserManager;
 import android.text.TextUtils;
 import android.util.Log;
-import android.view.ViewGroup;
 
 import com.android.launcher3.AutoInstallsLayout.LayoutParserCallback;
 import com.android.launcher3.LauncherSettings.Favorites;
@@ -67,10 +66,11 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.lang.reflect.Method;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Locale;
+import java.util.HashSet;
 
 public class LauncherProvider extends ContentProvider {
     private static final String TAG = "LauncherProvider";
@@ -85,7 +85,7 @@
      * overtime. These must be backwards compatible, else we risk breaking old devices during
      * restore or binary version downgrade.
      */
-    private static final int DATA_VERSION = 2;
+    private static final int DATA_VERSION = 3;
 
     private static final String PREF_KEY_DATA_VERISON = "provider_data_version";
 
@@ -262,10 +262,11 @@
 
             if (cn != null) {
                 try {
-                    int appWidgetId = new AppWidgetHost(getContext(), Launcher.APPWIDGET_HOST_ID)
-                            .allocateAppWidgetId();
+                    AppWidgetHost widgetHost = mOpenHelper.newLauncherWidgetHost();
+                    int appWidgetId = widgetHost.allocateAppWidgetId();
                     values.put(LauncherSettings.Favorites.APPWIDGET_ID, appWidgetId);
                     if (!appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId,cn)) {
+                        widgetHost.deleteAppWidgetId(appWidgetId);
                         return false;
                     }
                 } catch (RuntimeException e) {
@@ -347,23 +348,7 @@
 
         if (Binder.getCallingPid() != Process.myPid()
                 && Favorites.TABLE_NAME.equalsIgnoreCase(args.table)) {
-            String widgetSelection = TextUtils.isEmpty(args.where) ? "1=1" : args.where;
-            widgetSelection = String.format(Locale.ENGLISH, "%1$s = %2$d AND ( %3$s )",
-                    Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPWIDGET, widgetSelection);
-            try (Cursor c = db.query(Favorites.TABLE_NAME, new String[] { Favorites.APPWIDGET_ID },
-                    widgetSelection, args.args, null, null, null)) {
-                AppWidgetHost host = new AppWidgetHost(getContext(), Launcher.APPWIDGET_HOST_ID);
-                while (c.moveToNext()) {
-                    int widgetId = c.getInt(0);
-                    if (widgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
-                        try {
-                            host.deleteAppWidgetId(widgetId);
-                        } catch (RuntimeException e) {
-                            Log.e(TAG, "Error deleting widget id " + widgetId, e);
-                        }
-                    }
-                }
-            }
+            mOpenHelper.removeGhostWidgets(mOpenHelper.getWritableDatabase());
         }
         int count = db.delete(args.table, args.where, args.args);
         if (count > 0) {
@@ -441,6 +426,10 @@
                 loadDefaultFavoritesIfNecessary();
                 return null;
             }
+            case LauncherSettings.Settings.METHOD_REMOVE_GHOST_WIDGETS: {
+                mOpenHelper.removeGhostWidgets(mOpenHelper.getWritableDatabase());
+                return null;
+            }
         }
         return null;
     }
@@ -509,7 +498,7 @@
         if (sp.getBoolean(EMPTY_DATABASE_CREATED, false)) {
             Log.d(TAG, "loading default workspace");
 
-            AppWidgetHost widgetHost = new AppWidgetHost(getContext(), Launcher.APPWIDGET_HOST_ID);
+            AppWidgetHost widgetHost = mOpenHelper.newLauncherWidgetHost();
             AutoInstallsLayout loader = createWorkspaceLoaderFromAppRestriction(widgetHost);
             if (loader == null) {
                 loader = AutoInstallsLayout.get(getContext(),widgetHost, mOpenHelper);
@@ -659,7 +648,7 @@
         protected void onEmptyDbCreated() {
             // Database was just created, so wipe any previous widgets
             if (mWidgetHostResetHandler != null) {
-                new AppWidgetHost(mContext, Launcher.APPWIDGET_HOST_ID).deleteHost();
+                newLauncherWidgetHost().deleteHost();
                 mWidgetHostResetHandler.sendEmptyMessage(
                         ChangeListenerWrapper.MSG_APP_WIDGET_HOST_RESET);
             }
@@ -765,6 +754,8 @@
                     }
                 }
                 case 2:
+                    removeGhostWidgets(db);
+                case 3:
                     // data updated
                     return;
             }
@@ -906,6 +897,47 @@
         }
 
         /**
+         * Removes widgets which are registered to the Launcher's host, but are not present
+         * in our model.
+         */
+        public void removeGhostWidgets(SQLiteDatabase db) {
+            // Get all existing widget ids.
+            final AppWidgetHost host = newLauncherWidgetHost();
+            final int[] allWidgets;
+            try {
+                Method getter = AppWidgetHost.class.getDeclaredMethod("getAppWidgetIds");
+                getter.setAccessible(true);
+                allWidgets = (int[]) getter.invoke(host);
+            } catch (Exception e) {
+                Log.e(TAG, "getAppWidgetIds not supported", e);
+                return;
+            }
+            try {
+                Cursor c = db.query(Favorites.TABLE_NAME,
+                        new String[] {Favorites.APPWIDGET_ID },
+                        "itemType=" + Favorites.ITEM_TYPE_APPWIDGET, null, null, null, null);
+                HashSet<Integer> validWidgets = new HashSet<>();
+                while (c.moveToNext()) {
+                    validWidgets.add(c.getInt(0));
+                }
+                c.close();
+
+                for (int widgetId : allWidgets) {
+                    if (!validWidgets.contains(widgetId)) {
+                        try {
+                            FileLog.d(TAG, "Deleting invalid widget " + widgetId);
+                            host.deleteAppWidgetId(widgetId);
+                        } catch (RuntimeException e) {
+                            // Ignore
+                        }
+                    }
+                }
+            } catch (SQLException ex) {
+                Log.w(TAG, "Error getting widgets list", ex);
+            }
+        }
+
+        /**
          * Replaces all shortcuts of type {@link Favorites#ITEM_TYPE_SHORTCUT} which have a valid
          * launcher activity target with {@link Favorites#ITEM_TYPE_APPLICATION}.
          */
@@ -1074,6 +1106,10 @@
             return mMaxItemId;
         }
 
+        public AppWidgetHost newLauncherWidgetHost() {
+            return new AppWidgetHost(mContext, Launcher.APPWIDGET_HOST_ID);
+        }
+
         @Override
         public long insertAndCheck(SQLiteDatabase db, ContentValues values) {
             return dbInsertAndCheck(this, db, Favorites.TABLE_NAME, null, values);
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index af2c102..b25b256 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -299,6 +299,8 @@
         public static final String EXTRA_EXTRACTED_COLORS = "extra_extractedColors";
         public static final String EXTRA_WALLPAPER_ID = "extra_wallpaperId";
 
+        public static final String METHOD_REMOVE_GHOST_WIDGETS = "remove_ghost_widgets";
+
         public static final String EXTRA_VALUE = "value";
 
         public static Bundle call(ContentResolver cr, String method) {
diff --git a/src/com/android/launcher3/dragndrop/PinItemDragListener.java b/src/com/android/launcher3/dragndrop/PinItemDragListener.java
index 4b402f4..df0c47c 100644
--- a/src/com/android/launcher3/dragndrop/PinItemDragListener.java
+++ b/src/com/android/launcher3/dragndrop/PinItemDragListener.java
@@ -236,6 +236,10 @@
             mLauncher.exitSpringLoadedDragModeDelayed(true,
                     Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);
         }
+
+        if (!success) {
+            d.deferDragViewCleanupPostAnimation = false;
+        }
         postCleanup();
     }
 
diff --git a/src/com/android/launcher3/graphics/FixedScaleDrawable.java b/src/com/android/launcher3/graphics/FixedScaleDrawable.java
index 4be4bd5..7ee3d80 100644
--- a/src/com/android/launcher3/graphics/FixedScaleDrawable.java
+++ b/src/com/android/launcher3/graphics/FixedScaleDrawable.java
@@ -19,15 +19,17 @@
 
     // TODO b/33553066 use the constant defined in MaskableIconDrawable
     private static final float LEGACY_ICON_SCALE = .7f * .6667f;
+    private float mScale;
 
     public FixedScaleDrawable() {
         super(new ColorDrawable());
+        mScale = LEGACY_ICON_SCALE;
     }
 
     @Override
     public void draw(Canvas canvas) {
         int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
-        canvas.scale(LEGACY_ICON_SCALE, LEGACY_ICON_SCALE,
+        canvas.scale(mScale, mScale,
                 getBounds().exactCenterX(), getBounds().exactCenterY());
         super.draw(canvas);
         canvas.restoreToCount(saveCount);
@@ -38,4 +40,8 @@
 
     @Override
     public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) { }
+
+    public void setScale(float scale) {
+        mScale = scale * LEGACY_ICON_SCALE;
+    }
 }
diff --git a/src/com/android/launcher3/graphics/IconNormalizer.java b/src/com/android/launcher3/graphics/IconNormalizer.java
index 70b3dd6..34d0b72 100644
--- a/src/com/android/launcher3/graphics/IconNormalizer.java
+++ b/src/com/android/launcher3/graphics/IconNormalizer.java
@@ -20,15 +20,31 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
 import android.graphics.RectF;
+import android.graphics.drawable.AdaptiveIconDrawable;
 import android.graphics.drawable.Drawable;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.util.Log;
 
 import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.Utilities;
 
+import java.io.File;
+import java.io.FileOutputStream;
 import java.nio.ByteBuffer;
+import java.util.Random;
 
 public class IconNormalizer {
 
+    private static final String TAG = "IconNormalizer";
+    private static final boolean DEBUG = false;
     // Ratio of icon visible area to full icon size for a square shaped icon
     private static final float MAX_SQUARE_AREA_FACTOR = 375.0f / 576;
     // Ratio of icon visible area to full icon size for a circular shaped icon
@@ -42,17 +58,38 @@
 
     private static final int MIN_VISIBLE_ALPHA = 40;
 
+    // Shape detection related constants
+    private static final float BOUND_RATIO_MARGIN = .05f;
+    private static final float PIXEL_DIFF_PERCENTAGE_THRESHOLD = 0.005f;
+    private static final float SCALE_NOT_INITIALIZED = 0;
+
     private static final Object LOCK = new Object();
     private static IconNormalizer sIconNormalizer;
 
     private final int mMaxSize;
     private final Bitmap mBitmap;
+    private final Bitmap mBitmapARGB;
     private final Canvas mCanvas;
+    private final Paint mPaintMaskShape;
+    private final Paint mPaintMaskShapeOutline;
     private final byte[] mPixels;
+    private final int[] mPixelsARGB;
+
+    private final Rect mAdaptiveIconBounds;
+    private float mAdaptiveIconScale;
 
     // for each y, stores the position of the leftmost x and the rightmost x
     private final float[] mLeftBorder;
     private final float[] mRightBorder;
+    private final Rect mBounds;
+    private final Matrix mMatrix;
+
+    private Paint mPaintIcon;
+    private Canvas mCanvasARGB;
+
+    private File mDir;
+    private int mFileId;
+    private Random mRandom;
 
     private IconNormalizer(Context context) {
         // Use twice the icon size as maximum size to avoid scaling down twice.
@@ -60,9 +97,122 @@
         mBitmap = Bitmap.createBitmap(mMaxSize, mMaxSize, Bitmap.Config.ALPHA_8);
         mCanvas = new Canvas(mBitmap);
         mPixels = new byte[mMaxSize * mMaxSize];
-
+        mPixelsARGB = new int[mMaxSize * mMaxSize];
         mLeftBorder = new float[mMaxSize];
         mRightBorder = new float[mMaxSize];
+        mBounds = new Rect();
+        mAdaptiveIconBounds = new Rect();
+
+        // Needed for isShape() method
+        mBitmapARGB = Bitmap.createBitmap(mMaxSize, mMaxSize, Bitmap.Config.ARGB_8888);
+        mCanvasARGB = new Canvas(mBitmapARGB);
+
+        mPaintIcon = new Paint();
+        mPaintIcon.setColor(Color.WHITE);
+
+        mPaintMaskShape = new Paint();
+        mPaintMaskShape.setColor(Color.RED);
+        mPaintMaskShape.setStyle(Paint.Style.FILL);
+        mPaintMaskShape.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR));
+
+        mPaintMaskShapeOutline = new Paint();
+        mPaintMaskShapeOutline.setStrokeWidth(2 * context.getResources().getDisplayMetrics().density);
+        mPaintMaskShapeOutline.setStyle(Paint.Style.STROKE);
+        mPaintMaskShapeOutline.setColor(Color.BLACK);
+        mPaintMaskShapeOutline.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
+
+        mMatrix = new Matrix();
+        int[] mPixels = new int[mMaxSize * mMaxSize];
+        mAdaptiveIconScale = SCALE_NOT_INITIALIZED;
+
+        mDir = context.getExternalFilesDir(null);
+        mRandom = new Random();
+    }
+
+    /**
+     * Returns if the shape of the icon is same as the path.
+     * For this method to work, the shape path bounds should be in [0,1]x[0,1] bounds.
+     */
+    private boolean isShape(Path maskPath) {
+        // Condition1:
+        // If width and height of the path not close to a square, then the icon shape is
+        // not same as the mask shape.
+        float iconRatio = ((float) mBounds.width()) / mBounds.height();
+        if (Math.abs(iconRatio - 1) > BOUND_RATIO_MARGIN) {
+            if (DEBUG) {
+                Log.d(TAG, "Not same as mask shape because width != height. " + iconRatio);
+            }
+            return false;
+        }
+
+        // Condition 2:
+        // Actual icon (white) and the fitted shape (e.g., circle)(red) XOR operation
+        // should generate transparent image, if the actual icon is equivalent to the shape.
+        mFileId = mRandom.nextInt();
+        mBitmapARGB.eraseColor(Color.TRANSPARENT);
+        mCanvasARGB.drawBitmap(mBitmap, 0, 0, mPaintIcon);
+
+        if (DEBUG) {
+            final File beforeFile = new File(mDir, "isShape" + mFileId + "_before.png");
+            try {
+                mBitmapARGB.compress(Bitmap.CompressFormat.PNG, 100,
+                        new FileOutputStream(beforeFile));
+            } catch (Exception e) {}
+        }
+
+        // Fit the shape within the icon's bounding box
+        mMatrix.reset();
+        mMatrix.setScale(mBounds.width(), mBounds.height());
+        mMatrix.postTranslate(mBounds.left, mBounds.top);
+        maskPath.transform(mMatrix);
+
+        // XOR operation
+        mCanvasARGB.drawPath(maskPath, mPaintMaskShape);
+
+        // DST_OUT operation around the mask path outline
+        mCanvasARGB.drawPath(maskPath, mPaintMaskShapeOutline);
+
+        boolean isTrans = isTransparentBitmap(mBitmapARGB);
+        if (DEBUG) {
+            final File afterFile = new File(mDir, "isShape" + mFileId + "_after_" + isTrans + ".png");
+            try {
+                mBitmapARGB.compress(Bitmap.CompressFormat.PNG, 100,
+                        new FileOutputStream(afterFile));
+            } catch (Exception e) {}
+        }
+
+        // Check if the result is almost transparent
+        if (!isTrans) {
+            if (DEBUG) {
+                Log.d(TAG, "Not same as mask shape");
+            }
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Used to determine if certain the bitmap is transparent.
+     */
+    private boolean isTransparentBitmap(Bitmap bitmap) {
+        int w = mBounds.width();
+        int h = mBounds.height();
+        bitmap.getPixels(mPixelsARGB, 0 /* the first index to write into the array */,
+                w /* stride */,
+                mBounds.left, mBounds.top,
+                w, h);
+        int sum = 0;
+        for (int i = 0; i < w * h; i++) {
+            if(Color.alpha(mPixelsARGB[i]) > MIN_VISIBLE_ALPHA) {
+                    sum++;
+            }
+        }
+        float percentageDiffPixels = ((float) sum) / (mBounds.width() * mBounds.height());
+        boolean transparentImage = percentageDiffPixels < PIXEL_DIFF_PERCENTAGE_THRESHOLD;
+        if (DEBUG) {
+            Log.d(TAG, "Total # pixel that is different (id="+ mFileId + "):" + percentageDiffPixels + "="+ sum + "/" + mBounds.width() * mBounds.height());
+        }
+        return transparentImage;
     }
 
     /**
@@ -79,7 +229,15 @@
      *
      * @param outBounds optional rect to receive the fraction distance from each edge.
      */
-    public synchronized float getScale(Drawable d, RectF outBounds) {
+    public synchronized float getScale(@NonNull Drawable d, @Nullable RectF outBounds,
+            @Nullable Path path, @Nullable boolean[] outMaskShape) {
+        if (Utilities.isAtLeastO() && d instanceof AdaptiveIconDrawable &&
+                mAdaptiveIconScale != SCALE_NOT_INITIALIZED) {
+            if (outBounds != null) {
+                outBounds.set(mAdaptiveIconBounds);
+            }
+            return mAdaptiveIconScale;
+        }
         int width = d.getIntrinsicWidth();
         int height = d.getIntrinsicHeight();
         if (width <= 0 || height <= 0) {
@@ -169,20 +327,31 @@
         if (hullByRect < CIRCLE_AREA_BY_RECT) {
             scaleRequired = MAX_CIRCLE_AREA_FACTOR;
         } else {
-            scaleRequired = MAX_SQUARE_AREA_FACTOR + LINEAR_SCALE_SLOPE * (1  - hullByRect);
+            scaleRequired = MAX_SQUARE_AREA_FACTOR + LINEAR_SCALE_SLOPE * (1 - hullByRect);
         }
+        mBounds.left = leftX;
+        mBounds.right = rightX;
+
+        mBounds.top = topY;
+        mBounds.bottom = bottomY;
 
         if (outBounds != null) {
-            outBounds.left = ((float) leftX) / width;
-            outBounds.right = 1 - ((float) rightX) / width;
-
-            outBounds.top = ((float) topY) / height;
-            outBounds.bottom = 1 - ((float) bottomY) / height;
+            outBounds.set(((float) mBounds.left) / width, ((float) mBounds.top),
+                    1 - ((float) mBounds.right) / width,
+                    1 - ((float) mBounds.bottom) / height);
         }
 
+        if (outMaskShape != null && outMaskShape.length > 0) {
+            outMaskShape[0] = isShape(path);
+        }
         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.isAtLeastO() && d instanceof AdaptiveIconDrawable &&
+                mAdaptiveIconScale == SCALE_NOT_INITIALIZED) {
+            mAdaptiveIconScale = scale;
+            mAdaptiveIconBounds.set(mBounds);
+        }
         return scale;
     }
 
diff --git a/src/com/android/launcher3/graphics/LauncherIcons.java b/src/com/android/launcher3/graphics/LauncherIcons.java
index 2d987cc..f652a5c 100644
--- a/src/com/android/launcher3/graphics/LauncherIcons.java
+++ b/src/com/android/launcher3/graphics/LauncherIcons.java
@@ -95,8 +95,29 @@
      */
     public static Bitmap createBadgedIconBitmap(
             Drawable icon, UserHandle user, Context context) {
-        float scale = FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION ?
-                1 : IconNormalizer.getInstance(context).getScale(icon, null);
+
+        IconNormalizer normalizer;
+        float scale = 1f;
+        if (!FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION) {
+            normalizer = IconNormalizer.getInstance(context);
+            if (Utilities.isAtLeastO()) {
+                boolean[] outShape = new boolean[1];
+                AdaptiveIconDrawable dr = (AdaptiveIconDrawable)
+                        context.getDrawable(R.drawable.adaptive_icon_drawable_wrapper).mutate();
+                dr.setBounds(0, 0, 1, 1);
+                scale = normalizer.getScale(icon, null, dr.getIconMask(), outShape);
+                if (FeatureFlags.LEGACY_ICON_TREATMENT &&
+                        !outShape[0]){
+                    Drawable wrappedIcon = wrapToAdaptiveIconDrawable(context, icon, scale);
+                    if (wrappedIcon != icon) {
+                        icon = wrappedIcon;
+                        scale = normalizer.getScale(icon, null, null, null);
+                    }
+                }
+            } else {
+                scale = normalizer.getScale(icon, null, null, null);
+            }
+        }
         Bitmap bitmap = createIconBitmap(icon, context, scale);
         if (FeatureFlags.ADAPTIVE_ICON_SHADOW && Utilities.isAtLeastO() &&
                 icon instanceof AdaptiveIconDrawable) {
@@ -129,8 +150,29 @@
      */
     public static Bitmap createScaledBitmapWithoutShadow(Drawable icon, Context context) {
         RectF iconBounds = new RectF();
-        float scale = FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION ?
-                1 : IconNormalizer.getInstance(context).getScale(icon, iconBounds);
+        IconNormalizer normalizer;
+        float scale = 1f;
+        if (!FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION) {
+            normalizer = IconNormalizer.getInstance(context);
+            if (Utilities.isAtLeastO()) {
+                boolean[] outShape = new boolean[1];
+                AdaptiveIconDrawable dr = (AdaptiveIconDrawable)
+                        context.getDrawable(R.drawable.adaptive_icon_drawable_wrapper).mutate();
+                dr.setBounds(0, 0, 1, 1);
+                scale = normalizer.getScale(icon, iconBounds, dr.getIconMask(), outShape);
+                if (Utilities.isAtLeastO() && FeatureFlags.LEGACY_ICON_TREATMENT &&
+                        !outShape[0]) {
+                    Drawable wrappedIcon = wrapToAdaptiveIconDrawable(context, icon, scale);
+                    if (wrappedIcon != icon) {
+                        icon = wrappedIcon;
+                        scale = normalizer.getScale(icon, iconBounds, null, null);
+                    }
+                }
+            } else {
+                scale = normalizer.getScale(icon, iconBounds, null, null);
+            }
+
+        }
         scale = Math.min(scale, ShadowGenerator.getScaleForBounds(iconBounds));
         return createIconBitmap(icon, context, scale);
     }
@@ -180,10 +222,8 @@
      * @param scale the scale to apply before drawing {@param icon} on the canvas
      */
     public static Bitmap createIconBitmap(Drawable icon, Context context, float scale) {
-        icon = wrapToAdaptiveIconDrawable(context, icon);
         synchronized (sCanvas) {
             final int iconBitmapSize = LauncherAppState.getIDP(context).iconBitmapSize;
-
             int width = iconBitmapSize;
             int height = iconBitmapSize;
 
@@ -242,7 +282,7 @@
      * shrink the legacy icon and set it as foreground. Use color drawable as background to
      * create AdaptiveIconDrawable.
      */
-    static Drawable wrapToAdaptiveIconDrawable(Context context, Drawable drawable) {
+    static Drawable wrapToAdaptiveIconDrawable(Context context, Drawable drawable, float scale) {
         if (!(FeatureFlags.LEGACY_ICON_TREATMENT && Utilities.isAtLeastO())) {
             return drawable;
         }
@@ -252,8 +292,10 @@
             if (!clazz.isAssignableFrom(drawable.getClass())) {
                 Drawable iconWrapper =
                         context.getDrawable(R.drawable.adaptive_icon_drawable_wrapper).mutate();
-                ((FixedScaleDrawable) clazz.getMethod("getForeground").invoke(iconWrapper))
-                        .setDrawable(drawable);
+                FixedScaleDrawable fsd = ((FixedScaleDrawable) clazz.getMethod("getForeground")
+                        .invoke(iconWrapper));
+                fsd.setDrawable(drawable);
+                fsd.setScale(scale);
 
                 return iconWrapper;
             }
diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java
index 15fd126..e48e349 100644
--- a/src/com/android/launcher3/popup/SystemShortcut.java
+++ b/src/com/android/launcher3/popup/SystemShortcut.java
@@ -31,7 +31,7 @@
     }
 
     public Drawable getIcon(Context context, int colorAttr) {
-        Drawable icon = context.getResources().getDrawable(mIconResId);
+        Drawable icon = context.getResources().getDrawable(mIconResId, context.getTheme()).mutate();
         icon.setTint(Themes.getAttrColor(context, colorAttr));
         return icon;
     }
diff --git a/src_config/com/android/launcher3/config/FeatureFlags.java b/src_config/com/android/launcher3/config/FeatureFlags.java
index 80eebec..4e337a2 100644
--- a/src_config/com/android/launcher3/config/FeatureFlags.java
+++ b/src_config/com/android/launcher3/config/FeatureFlags.java
@@ -45,8 +45,8 @@
     public static final boolean LIGHT_STATUS_BAR = false;
     // When enabled icons are badged with the number of notifications associated with that app.
     public static final boolean BADGE_ICONS = true;
-    // When enabled, icons not supporting {@link MaskableIconDrawable} will be wrapped in this class.
-    public static final boolean LEGACY_ICON_TREATMENT = false;
+    // When enabled, icons not supporting {@link AdaptiveIconDrawable} will be wrapped in this class.
+    public static final boolean LEGACY_ICON_TREATMENT = true;
     // When enabled, adaptive icons would have shadows baked when being stored to icon cache.
     public static final boolean ADAPTIVE_ICON_SHADOW = true;
     // When enabled, app discovery will be enabled if service is implemented