Merge "Stop trying to draw a view not attached to the view tree" into sc-dev
diff --git a/res/layout/widget_cell_content.xml b/res/layout/widget_cell_content.xml
index 30bd8b1..0f6fc6c 100644
--- a/res/layout/widget_cell_content.xml
+++ b/res/layout/widget_cell_content.xml
@@ -17,16 +17,31 @@
     android:layout_width="wrap_content"
     android:layout_height="wrap_content">
 
-    <!-- The image of the widget. This view does not support padding. Any placement adjustment
-         should be done using margins. Width & height are set at runtime after scaling the preview
-         image. -->
-    <com.android.launcher3.widget.WidgetImageView
-        android:id="@+id/widget_preview"
+    <com.android.launcher3.widget.WidgetCellPreview
+        android:id="@+id/widget_preview_container"
         android:layout_width="0dp"
         android:layout_height="0dp"
         android:layout_weight="1"
         android:importantForAccessibility="no"
-        android:layout_marginVertical="8dp" />
+        android:layout_marginVertical="8dp">
+        <!-- The image of the widget. This view does not support padding. Any placement adjustment
+             should be done using margins. Width & height are set at runtime after scaling the
+             preview image. -->
+        <com.android.launcher3.widget.WidgetImageView
+            android:id="@+id/widget_preview"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:importantForAccessibility="no"
+            android:layout_gravity="fill"/>
+
+        <ImageView
+            android:id="@+id/widget_badge"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:importantForAccessibility="no"
+            android:layout_gravity="end|bottom"
+            android:layout_margin="@dimen/profile_badge_margin"/>
+    </com.android.launcher3.widget.WidgetCellPreview>
 
     <!-- The name of the widget. -->
     <TextView
diff --git a/src/com/android/launcher3/dragndrop/AppWidgetHostViewDrawable.java b/src/com/android/launcher3/dragndrop/AppWidgetHostViewDrawable.java
index 7b32bbf..2135f5d 100644
--- a/src/com/android/launcher3/dragndrop/AppWidgetHostViewDrawable.java
+++ b/src/com/android/launcher3/dragndrop/AppWidgetHostViewDrawable.java
@@ -17,12 +17,8 @@
 
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
-import android.graphics.Outline;
 import android.graphics.Paint;
-import android.graphics.Path;
 import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
 
 import com.android.launcher3.widget.LauncherAppWidgetHostView;
@@ -36,38 +32,15 @@
 
     private final LauncherAppWidgetHostView mAppWidgetHostView;
     private Paint mPaint = new Paint();
-    private final Path mClipPath;
-    private final boolean mWasAttached;
 
     public AppWidgetHostViewDrawable(LauncherAppWidgetHostView appWidgetHostView) {
         mAppWidgetHostView = appWidgetHostView;
-        mWasAttached = appWidgetHostView.isAttachedToWindow();
-        Path clipPath = null;
-        if (appWidgetHostView.getClipToOutline()) {
-            Outline outline = new Outline();
-            mAppWidgetHostView.getOutlineProvider().getOutline(mAppWidgetHostView, outline);
-            Rect rect = new Rect();
-            if (outline.getRect(rect)) {
-                float radius = outline.getRadius();
-                clipPath = new Path();
-                clipPath.addRoundRect(new RectF(rect), radius, radius, Path.Direction.CCW);
-            }
-        }
-        mClipPath = clipPath;
     }
 
     @Override
     public void draw(Canvas canvas) {
         int saveCount = canvas.saveLayer(0, 0, getIntrinsicWidth(), getIntrinsicHeight(), mPaint);
-        if (mClipPath != null) {
-            canvas.clipPath(mClipPath);
-        }
-        // If the view was never attached, or is current attached, then draw. Otherwise do not try
-        // to draw, or we might trigger bugs with items that get drawn while requiring the view to
-        // be attached.
-        if (!mWasAttached || mAppWidgetHostView.isAttachedToWindow()) {
-            mAppWidgetHostView.draw(canvas);
-        }
+        mAppWidgetHostView.draw(canvas);
         canvas.restoreToCount(saveCount);
     }
 
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index fc63af0..95b887c 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -19,6 +19,7 @@
 
 import android.content.Context;
 import android.graphics.Point;
