• 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 android.graphics.Bitmap;
20 import android.graphics.Canvas;
21 import android.graphics.Paint;
22 import android.graphics.Point;
23 import android.graphics.Rect;
24 import android.graphics.drawable.Drawable;
25 import android.view.View;
26 import android.view.View.MeasureSpec;
27 import android.widget.RemoteViews;
28 
29 import androidx.annotation.Nullable;
30 
31 import com.android.launcher3.DeviceProfile;
32 import com.android.launcher3.DragSource;
33 import com.android.launcher3.Launcher;
34 import com.android.launcher3.LauncherAppState;
35 import com.android.launcher3.PendingAddItemInfo;
36 import com.android.launcher3.R;
37 import com.android.launcher3.dragndrop.DragOptions;
38 import com.android.launcher3.dragndrop.DraggableView;
39 import com.android.launcher3.graphics.DragPreviewProvider;
40 import com.android.launcher3.icons.FastBitmapDrawable;
41 import com.android.launcher3.icons.LauncherIcons;
42 import com.android.launcher3.icons.RoundDrawableWrapper;
43 import com.android.launcher3.widget.dragndrop.AppWidgetHostViewDragListener;
44 
45 /**
46  * Extension of {@link DragPreviewProvider} with logic specific to pending widgets/shortcuts
47  * dragged from the widget tray.
48  */
49 public class PendingItemDragHelper extends DragPreviewProvider {
50 
51     private static final float MAX_WIDGET_SCALE = 1.25f;
52 
53     private final PendingAddItemInfo mAddInfo;
54     private int[] mEstimatedCellSize;
55 
56     @Nullable private RemoteViews mRemoteViewsPreview;
57     @Nullable private NavigableAppWidgetHostView mAppWidgetHostViewPreview;
58     private final float mEnforcedRoundedCornersForWidget;
59 
PendingItemDragHelper(View view)60     public PendingItemDragHelper(View view) {
61         super(view);
62         mAddInfo = (PendingAddItemInfo) view.getTag();
63         mEnforcedRoundedCornersForWidget = RoundedCornerEnforcement.computeEnforcedRadius(
64                 view.getContext());
65     }
66 
67     /**
68      * Sets a {@link RemoteViews} which shows an app widget preview provided by app developers in
69      * the pin widget flow.
70      */
setRemoteViewsPreview(@ullable RemoteViews remoteViewsPreview)71     public void setRemoteViewsPreview(@Nullable RemoteViews remoteViewsPreview) {
72         mRemoteViewsPreview = remoteViewsPreview;
73     }
74 
75     /** Sets a {@link NavigableAppWidgetHostView} which shows a preview layout of an app widget. */
setAppWidgetHostViewPreview( @ullable NavigableAppWidgetHostView appWidgetHostViewPreview)76     public void setAppWidgetHostViewPreview(
77             @Nullable NavigableAppWidgetHostView appWidgetHostViewPreview) {
78         mAppWidgetHostViewPreview = appWidgetHostViewPreview;
79     }
80 
81     /**
82      * Starts the drag for the pending item associated with the view.
83      *
84      * @param previewBounds The bounds where the image was displayed,
85      *                      {@link WidgetImageView#getBitmapBounds()}
86      * @param previewBitmapWidth The actual width of the bitmap displayed in the view.
87      * @param previewViewWidth The width of {@link WidgetImageView} displaying the preview
88      * @param screenPos Position of {@link WidgetImageView} on the screen
89      */
startDrag(Rect previewBounds, int previewBitmapWidth, int previewViewWidth, Point screenPos, DragSource source, DragOptions options)90     public void startDrag(Rect previewBounds, int previewBitmapWidth, int previewViewWidth,
91             Point screenPos, DragSource source, DragOptions options) {
92         final Launcher launcher = Launcher.getLauncher(mView.getContext());
93         LauncherAppState app = LauncherAppState.getInstance(launcher);
94 
95         Drawable preview = null;
96         final int previewWidth;
97         final int previewHeight;
98         final float scale;
99         final Point dragOffset;
100         final Rect dragRegion;
101 
102         mEstimatedCellSize = launcher.getWorkspace().estimateItemSize(mAddInfo);
103 
104         DraggableView draggableView;
105 
106         if (mAddInfo instanceof PendingAddWidgetInfo) {
107             PendingAddWidgetInfo createWidgetInfo = (PendingAddWidgetInfo) mAddInfo;
108 
109             int maxWidth = Math.min((int) (previewBitmapWidth * MAX_WIDGET_SCALE), mEstimatedCellSize[0]);
110 
111             int[] previewSizeBeforeScale = new int[1];
112 
113             if (mRemoteViewsPreview != null) {
114                 mAppWidgetHostViewPreview = new LauncherAppWidgetHostView(launcher);
115                 mAppWidgetHostViewPreview.setAppWidget(/* appWidgetId= */ -1,
116                         ((PendingAddWidgetInfo) mAddInfo).info);
117                 DeviceProfile deviceProfile = launcher.getDeviceProfile();
118                 Rect padding = new Rect();
119                 mAppWidgetHostViewPreview.getWidgetInset(deviceProfile, padding);
120                 mAppWidgetHostViewPreview.setPadding(padding.left, padding.top, padding.right,
121                         padding.bottom);
122                 mAppWidgetHostViewPreview.updateAppWidget(/* remoteViews= */ mRemoteViewsPreview);
123                 int width =
124                         deviceProfile.cellWidthPx * mAddInfo.spanX + padding.left + padding.right;
125                 int height =
126                         deviceProfile.cellHeightPx * mAddInfo.spanY + padding.top + padding.bottom;
127                 mAppWidgetHostViewPreview.measure(
128                         MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
129                         MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
130             }
131             if (mAppWidgetHostViewPreview != null) {
132                 previewSizeBeforeScale[0] = mAppWidgetHostViewPreview.getMeasuredWidth();
133                 launcher.getDragController()
134                         .addDragListener(new AppWidgetHostViewDragListener(launcher));
135             }
136             if (preview == null && mAppWidgetHostViewPreview == null) {
137                 Drawable p = new FastBitmapDrawable(
138                         app.getWidgetCache().generateWidgetPreview(launcher,
139                                 createWidgetInfo.info, maxWidth, null,
140                                 previewSizeBeforeScale).first);
141                 if (RoundedCornerEnforcement.isRoundedCornerEnabled()) {
142                     p = new RoundDrawableWrapper(p, mEnforcedRoundedCornersForWidget);
143                 }
144                 preview = p;
145             }
146 
147             if (previewSizeBeforeScale[0] < previewBitmapWidth) {
148                 // The icon has extra padding around it.
149                 int padding = (previewBitmapWidth - previewSizeBeforeScale[0]) / 2;
150                 if (previewBitmapWidth > previewViewWidth) {
151                     padding = padding * previewViewWidth / previewBitmapWidth;
152                 }
153 
154                 previewBounds.left += padding;
155                 previewBounds.right -= padding;
156             }
157             if (mAppWidgetHostViewPreview != null) {
158                 previewWidth = mAppWidgetHostViewPreview.getMeasuredWidth();
159                 previewHeight = mAppWidgetHostViewPreview.getMeasuredHeight();
160             } else {
161                 previewWidth = preview.getIntrinsicWidth();
162                 previewHeight = preview.getIntrinsicHeight();
163             }
164             scale = previewBounds.width() / (float) previewWidth;
165             launcher.getDragController().addDragListener(new WidgetHostViewLoader(launcher, mView));
166 
167             dragOffset = null;
168             dragRegion = null;
169             draggableView = DraggableView.ofType(DraggableView.DRAGGABLE_WIDGET);
170         } else {
171             PendingAddShortcutInfo createShortcutInfo = (PendingAddShortcutInfo) mAddInfo;
172             Drawable icon = createShortcutInfo.activityInfo.getFullResIcon(app.getIconCache());
173             LauncherIcons li = LauncherIcons.obtain(launcher);
174             preview = new FastBitmapDrawable(
175                     li.createScaledBitmapWithoutShadow(icon, 0));
176             previewWidth = preview.getIntrinsicWidth();
177             previewHeight = preview.getIntrinsicHeight();
178             li.recycle();
179             scale = ((float) launcher.getDeviceProfile().iconSizePx) / previewWidth;
180 
181             dragOffset = new Point(previewPadding / 2, previewPadding / 2);
182 
183             // Create a preview same as the workspace cell size and draw the icon at the
184             // appropriate position.
185             DeviceProfile dp = launcher.getDeviceProfile();
186             int iconSize = dp.iconSizePx;
187 
188             int padding = launcher.getResources()
189                     .getDimensionPixelSize(R.dimen.widget_preview_shortcut_padding);
190             previewBounds.left += padding;
191             previewBounds.top += padding;
192 
193             dragRegion = new Rect();
194             dragRegion.left = (mEstimatedCellSize[0] - iconSize) / 2;
195             dragRegion.right = dragRegion.left + iconSize;
196             dragRegion.top = (mEstimatedCellSize[1]
197                     - iconSize - dp.iconTextSizePx - dp.iconDrawablePaddingPx) / 2;
198             dragRegion.bottom = dragRegion.top + iconSize;
199             draggableView = DraggableView.ofType(DraggableView.DRAGGABLE_ICON);
200         }
201 
202         // Since we are not going through the workspace for starting the drag, set drag related
203         // information on the workspace before starting the drag.
204         launcher.getWorkspace().prepareDragWithProvider(this);
205 
206         int dragLayerX = screenPos.x + previewBounds.left
207                 + (int) ((scale * previewWidth - previewWidth) / 2);
208         int dragLayerY = screenPos.y + previewBounds.top
209                 + (int) ((scale * previewHeight - previewHeight) / 2);
210 
211         // Start the drag
212         if (mAppWidgetHostViewPreview != null) {
213             launcher.getDragController().startDrag(mAppWidgetHostViewPreview, draggableView,
214                     dragLayerX, dragLayerY, source, mAddInfo, dragOffset, dragRegion, scale, scale,
215                     options);
216         } else {
217             launcher.getDragController().startDrag(preview, draggableView, dragLayerX, dragLayerY,
218                     source, mAddInfo, dragOffset, dragRegion, scale, scale, options);
219         }
220     }
221 
222     @Override
convertPreviewToAlphaBitmap(Bitmap preview)223     protected Bitmap convertPreviewToAlphaBitmap(Bitmap preview) {
224         if (mAddInfo instanceof PendingAddShortcutInfo || mEstimatedCellSize == null) {
225             return super.convertPreviewToAlphaBitmap(preview);
226         }
227 
228         int w = mEstimatedCellSize[0];
229         int h = mEstimatedCellSize[1];
230         final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ALPHA_8);
231         Rect src = new Rect(0, 0, preview.getWidth(), preview.getHeight());
232 
233         float scaleFactor = Math.min((w - blurSizeOutline) / (float) preview.getWidth(),
234                 (h - blurSizeOutline) / (float) preview.getHeight());
235         int scaledWidth = (int) (scaleFactor * preview.getWidth());
236         int scaledHeight = (int) (scaleFactor * preview.getHeight());
237         Rect dst = new Rect(0, 0, scaledWidth, scaledHeight);
238 
239         // center the image
240         dst.offset((w - scaledWidth) / 2, (h - scaledHeight) / 2);
241         new Canvas(b).drawBitmap(preview, src, dst, new Paint(Paint.FILTER_BITMAP_FLAG));
242         return b;
243     }
244 }
245