Remove intrinsic padding from widget previews

Also, scale down the preview size if it's wider than the target cell.

The intrinsic padding prevents the corners of the preview from being
rounded correctly and can lead to clipping or no rounding, especially at
larger sizes.

Bug: 187141692
Test: verified locally
Change-Id: Ie57ad57ba7c102330324bd0439acc55ff4fd83ff
diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java
index 8b7a750..c7323d0 100644
--- a/src/com/android/launcher3/WidgetPreviewLoader.java
+++ b/src/com/android/launcher3/WidgetPreviewLoader.java
@@ -385,27 +385,29 @@
             previewHeight = Math.max((int)(scale * previewHeight), 1);
         }
 
-        // If a bitmap is passed in, we use it; otherwise, we create a bitmap of the right size
         final Canvas c = new Canvas();
         if (preview == null) {
+            // If no bitmap was provided, then allocate a new one with the right size.
             preview = Bitmap.createBitmap(previewWidth, previewHeight, Config.ARGB_8888);
             c.setBitmap(preview);
         } else {
-            // We use the preview bitmap height to determine where the badge will be drawn in the
-            // UI. If its larger than what we need, resize the preview bitmap so that there are
-            // no transparent pixels between the preview and the badge.
-            if (preview.getHeight() > previewHeight) {
-                preview.reconfigure(preview.getWidth(), previewHeight, preview.getConfig());
+            // If a bitmap was passed in, attempt to reconfigure the bitmap to the same dimensions
+            // as the preview.
+            try {
+                preview.reconfigure(previewWidth, previewHeight, preview.getConfig());
+            } catch (IllegalArgumentException e) {
+                // This occurs if the preview can't be reconfigured for any reason. In this case,
+                // allocate a new bitmap with the right size.
+                preview = Bitmap.createBitmap(previewWidth, previewHeight, Config.ARGB_8888);
             }
-            // Reusing bitmap. Clear it.
+
             c.setBitmap(preview);
             c.drawColor(0, PorterDuff.Mode.CLEAR);
         }
 
         // Draw the scaled preview into the final bitmap
-        int x = (preview.getWidth() - previewWidth) / 2;
         if (widgetPreviewExists) {
-            drawable.setBounds(x, 0, x + previewWidth, previewHeight);
+            drawable.setBounds(0, 0, previewWidth, previewHeight);
             drawable.draw(c);
         } else {
             RectF boxRect;
@@ -565,6 +567,7 @@
         @Thunk long[] mVersions;
         @Thunk Bitmap mBitmapToRecycle;
 
+        @Nullable private Bitmap mUnusedPreviewBitmap;
         private boolean mSaveToDB = false;
 
         PreviewLoadTask(WidgetCacheKey key, WidgetItem info, int previewWidth,
@@ -625,6 +628,11 @@
                 Pair<Bitmap, Boolean> pair = generatePreview(mActivity, mInfo, unusedBitmap,
                         mPreviewWidth, mPreviewHeight);
                 preview = pair.first;
+
+                if (preview != unusedBitmap) {
+                    mUnusedPreviewBitmap = unusedBitmap;
+                }
+
                 this.mSaveToDB = pair.second;
             }
             return preview;
@@ -639,6 +647,14 @@
                 MODEL_EXECUTOR.post(new Runnable() {
                     @Override
                     public void run() {
+                        if (mUnusedPreviewBitmap != null) {
+                            // If we didn't end up using the bitmap, it can be added back into the
+                            // recycled set.
+                            synchronized (mUnusedBitmaps) {
+                                mUnusedBitmaps.add(mUnusedPreviewBitmap);
+                            }
+                        }
+
                         if (!isCancelled() && mSaveToDB) {
                             // If we are still using this preview, then write it to the DB and then
                             // let the normal clear mechanism recycle the bitmap
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index f7993dc..7d04d7b 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -95,6 +95,7 @@
     protected final BaseActivity mActivity;
     private final CheckLongPressHelper mLongPressHelper;
     private final float mEnforcedCornerRadius;
+    private final int mPreviewPadding;
 
     private RemoteViews mRemoteViewsPreview;
     private NavigableAppWidgetHostView mAppWidgetHostViewPreview;
@@ -119,6 +120,8 @@
         setClipToPadding(false);
         setAccessibilityDelegate(mActivity.getAccessibilityDelegate());
         mEnforcedCornerRadius = RoundedCornerEnforcement.computeEnforcedRadius(context);
+        mPreviewPadding =
+                2 * getResources().getDimensionPixelSize(R.dimen.widget_preview_shortcut_padding);
     }
 
     private void setContainerWidth() {
@@ -281,7 +284,16 @@
             return;
         }
         if (drawable != null) {
-            setContainerSize(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
+            float scale = 1f;
+            if (getWidth() > 0 && getHeight() > 0) {
+                // Scale down the preview size if it's wider than the cell.
+                float maxWidth = getWidth() - mPreviewPadding;
+                float previewWidth = drawable.getIntrinsicWidth() * mPreviewScale;
+                scale = Math.min(maxWidth / previewWidth, 1);
+            }
+            setContainerSize(
+                    Math.round(drawable.getIntrinsicWidth() * scale),
+                    Math.round(drawable.getIntrinsicHeight() * scale));
             mWidgetImage.setDrawable(drawable);
             mWidgetImage.setVisibility(View.VISIBLE);
             if (mAppWidgetHostViewPreview != null) {
@@ -330,11 +342,9 @@
 
     /** Sets the widget preview image size, in number of cells, and preview scale. */
     public void setPreviewSize(int spanX, int spanY, float previewScale) {
-        int padding = 2 * getResources()
-                .getDimensionPixelSize(R.dimen.widget_preview_shortcut_padding);
         DeviceProfile deviceProfile = mActivity.getDeviceProfile();
-        mPreviewWidth = deviceProfile.cellWidthPx * spanX + padding;
-        mPreviewHeight = deviceProfile.cellHeightPx * spanY + padding;
+        mPreviewWidth = deviceProfile.cellWidthPx * spanX + mPreviewPadding;
+        mPreviewHeight = deviceProfile.cellHeightPx * spanY + mPreviewPadding;
         mPreviewScale = previewScale;
     }