+import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -108,7 +109,7 @@
 
         // If the ImageView doesn't have a drawable yet, the widget preview hasn't been loaded and
         // we abort the drag.
-        if (image.getDrawable() == null) {
+        if (image.getDrawable() == null && v.getAppWidgetHostViewPreview() == null) {
             return false;
         }
 
@@ -116,11 +117,21 @@
         dragHelper.setRemoteViewsPreview(v.getPreview());
         dragHelper.setAppWidgetHostViewPreview(v.getAppWidgetHostViewPreview());
 
-        int[] loc = new int[2];
-        getPopupContainer().getLocationInDragLayer(image, loc);
+        if (image.getDrawable() != null) {
+            int[] loc = new int[2];
+            getPopupContainer().getLocationInDragLayer(image, loc);
 
-        dragHelper.startDrag(image.getBitmapBounds(), image.getDrawable().getIntrinsicWidth(),
-                image.getWidth(), new Point(loc[0], loc[1]), this, new DragOptions());
+            dragHelper.startDrag(image.getBitmapBounds(), image.getDrawable().getIntrinsicWidth(),
+                    image.getWidth(), new Point(loc[0], loc[1]), this, new DragOptions());
+        } else {
+            View preview = v.getAppWidgetHostViewPreview();
+            int[] loc = new int[2];
+            getPopupContainer().getLocationInDragLayer(preview, loc);
+
+            Rect r = new Rect(0, 0, preview.getWidth(), preview.getHeight());
+            dragHelper.startDrag(r, preview.getMeasuredWidth(), preview.getMeasuredWidth(),
+                    new Point(loc[0], loc[1]), this, new DragOptions());
+        }
         close(true);
         return true;
     }
diff --git a/src/com/android/launcher3/widget/PendingItemDragHelper.java b/src/com/android/launcher3/widget/PendingItemDragHelper.java
index 3e61e56..e78d517 100644
--- a/src/com/android/launcher3/widget/PendingItemDragHelper.java
+++ b/src/com/android/launcher3/widget/PendingItemDragHelper.java
@@ -115,6 +115,7 @@
             }
             if (mAppWidgetHostViewPreview != null) {
                 preview = new AppWidgetHostViewDrawable(mAppWidgetHostViewPreview);
+                previewSizeBeforeScale[0] = mAppWidgetHostViewPreview.getMeasuredWidth();
                 launcher.getDragController()
                         .addDragListener(new AppWidgetHostViewDragListener(launcher));
             }
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index 40b256b..5e7c961 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -28,9 +28,11 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnLayoutChangeListener;
+import android.view.ViewGroup;
 import android.view.ViewPropertyAnimator;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.FrameLayout;
+import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.RemoteViews;
 import android.widget.TextView;
@@ -42,7 +44,6 @@
 import com.android.launcher3.DeviceProfile;
 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;
@@ -77,7 +78,9 @@
     private int mCellSize;
     private float mPreviewScale = 1f;
 
+    private FrameLayout mWidgetImageContainer;
     private WidgetImageView mWidgetImage;
+    private ImageView mWidgetBadge;
     private TextView mWidgetName;
     private TextView mWidgetDims;
     private TextView mWidgetDescription;
@@ -133,7 +136,9 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
 
+        mWidgetImageContainer = findViewById(R.id.widget_preview_container);
         mWidgetImage = findViewById(R.id.widget_preview);
+        mWidgetBadge = findViewById(R.id.widget_badge);
         mWidgetName = findViewById(R.id.widget_name);
         mWidgetDims = findViewById(R.id.widget_dims);
         mWidgetDescription = findViewById(R.id.widget_description);
@@ -155,7 +160,9 @@
             Log.d(TAG, "reset called on:" + mWidgetName.getText());
         }
         mWidgetImage.animate().cancel();
-        mWidgetImage.setDrawable(null, null);
+        mWidgetImage.setDrawable(null);
+        mWidgetImage.setVisibility(View.VISIBLE);
+        mWidgetBadge.setImageDrawable(null);
         mWidgetName.setText(null);
         mWidgetDims.setText(null);
         mWidgetDescription.setText(null);
@@ -167,6 +174,9 @@
             mActiveRequest = null;
         }
         mPreview = null;
