Prevent launcher crash when an App Widget is removed.
If an App Widget with a scrollable element is removed, we may end up in
a situation where we try to draw the view directly on a canvas while the
it has already been detached from the workspace. This can crash as some
of the drawing the scroll indicators require the view to be attached.
In general, we should never draw a view by calling the draw method
directly, even more so when the view is detached: the behavior is
undefined as the method expects the canvas to be properly set up, and it
is not. A crash can therefore be expected. This patch should avoid
crashing the launcher until we stop doing that altogether.
Fix: 183386115
Test: Manally add a view with a preview layout
Test: Manually remove an app widget with a list view
Change-Id: I8e1aa581700a08d6747eab085199c2b293e0e3fb
diff --git a/src/com/android/launcher3/dragndrop/AppWidgetHostViewDrawable.java b/src/com/android/launcher3/dragndrop/AppWidgetHostViewDrawable.java
index 5cd95dc..7b32bbf 100644
--- a/src/com/android/launcher3/dragndrop/AppWidgetHostViewDrawable.java
+++ b/src/com/android/launcher3/dragndrop/AppWidgetHostViewDrawable.java
@@ -27,15 +27,21 @@
import com.android.launcher3.widget.LauncherAppWidgetHostView;
-/** A drawable which renders {@link LauncherAppWidgetHostView} to a canvas. */
+/**
+ * A drawable which renders {@link LauncherAppWidgetHostView} to a canvas.
+ *
+ * TODO(b/183609936) Stop using that class and remove it.
+ */
public final class AppWidgetHostViewDrawable extends Drawable {
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();
@@ -56,7 +62,12 @@
if (mClipPath != null) {
canvas.clipPath(mClipPath);
}
- mAppWidgetHostView.draw(canvas);
+ // 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);
+ }
canvas.restoreToCount(saveCount);
}