• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.launcher3.widget;
18 
19 import static com.android.launcher3.widget.util.WidgetSizes.getWidgetSizePx;
20 
21 import android.graphics.Bitmap;
22 import android.graphics.Canvas;
23 import android.graphics.Paint;
24 import android.graphics.Point;
25 import android.graphics.Rect;
26 import android.graphics.drawable.Drawable;
27 import android.util.Size;
28 import android.view.View;
29 import android.view.View.MeasureSpec;
30 import android.widget.RemoteViews;
31 
32 import androidx.annotation.Nullable;
33 
34 import com.android.launcher3.DeviceProfile;
35 import com.android.launcher3.DragSource;
36 import com.android.launcher3.Launcher;
37 import com.android.launcher3.LauncherAppState;
38 import com.android.launcher3.PendingAddItemInfo;
39 import com.android.launcher3.R;
40 import com.android.launcher3.dragndrop.DragOptions;
41 import com.android.launcher3.dragndrop.DraggableView;
42 import com.android.launcher3.graphics.DragPreviewProvider;
43 import com.android.launcher3.icons.BaseIconFactory;
44 import com.android.launcher3.icons.FastBitmapDrawable;
45 import com.android.launcher3.icons.LauncherIcons;
46 import com.android.launcher3.icons.RoundDrawableWrapper;
47 
48 /**
49  * Extension of {@link DragPreviewProvider} with logic specific to pending widgets/shortcuts
50  * dragged from the widget tray.
51  */
52 public class PendingItemDragHelper extends DragPreviewProvider {
53 
54     private static final float MAX_WIDGET_SCALE = 1.25f;
55 
56     private final PendingAddItemInfo mAddInfo;
57     private int[] mEstimatedCellSize;
58 
59     @Nullable private RemoteViews mRemoteViewsPreview;
60     private float mRemoteViewsPreviewScale = 1f;
61     @Nullable private NavigableAppWidgetHostView mAppWidgetHostViewPreview;
62     private final float mEnforcedRoundedCornersForWidget;
63 
PendingItemDragHelper(View view)64     public PendingItemDragHelper(View view) {
65         super(view);
66         mAddInfo = (PendingAddItemInfo) view.getTag();
67         mEnforcedRoundedCornersForWidget = RoundedCornerEnforcement.computeEnforcedRadius(
68                 view.getContext());
69     }
70 
71     /**
72      * Sets a {@link RemoteViews} which shows an app widget preview provided by app developers in
73      * the pin widget flow.
74      */
setRemoteViewsPreview(@ullable RemoteViews remoteViewsPreview, float previewScale)75     public void setRemoteViewsPreview(@Nullable RemoteViews remoteViewsPreview,
76             float previewScale) {
77         mRemoteViewsPreview = remoteViewsPreview;
78         mRemoteViewsPreviewScale = previewScale;
79     }
80 
81     /** Sets a {@link NavigableAppWidgetHostView} which shows a preview layout of an app widget. */
setAppWidgetHostViewPreview( @ullable NavigableAppWidgetHostView appWidgetHostViewPreview)82     public void setAppWidgetHostViewPreview(
83             @Nullable NavigableAppWidgetHostView appWidgetHostViewPreview) {
84         mAppWidgetHostViewPreview = appWidgetHostViewPreview;
85     }
86 
87     /**
88      * Starts the drag for the pending item associated with the view.
89      *
90      * @param previewBounds The bounds where the image was displayed,
91      *                      {@link WidgetImageView#getBitmapBounds()}
92      * @param previewBitmapWidth The actual width of the bitmap displayed in the view.
93      * @param previewViewWidth The width of {@link WidgetImageView} displaying the preview
94      * @param screenPos Position of {@link WidgetImageView} on the screen
95      */
startDrag(Rect previewBounds, int previewBitmapWidth, int previewViewWidth, Point screenPos, DragSource source, DragOptions options)96     public void startDrag(Rect previewBounds, int previewBitmapWidth, int previewViewWidth,
97             Point screenPos, DragSource source, DragOptions options) {
98         final Launcher launcher = Launcher.getLauncher(mView.getContext());
99         LauncherAppState app = LauncherAppState.getInstance(launcher);
100 
101         Drawable preview = null;
102         final int previewWidth;
103         final int previewHeight;
104         final float scale;
105         final Rect dragRegion;
106 
107         mEstimatedCellSize = launcher.getWorkspace().estimateItemSize(mAddInfo);
108 
109         DraggableView draggableView;
110 
111         if (mAddInfo instanceof PendingAddWidgetInfo) {
112             PendingAddWidgetInfo createWidgetInfo = (PendingAddWidgetInfo) mAddInfo;
113 
114             int maxWidth = Math.min((int) (previewBitmapWidth * MAX_WIDGET_SCALE), mEstimatedCellSize[0]);
115 
116             int[] previewSizeBeforeScale = new int[1];
117 
118             if (mRemoteViewsPreview != null) {
119                 mAppWidgetHostViewPreview = new LauncherAppWidgetHostView(launcher);
120                 mAppWidgetHostViewPreview.setAppWidget(/* appWidgetId= */ -1,
121                         ((PendingAddWidgetInfo) mAddInfo).info);
122                 DeviceProfile deviceProfile = launcher.getDeviceProfile();
123                 mAppWidgetHostViewPreview.updateAppWidget(/* remoteViews= */ mRemoteViewsPreview);
124                 Size widgetSizes = getWidgetSizePx(deviceProfile, mAddInfo.spanX, mAddInfo.spanY);
125                 mAppWidgetHostViewPreview.measure(
126                         MeasureSpec.makeMeasureSpec(widgetSizes.getWidth(), MeasureSpec.EXACTLY),
127                         MeasureSpec.makeMeasureSpec(widgetSizes.getHeight(), MeasureSpec.EXACTLY));
128                 mAppWidgetHostViewPreview.setClipChildren(false);
129                 mAppWidgetHostViewPreview.setClipToPadding(false);
130                 mAppWidgetHostViewPreview.setScaleToFit(mRemoteViewsPreviewScale);
131             }
132             if (mAppWidgetHostViewPreview != null) {
133                 previewSizeBeforeScale[0] = mAppWidgetHostViewPreview.getMeasuredWidth();
134             }
135             if (preview == null && mAppWidgetHostViewPreview == null) {
136                 Drawable p = new FastBitmapDrawable(new DatabaseWidgetPreviewLoader(launcher)
137                         .generateWidgetPreview(
138                                 createWidgetInfo.info, maxWidth, previewSizeBeforeScale));
139                 p = new RoundDrawableWrapper(p, mEnforcedRoundedCornersForWidget);
140                 preview = p;
141             }
142 
143             if (previewSizeBeforeScale[0] < previewBitmapWidth) {
144                 // The icon has extra padding around it.
145                 int padding = (previewBitmapWidth - previewSizeBeforeScale[0]) / 2;
146                 if (previewBitmapWidth > previewViewWidth) {
147                     padding = padding * previewViewWidth / previewBitmapWidth;
148                 }
149 
150                 previewBounds.left += padding;
151                 previewBounds.right -= padding;
152             }
153             if (mAppWidgetHostViewPreview != null) {
154                 float previewScale = mAppWidgetHostViewPreview.getScaleX();
155                 int widgetWidth = mAppWidgetHostViewPreview.getMeasuredWidth();
156                 int widgetHeight = mAppWidgetHostViewPreview.getMeasuredHeight();
157                 previewWidth = Math.round(widgetWidth * previewScale);
158                 previewHeight = Math.round(widgetHeight * previewScale);
159 
160                 previewBounds.offset(
161                         Math.round(widgetWidth * (previewScale - 1) / 2),
162                         Math.round(widgetHeight * (previewScale - 1) / 2));
163             } else {
164                 previewWidth = preview.getIntrinsicWidth();
165                 previewHeight = preview.getIntrinsicHeight();
166             }
167             scale = previewBounds.width() / (float) previewWidth;
168             launcher.getDragController().addDragListener(new WidgetHostViewLoader(launcher, mView));
169 
170             dragRegion = null;
171             draggableView = DraggableView.ofType(DraggableView.DRAGGABLE_WIDGET);
172         } else {
173             PendingAddShortcutInfo createShortcutInfo = (PendingAddShortcutInfo) mAddInfo;
174             Drawable icon = createShortcutInfo.getActivityInfo(launcher)
175                     .getFullResIcon(app.getIconCache());
176             LauncherIcons li = LauncherIcons.obtain(launcher);
177             preview = new FastBitmapDrawable(
178                     li.createScaledBitmap(icon, BaseIconFactory.MODE_DEFAULT));
179             previewWidth = preview.getIntrinsicWidth();
180             previewHeight = preview.getIntrinsicHeight();
181             li.recycle();
182             scale = ((float) launcher.getDeviceProfile().iconSizePx) / previewWidth;
183 
184             // Create a preview same as the workspace cell size and draw the icon at the
185             // appropriate position.
186             DeviceProfile dp = launcher.getDeviceProfile();
187             int iconSize = dp.iconSizePx;
188 
189             int padding = launcher.getResources()
190                     .getDimensionPixelSize(R.dimen.widget_preview_shortcut_padding);
191             previewBounds.left += padding;
192             previewBounds.top += padding;
193 
194             dragRegion = new Rect();
195             dragRegion.left = (mEstimatedCellSize[0] - iconSize) / 2;
196             dragRegion.right = dragRegion.left + iconSize;
197             dragRegion.top = (mEstimatedCellSize[1]
198                     - iconSize - dp.iconTextSizePx - dp.iconDrawablePaddingPx) / 2;
199             dragRegion.bottom = dragRegion.top + iconSize;
200             draggableView = DraggableView.ofType(DraggableView.DRAGGABLE_ICON);
201         }
202 
203         int dragLayerX = screenPos.x + previewBounds.left
204                 + (int) ((scale * previewWidth - previewWidth) / 2);
205         int dragLayerY = screenPos.y + previewBounds.top
206                 + (int) ((scale * previewHeight - previewHeight) / 2);
207 
208         // Start the drag
209         if (mAppWidgetHostViewPreview != null) {
210             launcher.getDragController().startDrag(mAppWidgetHostViewPreview, draggableView,
211                     dragLayerX, dragLayerY, source, mAddInfo, dragRegion, scale, scale, options);
212         } else {
213             launcher.getDragController().startDrag(preview, draggableView, dragLayerX, dragLayerY,
214                     source, mAddInfo, dragRegion, scale, scale, options);
215         }
216     }
217 
218     @Override
convertPreviewToAlphaBitmap(Bitmap preview)219     protected Bitmap convertPreviewToAlphaBitmap(Bitmap preview) {
220         if (mAddInfo instanceof PendingAddShortcutInfo || mEstimatedCellSize == null) {
221             return super.convertPreviewToAlphaBitmap(preview);
222         }
223 
224         int w = mEstimatedCellSize[0];
225         int h = mEstimatedCellSize[1];
226         final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ALPHA_8);
227         Rect src = new Rect(0, 0, preview.getWidth(), preview.getHeight());
228 
229         float scaleFactor = Math.min((w - blurSizeOutline) / (float) preview.getWidth(),
230                 (h - blurSizeOutline) / (float) preview.getHeight());
231         int scaledWidth = (int) (scaleFactor * preview.getWidth());
232         int scaledHeight = (int) (scaleFactor * preview.getHeight());
233         Rect dst = new Rect(0, 0, scaledWidth, scaledHeight);
234 
235         // center the image
236         dst.offset((w - scaledWidth) / 2, (h - scaledHeight) / 2);
237         new Canvas(b).drawBitmap(preview, src, dst, new Paint(Paint.FILTER_BITMAP_FLAG));
238         return b;
239     }
240 }
241