Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e973d6f3 authored by Steven Ng's avatar Steven Ng
Browse files

Render RemoteViews in LauncherAppWidgetHostView

Test: Pin a conversation widget from a notification. RemoteViews are
      rendered with the default size. Drag-n-drop from the pin widget
      dialog works fine.
Bug: 185934141

Change-Id: Idb76cce2807e55e7b42e2e044712519857beb202
parent 8e64bba9
Loading
Loading
Loading
Loading
+21 −8
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ import com.android.launcher3.pm.PinRequestHelper;
import com.android.launcher3.views.BaseDragLayer;
import com.android.launcher3.widget.LauncherAppWidgetHost;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.NavigableAppWidgetHostView;
import com.android.launcher3.widget.PendingAddShortcutInfo;
import com.android.launcher3.widget.PendingAddWidgetInfo;
import com.android.launcher3.widget.WidgetCell;
@@ -147,20 +148,31 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener
    public boolean onLongClick(View view) {
        // Find the position of the preview relative to the touch location.
        WidgetImageView img = mWidgetCell.getWidgetView();
        NavigableAppWidgetHostView appWidgetHostView = mWidgetCell.getAppWidgetHostViewPreview();

        // If the ImageView doesn't have a drawable yet, the widget preview hasn't been loaded and
        // we abort the drag.
        if (img.getDrawable() == null) {
        if (img.getDrawable() == null && appWidgetHostView == null) {
            return false;
        }

        Rect bounds = img.getBitmapBounds();
        bounds.offset(img.getLeft() - (int) mLastTouchPos.x, img.getTop() - (int) mLastTouchPos.y);

        final Rect bounds;
        // Start home and pass the draw request params
        PinItemDragListener listener = new PinItemDragListener(mRequest, bounds,
        final PinItemDragListener listener;
        if (appWidgetHostView != null) {
            bounds = new Rect();
            appWidgetHostView.getSourceVisualDragBounds(bounds);
            bounds.offset(appWidgetHostView.getLeft() - (int) mLastTouchPos.x,
                    appWidgetHostView.getTop() - (int) mLastTouchPos.y);
            listener = new PinItemDragListener(mRequest, bounds,
                    appWidgetHostView.getMeasuredWidth(), appWidgetHostView.getMeasuredWidth());
        } else {
            bounds = img.getBitmapBounds();
            bounds.offset(img.getLeft() - (int) mLastTouchPos.x,
                    img.getTop() - (int) mLastTouchPos.y);
            listener = new PinItemDragListener(mRequest, bounds,
                    img.getDrawable().getIntrinsicWidth(), img.getWidth());

        }

        // Start a system drag and drop. We use a transparent bitmap as preview for system drag
        // as the preview is handled internally by launcher.
@@ -214,7 +226,7 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener
            // Cannot add widget
            return false;
        }
        mWidgetCell.setPreview(PinItemDragListener.getPreview(mRequest));
        mWidgetCell.setRemoteViewsPreview(PinItemDragListener.getPreview(mRequest));

        mAppWidgetManager = new WidgetManagerHelper(this);
        mAppWidgetHost = new LauncherAppWidgetHost(this);
@@ -238,6 +250,7 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener

            @Override
            protected void onPostExecute(WidgetItem item) {
                mWidgetCell.setPreviewSize(item.spanX, item.spanY);
                mWidgetCell.applyFromCellItem(item, mApp.getWidgetCache());
                mWidgetCell.ensurePreview();
            }
+1 −1
Original line number Diff line number Diff line
@@ -114,7 +114,7 @@ public abstract class BaseWidgetSheet extends AbstractSlideInView
        }

        PendingItemDragHelper dragHelper = new PendingItemDragHelper(v);
        dragHelper.setRemoteViewsPreview(v.getPreview());
        dragHelper.setRemoteViewsPreview(v.getRemoteViewsPreview());
        dragHelper.setAppWidgetHostViewPreview(v.getAppWidgetHostViewPreview());

        if (image.getDrawable() != null) {
+20 −6
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.view.View.MeasureSpec;
import android.widget.RemoteViews;

import androidx.annotation.Nullable;
@@ -53,7 +54,7 @@ public class PendingItemDragHelper extends DragPreviewProvider {
    private int[] mEstimatedCellSize;

    @Nullable private RemoteViews mRemoteViewsPreview;
    @Nullable private LauncherAppWidgetHostView mAppWidgetHostViewPreview;
    @Nullable private NavigableAppWidgetHostView mAppWidgetHostViewPreview;
    private final float mEnforcedRoundedCornersForWidget;

    public PendingItemDragHelper(View view) {
@@ -71,9 +72,9 @@ public class PendingItemDragHelper extends DragPreviewProvider {
        mRemoteViewsPreview = remoteViewsPreview;
    }

    /** Sets a {@link LauncherAppWidgetHostView} which shows a preview layout of an app widget. */
    /** Sets a {@link NavigableAppWidgetHostView} which shows a preview layout of an app widget. */
    public void setAppWidgetHostViewPreview(
            @Nullable LauncherAppWidgetHostView appWidgetHostViewPreview) {
            @Nullable NavigableAppWidgetHostView appWidgetHostViewPreview) {
        mAppWidgetHostViewPreview = appWidgetHostViewPreview;
    }

@@ -110,9 +111,22 @@ public class PendingItemDragHelper extends DragPreviewProvider {
            int[] previewSizeBeforeScale = new int[1];

            if (mRemoteViewsPreview != null) {
                preview = new FastBitmapDrawable(
                        WidgetCell.generateFromRemoteViews(launcher, mRemoteViewsPreview,
                                createWidgetInfo.info, maxWidth, previewSizeBeforeScale));
                mAppWidgetHostViewPreview = new LauncherAppWidgetHostView(launcher);
                mAppWidgetHostViewPreview.setAppWidget(/* appWidgetId= */ -1,
                        ((PendingAddWidgetInfo) mAddInfo).info);
                DeviceProfile deviceProfile = launcher.getDeviceProfile();
                Rect padding = new Rect();
                mAppWidgetHostViewPreview.getWidgetInset(deviceProfile, padding);
                mAppWidgetHostViewPreview.setPadding(padding.left, padding.top, padding.right,
                        padding.bottom);
                mAppWidgetHostViewPreview.updateAppWidget(/* remoteViews= */ mRemoteViewsPreview);
                int width =
                        deviceProfile.cellWidthPx * mAddInfo.spanX + padding.left + padding.right;
                int height =
                        deviceProfile.cellHeightPx * mAddInfo.spanY + padding.top + padding.bottom;
                mAppWidgetHostViewPreview.measure(
                        MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
                        MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
            }
            if (mAppWidgetHostViewPreview != null) {
                previewSizeBeforeScale[0] = mAppWidgetHostViewPreview.getMeasuredWidth();
+29 −70
Original line number Diff line number Diff line
@@ -46,7 +46,6 @@ import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.WidgetPreviewLoader;
import com.android.launcher3.icons.BaseIconFactory;
import com.android.launcher3.icons.BitmapRenderer;
import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.icons.RoundDrawableWrapper;
import com.android.launcher3.model.WidgetItem;
@@ -100,8 +99,8 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
    private final CheckLongPressHelper mLongPressHelper;
    private final float mEnforcedCornerRadius;

    private RemoteViews mPreview;
    private LauncherAppWidgetHostView mAppWidgetHostViewPreview;
    private RemoteViews mRemoteViewsPreview;
    private NavigableAppWidgetHostView mAppWidgetHostViewPreview;

    public WidgetCell(Context context) {
        this(context, null);
@@ -143,12 +142,13 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
        mWidgetDescription = findViewById(R.id.widget_description);
    }

    public void setPreview(RemoteViews view) {
        mPreview = view;
    public void setRemoteViewsPreview(RemoteViews view) {
        mRemoteViewsPreview = view;
    }

    public RemoteViews getPreview() {
        return mPreview;
    @Nullable
    public RemoteViews getRemoteViewsPreview() {
        return mRemoteViewsPreview;
    }

    /**
@@ -172,7 +172,7 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
            mActiveRequest.cancel();
            mActiveRequest = null;
        }
        mPreview = null;
        mRemoteViewsPreview = null;
        if (mAppWidgetHostViewPreview != null) {
            mWidgetImageContainer.removeView(mAppWidgetHostViewPreview);
        }
@@ -180,7 +180,7 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
    }

    public void applyFromCellItem(WidgetItem item, WidgetPreviewLoader loader) {
        applyPreviewLayout(item);
        applyPreviewOnAppWidgetHostView(item);

        mItem = item;
        mWidgetName.setText(mItem.label);
@@ -206,9 +206,26 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
        }
    }

    private void applyPreviewLayout(WidgetItem item) {

    private void applyPreviewOnAppWidgetHostView(WidgetItem item) {
        if (mRemoteViewsPreview != null) {
            mAppWidgetHostViewPreview = new NavigableAppWidgetHostView(getContext()) {
                @Override
                protected boolean shouldAllowDirectClick() {
                    return false;
                }
            };
            mAppWidgetHostViewPreview.setAppWidget(/* appWidgetId= */ -1, item.widgetInfo);
            Rect padding = new Rect();
            mAppWidgetHostViewPreview.getWidgetInset(mActivity.getDeviceProfile(), padding);
            mAppWidgetHostViewPreview.setPadding(padding.left, padding.top, padding.right,
                    padding.bottom);
            mAppWidgetHostViewPreview.updateAppWidget(/* remoteViews= */ mRemoteViewsPreview);
            return;
        }

        if (ATLEAST_S
                && mPreview == null
                && mRemoteViewsPreview == null
                && item.widgetInfo != null
                && item.widgetInfo.previewLayout != Resources.ID_NULL) {
            mAppWidgetHostViewPreview = new LauncherAppWidgetHostView(getContext());
@@ -234,7 +251,7 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
    }

    @Nullable
    public LauncherAppWidgetHostView getAppWidgetHostViewPreview() {
    public NavigableAppWidgetHostView getAppWidgetHostViewPreview() {
        return mAppWidgetHostViewPreview;
    }

@@ -303,15 +320,6 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
    }

    public void ensurePreview() {
        if (mPreview != null && mActiveRequest == null) {
            Bitmap preview = generateFromRemoteViews(
                    mActivity, mPreview, mItem.widgetInfo, mPresetPreviewSize, new int[1]);
            if (preview != null) {
                applyPreview(new FastBitmapDrawable(preview));
                return;
            }
        }

        if (mAppWidgetHostViewPreview != null) {
            setContainerSize(mPreviewWidth, mPreviewHeight);
            FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
@@ -385,53 +393,4 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
        super.onInitializeAccessibilityNodeInfo(info);
        info.removeAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK);
    }

    /**
     * Generates a bitmap by inflating {@param views}.
     * @see com.android.launcher3.WidgetPreviewLoader#generateWidgetPreview
     *
     * TODO: Consider moving this to the background thread.
     */
    public static Bitmap generateFromRemoteViews(BaseActivity activity, RemoteViews views,
            LauncherAppWidgetProviderInfo info, int previewSize, int[] preScaledWidthOut) {
        try {
            return generateFromView(activity, views.apply(activity, new FrameLayout(activity)),
                    info, previewSize, preScaledWidthOut);
        } catch (Exception e) {
            return null;
        }
    }

    private static Bitmap generateFromView(BaseActivity activity, View v,
            LauncherAppWidgetProviderInfo info, int previewSize, int[] preScaledWidthOut) {

        DeviceProfile dp = activity.getDeviceProfile();
        int viewWidth = dp.cellWidthPx * info.spanX;
        int viewHeight = dp.cellHeightPx * info.spanY;

        v.measure(MeasureSpec.makeMeasureSpec(viewWidth, MeasureSpec.EXACTLY),
                MeasureSpec.makeMeasureSpec(viewHeight, MeasureSpec.EXACTLY));

        viewWidth = v.getMeasuredWidth();
        viewHeight = v.getMeasuredHeight();
        v.layout(0, 0, viewWidth, viewHeight);

        preScaledWidthOut[0] = viewWidth;
        final int bitmapWidth, bitmapHeight;
        final float scale;
        if (viewWidth > previewSize) {
            scale = ((float) previewSize) / viewWidth;
            bitmapWidth = previewSize;
            bitmapHeight = (int) (viewHeight * scale);
        } else {
            scale = 1;
            bitmapWidth = viewWidth;
            bitmapHeight = viewHeight;
        }

        return BitmapRenderer.createSoftwareBitmap(bitmapWidth, bitmapHeight, c -> {
            c.scale(scale, scale);
            v.draw(c);
        });
    }
}