Merge "Stop trying to draw a view not attached to the view tree" into sc-dev am: d1bde5e6f3
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/13989193 Change-Id: I1274a9fe111647630dafd71a4d30fcdc7adebd97
This commit is contained in:
committed by
Automerger Merge Worker
commit
71cf2f593f
@@ -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
|
||||
|
||||
@@ -17,12 +17,8 @@ package com.android.launcher3.dragndrop;
|
||||
|
||||
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 @@ 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();
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
|
||||
|
||||
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 @@ public abstract class BaseWidgetSheet extends AbstractSlideInView
|
||||
|
||||
// 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 @@ public abstract class BaseWidgetSheet extends AbstractSlideInView
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -115,6 +115,7 @@ public class PendingItemDragHelper extends DragPreviewProvider {
|
||||
}
|
||||
if (mAppWidgetHostViewPreview != null) {
|
||||
preview = new AppWidgetHostViewDrawable(mAppWidgetHostViewPreview);
|
||||
previewSizeBeforeScale[0] = mAppWidgetHostViewPreview.getMeasuredWidth();
|
||||
launcher.getDragController()
|
||||
.addDragListener(new AppWidgetHostViewDragListener(launcher));
|
||||
}
|
||||
|
||||
@@ -28,9 +28,11 @@ import android.util.Log;
|
||||
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.CheckLongPressHelper;
|
||||
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 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
|
||||
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 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
|
||||
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 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
|
||||
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 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
|
||||
mActiveRequest = null;
|
||||
}
|
||||
mPreview = null;
|
||||
if (mAppWidgetHostViewPreview != null) {
|
||||
mWidgetImageContainer.removeView(mAppWidgetHostViewPreview);
|
||||
}
|
||||
mAppWidgetHostViewPreview = null;
|
||||
}
|
||||
|
||||
@@ -215,6 +225,13 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
|
||||
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 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
|
||||
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 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
|
||||
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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,7 +25,6 @@ import android.util.AttributeSet;
|
||||
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 @@ public class WidgetImageView extends View {
|
||||
private final int mBadgeMargin;
|
||||
|
||||
private Drawable mDrawable;
|
||||
private Drawable mBadge;
|
||||
|
||||
public WidgetImageView(Context context) {
|
||||
this(context, null);
|
||||
@@ -54,9 +52,9 @@ public class WidgetImageView extends View {
|
||||
.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 @@ public class WidgetImageView extends View {
|
||||
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 @@ public class WidgetImageView extends View {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,7 +31,6 @@ import com.android.launcher3.WidgetPreviewLoader;
|
||||
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 @@ public final class WidgetsListTableViewHolderBinder
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user