+        if (mAppWidgetHostViewPreview != null) {
+            mWidgetImageContainer.removeView(mAppWidgetHostViewPreview);
+        }
         mAppWidgetHostViewPreview = null;
     }
 
@@ -215,6 +225,13 @@
             mAppWidgetHostViewPreview.setPadding(/* left= */ 0, /* top= */0, /* right= */
                     0, /* bottom= */ 0);
             mAppWidgetHostViewPreview.updateAppWidget(/* remoteViews= */ null);
+            // Gravity 77 = "fill"
+            FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
+                    ViewGroup.LayoutParams.MATCH_PARENT,
+                    ViewGroup.LayoutParams.MATCH_PARENT, /* gravity= */ 77);
+            mAppWidgetHostViewPreview.setLayoutParams(params);
+            mWidgetImageContainer.addView(mAppWidgetHostViewPreview, /* index= */ 0);
+            mWidgetImage.setVisibility(View.GONE);
         }
     }
 
@@ -258,21 +275,36 @@
             return;
         }
         if (drawable != null) {
-            LayoutParams layoutParams = (LayoutParams) mWidgetImage.getLayoutParams();
-            layoutParams.width = (int) (drawable.getIntrinsicWidth() * mPreviewScale);
-            layoutParams.height = (int) (drawable.getIntrinsicHeight() * mPreviewScale);
-            mWidgetImage.setLayoutParams(layoutParams);
-
-            mWidgetImage.setDrawable(drawable, mWidgetPreviewLoader.getBadgeForUser(mItem.user,
-                    BaseIconFactory.getBadgeSizeForIconSize(mDeviceProfile.allAppsIconSizePx)));
-            if (mAnimatePreview) {
-                mWidgetImage.setAlpha(0f);
-                ViewPropertyAnimator anim = mWidgetImage.animate();
-                anim.alpha(1.0f).setDuration(FADE_IN_DURATION_MS);
-            } else {
-                mWidgetImage.setAlpha(1f);
+            setContainerSize(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
+            mWidgetImage.setDrawable(drawable);
+            mWidgetImage.setVisibility(View.VISIBLE);
+            if (mAppWidgetHostViewPreview != null) {
+                removeView(mAppWidgetHostViewPreview);
+                mAppWidgetHostViewPreview = null;
             }
         }
+        Drawable badge = mWidgetPreviewLoader.getBadgeForUser(mItem.user,
+                BaseIconFactory.getBadgeSizeForIconSize(mDeviceProfile.allAppsIconSizePx));
+        if (badge == null) {
+            mWidgetBadge.setVisibility(View.GONE);
+        } else {
+            mWidgetBadge.setVisibility(View.VISIBLE);
+            mWidgetBadge.setImageDrawable(badge);
+        }
+        if (mAnimatePreview) {
+            mWidgetImageContainer.setAlpha(0f);
+            ViewPropertyAnimator anim = mWidgetImageContainer.animate();
+            anim.alpha(1.0f).setDuration(FADE_IN_DURATION_MS);
+        } else {
+            mWidgetImageContainer.setAlpha(1f);
+        }
+    }
+
+    private void setContainerSize(int width, int height) {
+        LayoutParams layoutParams = (LayoutParams) mWidgetImageContainer.getLayoutParams();
+        layoutParams.width = (int) (width * mPreviewScale);
+        layoutParams.height = (int) (height * mPreviewScale);
+        mWidgetImageContainer.setLayoutParams(layoutParams);
     }
 
     public void ensurePreview() {
@@ -290,15 +322,8 @@
             int viewWidth = dp.cellWidthPx * mItem.spanX;
             int viewHeight = dp.cellHeightPx * mItem.spanY;
 
-            mAppWidgetHostViewPreview.measure(
-                    MeasureSpec.makeMeasureSpec(viewWidth, MeasureSpec.EXACTLY),
-                    MeasureSpec.makeMeasureSpec(viewHeight, MeasureSpec.EXACTLY));
-
-            viewWidth = mAppWidgetHostViewPreview.getMeasuredWidth();
-            viewHeight = mAppWidgetHostViewPreview.getMeasuredHeight();
-            mAppWidgetHostViewPreview.layout(0, 0, viewWidth, viewHeight);
-            Drawable drawable = new AppWidgetHostViewDrawable(mAppWidgetHostViewPreview);
-            applyPreview(drawable);
+            setContainerSize(viewWidth, viewHeight);
+            applyPreview((Drawable) null);
             return;
         }
         if (mActiveRequest != null) {
diff --git a/src/com/android/launcher3/widget/WidgetCellPreview.java b/src/com/android/launcher3/widget/WidgetCellPreview.java
new file mode 100644
index 0000000..ad3a61a
--- /dev/null
+++ b/src/com/android/launcher3/widget/WidgetCellPreview.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 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.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.widget.FrameLayout;
+
+/**
+ * View group managing the widget preview: either using a {@link WidgetImageView} or an actual
+ * {@link LauncherAppWidgetHostView}.
+ */
+public class WidgetCellPreview extends FrameLayout {
+    public WidgetCellPreview(Context context) {
+        this(context, null);
+    }
+
+    public WidgetCellPreview(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public WidgetCellPreview(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        super.onInterceptTouchEvent(ev);
+        return true;
+    }
+
+}
diff --git a/src/com/android/launcher3/widget/WidgetImageView.java b/src/com/android/launcher3/widget/WidgetImageView.java
index 39d701c..11f4485 100644
--- a/src/com/android/launcher3/widget/WidgetImageView.java
+++ b/src/com/android/launcher3/widget/WidgetImageView.java
@@ -25,7 +25,6 @@
 import android.view.View;
 
 import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
 
 /**
  * View that draws a bitmap horizontally centered. If the image width is greater than the view
@@ -37,7 +36,6 @@
     private final int mBadgeMargin;
 
     private Drawable mDrawable;
-    private Drawable mBadge;
 
     public WidgetImageView(Context context) {
         this(context, null);
@@ -54,9 +52,9 @@
                 .getDimensionPixelSize(R.dimen.profile_badge_margin);
     }
 
-    public void setDrawable(Drawable drawable, Drawable badge) {
+    /** Set the drawable to use for this view. */
+    public void setDrawable(Drawable drawable) {
         mDrawable = drawable;
-        mBadge = badge;
         invalidate();
     }
 
@@ -70,11 +68,6 @@
             updateDstRectF();
             mDrawable.setBounds(getBitmapBounds());
             mDrawable.draw(canvas);
-
-            // Only draw the badge if a preview was drawn.
-            if (mBadge != null) {
-                mBadge.draw(canvas);
-            }
         }
     }
 
@@ -105,17 +98,6 @@
             mDstRectF.top = (myHeight - scaledHeight) / 2;
             mDstRectF.bottom = (myHeight + scaledHeight) / 2;
         }
