Sharesheet - force DS icons to be round

DS icons cannot be provided as AdaptiveIcons. Most today are
provided as a circular bitmap but there is no shape guarantee.
To provide visual consistency, scale and mask all DS icons to a
circle. Currently, all DS icons are shaped making them hard to
see.

Fixes: 129980123
Test: manual images large and small, rectangular, circular, etc
Change-Id: I011b35c1334affb1224f62beafd3f72026198054
diff --git a/core/java/com/android/internal/app/SimpleIconFactory.java b/core/java/com/android/internal/app/SimpleIconFactory.java
index a85485d..2484109 100644
--- a/core/java/com/android/internal/app/SimpleIconFactory.java
+++ b/core/java/com/android/internal/app/SimpleIconFactory.java
@@ -34,6 +34,8 @@
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.PaintFlagsDrawFilter;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.drawable.AdaptiveIconDrawable;
@@ -56,7 +58,7 @@
 /**
  * @deprecated Use the Launcher3 Iconloaderlib at packages/apps/Launcher3/iconloaderlib. This class
  * is a temporary fork of Iconloader. It combines all necessary methods to render app icons that are
- * possibly badged. It is intended to be used only by Sharesheet for the Q release.
+ * possibly badged. It is intended to be used only by Sharesheet for the Q release with custom code.
  */
 @Deprecated
 public class SimpleIconFactory {
@@ -202,6 +204,7 @@
     /**
      * Creates bitmap using the source drawable and flattened pre-rendered app icon.
      * The bitmap is visually normalized with other icons and has enough spacing to add shadow.
+     * This is custom functionality added to Iconloaderlib that will need to be ported.
      *
      * @param icon                      source of the icon associated with a user that has no badge
      * @param renderedAppIcon           pre-rendered app icon to use as a badge, likely the output
@@ -212,34 +215,70 @@
      */
     @Deprecated
     Bitmap createAppBadgedIconBitmap(@Nullable Drawable icon, Bitmap renderedAppIcon) {
-        // Flatten the passed in icon
-        float [] scale = new float[1];
-
         // If no icon is provided use the system default
         if (icon == null) {
             icon = getFullResDefaultActivityIcon(mFillResIconDpi);
         }
-        icon = normalizeAndWrapToAdaptiveIcon(icon, null, scale);
-        Bitmap bitmap = createIconBitmap(icon, scale[0]);
-        if (icon instanceof AdaptiveIconDrawable) {
-            mCanvas.setBitmap(bitmap);
-            recreateIcon(Bitmap.createBitmap(bitmap), mCanvas);
-            mCanvas.setBitmap(null);
+
+        // Direct share icons cannot be adaptive, most will arrive as bitmaps. To get reliable
+        // presentation, force all DS icons to be circular. Scale DS image so it completely fills.
+        int w = icon.getIntrinsicWidth();
+        int h = icon.getIntrinsicHeight();
+        float scale = 1;
+        if (h > w && w > 0) {
+            scale = (float) h / w;
+        } else if (w > h && h > 0) {
+            scale = (float) w / h;
+        }
+        Bitmap bitmap = createIconBitmap(icon, scale);
+        bitmap = maskBitmapToCircle(bitmap);
+        icon = new BitmapDrawable(mContext.getResources(), bitmap);
+
+        // We now have a circular masked and scaled icon, inset and apply shadow
+        scale = getScale(icon, null);
+        bitmap = createIconBitmap(icon, scale);
+
+        mCanvas.setBitmap(bitmap);
+        recreateIcon(Bitmap.createBitmap(bitmap), mCanvas);
+
+        if (renderedAppIcon != null) {
+            // Now scale down and apply the badge to the bottom right corner of the flattened icon
+            renderedAppIcon = Bitmap.createScaledBitmap(renderedAppIcon, mBadgeBitmapSize,
+                    mBadgeBitmapSize, false);
+
+            // Paint the provided badge on top of the flattened icon
+            mCanvas.drawBitmap(renderedAppIcon, mIconBitmapSize - mBadgeBitmapSize,
+                    mIconBitmapSize - mBadgeBitmapSize, null);
         }
 
-        // Now scale down and apply the badge to the bottom right corner of the flattened icon
-        renderedAppIcon = Bitmap.createScaledBitmap(renderedAppIcon, mBadgeBitmapSize,
-                mBadgeBitmapSize, false);
-
-        // Paint the provided badge on top of the flattened icon
-        mCanvas.setBitmap(bitmap);
-        mCanvas.drawBitmap(renderedAppIcon, mIconBitmapSize - mBadgeBitmapSize,
-                mIconBitmapSize - mBadgeBitmapSize, null);
         mCanvas.setBitmap(null);
 
         return bitmap;
     }
 
+    private Bitmap maskBitmapToCircle(Bitmap bitmap) {
+        final Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
+                bitmap.getHeight(), Bitmap.Config.ARGB_8888);
+        final Canvas canvas = new Canvas(output);
+        final Paint paint = new Paint();
+        paint.setAntiAlias(true);
+
+        // Draw mask
+        paint.setColor(0xffffffff);
+        canvas.drawARGB(0, 0, 0, 0);
+        canvas.drawCircle(bitmap.getWidth() / 2f,
+                bitmap.getHeight() / 2f,
+                bitmap.getWidth() / 2f - 1 /* -1 to avoid circles with flat sides */,
+                paint);
+
+        // Draw masked bitmap
+        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
+        final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
+        canvas.drawBitmap(bitmap, rect, rect, paint);
+
+        return output;
+    }
+
     private static Drawable getFullResDefaultActivityIcon(int iconDpi) {
         return Resources.getSystem().getDrawableForDensity(android.R.mipmap.sym_def_app_icon,
                 iconDpi);