/* * Copyright (C) 2016 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 static com.android.launcher3.widget.util.WidgetSizes.getWidgetSizePx; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.util.Size; import android.view.View; import android.view.View.MeasureSpec; import android.widget.RemoteViews; import androidx.annotation.Nullable; import com.android.launcher3.DeviceProfile; import com.android.launcher3.DragSource; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; import com.android.launcher3.PendingAddItemInfo; import com.android.launcher3.R; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.dragndrop.DraggableView; import com.android.launcher3.graphics.DragPreviewProvider; import com.android.launcher3.icons.BaseIconFactory; import com.android.launcher3.icons.FastBitmapDrawable; import com.android.launcher3.icons.LauncherIcons; import com.android.launcher3.icons.RoundDrawableWrapper; /** * Extension of {@link DragPreviewProvider} with logic specific to pending widgets/shortcuts * dragged from the widget tray. */ public class PendingItemDragHelper extends DragPreviewProvider { private static final float MAX_WIDGET_SCALE = 1.25f; private final PendingAddItemInfo mAddInfo; private int[] mEstimatedCellSize; @Nullable private RemoteViews mRemoteViewsPreview; private float mRemoteViewsPreviewScale = 1f; @Nullable private NavigableAppWidgetHostView mAppWidgetHostViewPreview; private final float mEnforcedRoundedCornersForWidget; public PendingItemDragHelper(View view) { super(view); mAddInfo = (PendingAddItemInfo) view.getTag(); mEnforcedRoundedCornersForWidget = RoundedCornerEnforcement.computeEnforcedRadius( view.getContext()); } /** * Sets a {@link RemoteViews} which shows an app widget preview provided by app developers in * the pin widget flow. */ public void setRemoteViewsPreview(@Nullable RemoteViews remoteViewsPreview, float previewScale) { mRemoteViewsPreview = remoteViewsPreview; mRemoteViewsPreviewScale = previewScale; } /** Sets a {@link NavigableAppWidgetHostView} which shows a preview layout of an app widget. */ public void setAppWidgetHostViewPreview( @Nullable NavigableAppWidgetHostView appWidgetHostViewPreview) { mAppWidgetHostViewPreview = appWidgetHostViewPreview; } /** * Starts the drag for the pending item associated with the view. * * @param previewBounds The bounds where the image was displayed, * {@link WidgetImageView#getBitmapBounds()} * @param previewBitmapWidth The actual width of the bitmap displayed in the view. * @param previewViewWidth The width of {@link WidgetImageView} displaying the preview * @param screenPos Position of {@link WidgetImageView} on the screen */ public void startDrag(Rect previewBounds, int previewBitmapWidth, int previewViewWidth, Point screenPos, DragSource source, DragOptions options) { final Launcher launcher = Launcher.getLauncher(mView.getContext()); LauncherAppState app = LauncherAppState.getInstance(launcher); Drawable preview = null; final int previewWidth; final int previewHeight; final float scale; final Rect dragRegion; mEstimatedCellSize = launcher.getWorkspace().estimateItemSize(mAddInfo); DraggableView draggableView; if (mAddInfo instanceof PendingAddWidgetInfo) { PendingAddWidgetInfo createWidgetInfo = (PendingAddWidgetInfo) mAddInfo; int maxWidth = Math.min((int) (previewBitmapWidth * MAX_WIDGET_SCALE), mEstimatedCellSize[0]); int[] previewSizeBeforeScale = new int[1]; if (mRemoteViewsPreview != null) { mAppWidgetHostViewPreview = new LauncherAppWidgetHostView(launcher); mAppWidgetHostViewPreview.setAppWidget(/* appWidgetId= */ -1, ((PendingAddWidgetInfo) mAddInfo).info); DeviceProfile deviceProfile = launcher.getDeviceProfile(); mAppWidgetHostViewPreview.updateAppWidget(/* remoteViews= */ mRemoteViewsPreview); Size widgetSizes = getWidgetSizePx(deviceProfile, mAddInfo.spanX, mAddInfo.spanY); mAppWidgetHostViewPreview.measure( MeasureSpec.makeMeasureSpec(widgetSizes.getWidth(), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(widgetSizes.getHeight(), MeasureSpec.EXACTLY)); mAppWidgetHostViewPreview.setClipChildren(false); mAppWidgetHostViewPreview.setClipToPadding(false); mAppWidgetHostViewPreview.setScaleToFit(mRemoteViewsPreviewScale); } if (mAppWidgetHostViewPreview != null) { previewSizeBeforeScale[0] = mAppWidgetHostViewPreview.getMeasuredWidth(); } if (preview == null && mAppWidgetHostViewPreview == null) { Drawable p = new FastBitmapDrawable(new DatabaseWidgetPreviewLoader(launcher) .generateWidgetPreview( createWidgetInfo.info, maxWidth, previewSizeBeforeScale)); if (RoundedCornerEnforcement.isRoundedCornerEnabled()) { p = new RoundDrawableWrapper(p, mEnforcedRoundedCornersForWidget); } preview = p; } if (previewSizeBeforeScale[0] < previewBitmapWidth) { // The icon has extra padding around it. int padding = (previewBitmapWidth - previewSizeBeforeScale[0]) / 2; if (previewBitmapWidth > previewViewWidth) { padding = padding * previewViewWidth / previewBitmapWidth; } previewBounds.left += padding; previewBounds.right -= padding; } if (mAppWidgetHostViewPreview != null) { float previewScale = mAppWidgetHostViewPreview.getScaleX(); int widgetWidth = mAppWidgetHostViewPreview.getMeasuredWidth(); int widgetHeight = mAppWidgetHostViewPreview.getMeasuredHeight(); previewWidth = Math.round(widgetWidth * previewScale); previewHeight = Math.round(widgetHeight * previewScale); previewBounds.offset( Math.round(widgetWidth * (previewScale - 1) / 2), Math.round(widgetHeight * (previewScale - 1) / 2)); } else { previewWidth = preview.getIntrinsicWidth(); previewHeight = preview.getIntrinsicHeight(); } scale = previewBounds.width() / (float) previewWidth; launcher.getDragController().addDragListener(new WidgetHostViewLoader(launcher, mView)); dragRegion = null; draggableView = DraggableView.ofType(DraggableView.DRAGGABLE_WIDGET); } else { PendingAddShortcutInfo createShortcutInfo = (PendingAddShortcutInfo) mAddInfo; Drawable icon = createShortcutInfo.getActivityInfo(launcher) .getFullResIcon(app.getIconCache()); LauncherIcons li = LauncherIcons.obtain(launcher); preview = new FastBitmapDrawable( li.createScaledBitmap(icon, BaseIconFactory.MODE_DEFAULT)); previewWidth = preview.getIntrinsicWidth(); previewHeight = preview.getIntrinsicHeight(); li.recycle(); scale = ((float) launcher.getDeviceProfile().iconSizePx) / previewWidth; // Create a preview same as the workspace cell size and draw the icon at the // appropriate position. DeviceProfile dp = launcher.getDeviceProfile(); int iconSize = dp.iconSizePx; int padding = launcher.getResources() .getDimensionPixelSize(R.dimen.widget_preview_shortcut_padding); previewBounds.left += padding; previewBounds.top += padding; dragRegion = new Rect(); dragRegion.left = (mEstimatedCellSize[0] - iconSize) / 2; dragRegion.right = dragRegion.left + iconSize; dragRegion.top = (mEstimatedCellSize[1] - iconSize - dp.iconTextSizePx - dp.iconDrawablePaddingPx) / 2; dragRegion.bottom = dragRegion.top + iconSize; draggableView = DraggableView.ofType(DraggableView.DRAGGABLE_ICON); } int dragLayerX = screenPos.x + previewBounds.left + (int) ((scale * previewWidth - previewWidth) / 2); int dragLayerY = screenPos.y + previewBounds.top + (int) ((scale * previewHeight - previewHeight) / 2); // Start the drag if (mAppWidgetHostViewPreview != null) { launcher.getDragController().startDrag(mAppWidgetHostViewPreview, draggableView, dragLayerX, dragLayerY, source, mAddInfo, dragRegion, scale, scale, options); } else { launcher.getDragController().startDrag(preview, draggableView, dragLayerX, dragLayerY, source, mAddInfo, dragRegion, scale, scale, options); } } @Override protected Bitmap convertPreviewToAlphaBitmap(Bitmap preview) { if (mAddInfo instanceof PendingAddShortcutInfo || mEstimatedCellSize == null) { return super.convertPreviewToAlphaBitmap(preview); } int w = mEstimatedCellSize[0]; int h = mEstimatedCellSize[1]; final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ALPHA_8); Rect src = new Rect(0, 0, preview.getWidth(), preview.getHeight()); float scaleFactor = Math.min((w - blurSizeOutline) / (float) preview.getWidth(), (h - blurSizeOutline) / (float) preview.getHeight()); int scaledWidth = (int) (scaleFactor * preview.getWidth()); int scaledHeight = (int) (scaleFactor * preview.getHeight()); Rect dst = new Rect(0, 0, scaledWidth, scaledHeight); // center the image dst.offset((w - scaledWidth) / 2, (h - scaledHeight) / 2); new Canvas(b).drawBitmap(preview, src, dst, new Paint(Paint.FILTER_BITMAP_FLAG)); return b; } }