-
-        if (mBadge != null) {
-            Rect bounds = mBadge.getBounds();
-            int left = Utilities.boundToRange(
-                    (int) (mDstRectF.right + mBadgeMargin - bounds.width()),
-                    mBadgeMargin, getWidth() - bounds.width());
-            int top = Utilities.boundToRange(
-                    (int) (mDstRectF.bottom + mBadgeMargin - bounds.height()),
-                    mBadgeMargin, getHeight() - bounds.height());
-            mBadge.setBounds(left, top, bounds.width() + left, bounds.height() + top);
-        }
     }
 
     /**
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
index c1d64b1..1524ab3 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
@@ -31,7 +31,6 @@
 import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.recyclerview.ViewHolderBinder;
 import com.android.launcher3.widget.WidgetCell;
-import com.android.launcher3.widget.WidgetImageView;
 import com.android.launcher3.widget.model.WidgetsListContentEntry;
 import com.android.launcher3.widget.util.WidgetsTableUtils;
 
@@ -170,7 +169,7 @@
                     WidgetCell widget = (WidgetCell) mLayoutInflater.inflate(
                             R.layout.widget_cell, tableRow, false);
                     // set up touch.
-                    WidgetImageView preview = widget.findViewById(R.id.widget_preview);
+                    View preview = widget.findViewById(R.id.widget_preview_container);
                     preview.setOnClickListener(mIconClickListener);
                     preview.setOnLongClickListener(mIconLongClickListener);
                     tableRow.addView(widget);