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.widget.RemoteViews;
27 
28 import com.android.launcher3.DeviceProfile;
29 import com.android.launcher3.DragSource;
30 import com.android.launcher3.Launcher;
31 import com.android.launcher3.LauncherAppState;
32 import com.android.launcher3.PendingAddItemInfo;
33 import com.android.launcher3.R;
34 import com.android.launcher3.dragndrop.DragOptions;
35 import com.android.launcher3.dragndrop.DraggableView;
36 import com.android.launcher3.dragndrop.LivePreviewWidgetCell;
37 import com.android.launcher3.graphics.DragPreviewProvider;
38 import com.android.launcher3.icons.LauncherIcons;
39 
40 /**
41  * Extension of {@link DragPreviewProvider} with logic specific to pending widgets/shortcuts
42  * dragged from the widget tray.
43  */
44 public class PendingItemDragHelper extends DragPreviewProvider {
45 
46     private static final float MAX_WIDGET_SCALE = 1.25f;
47 
48     private final PendingAddItemInfo mAddInfo;
49     private int[] mEstimatedCellSize;
50 
51     private RemoteViews mPreview;
52 
PendingItemDragHelper(View view)53     public PendingItemDragHelper(View view) {
54         super(view);
55         mAddInfo = (PendingAddItemInfo) view.getTag();
56     }
57 
setPreview(RemoteViews preview)58     public void setPreview(RemoteViews preview) {
59         mPreview = preview;
60     }
61 
62     /**
63      * Starts the drag for the pending item associated with the view.
64      *
65      * @param previewBounds The bounds where the image was displayed,
66      *                      {@link WidgetImageView#getBitmapBounds()}
67      * @param previewBitmapWidth The actual width of the bitmap displayed in the view.
68      * @param previewViewWidth The width of {@link WidgetImageView} displaying the preview
69      * @param screenPos Position of {@link WidgetImageView} on the screen
70      */
startDrag(Rect previewBounds, int previewBitmapWidth, int previewViewWidth, Point screenPos, DragSource source, DragOptions options)71     public void startDrag(Rect previewBounds, int previewBitmapWidth, int previewViewWidth,
72             Point screenPos, DragSource source, DragOptions options) {
73         final Launcher launcher = Launcher.getLauncher(mView.getContext());
74         LauncherAppState app = LauncherAppState.getInstance(launcher);
75 
76         Bitmap preview = null;
77         final float scale;
78         final Point dragOffset;
79         final Rect dragRegion;
80 
81         mEstimatedCellSize = launcher.getWorkspace().estimateItemSize(mAddInfo);
82 
83         DraggableView draggableView;
84 
85         if (mAddInfo instanceof PendingAddWidgetInfo) {
86             PendingAddWidgetInfo createWidgetInfo = (PendingAddWidgetInfo) mAddInfo;
87 
88             int maxWidth = Math.min((int) (previewBitmapWidth * MAX_WIDGET_SCALE), mEstimatedCellSize[0]);
89 
90             int[] previewSizeBeforeScale = new int[1];
91 
92             if (mPreview != null) {
93                 preview = LivePreviewWidgetCell.generateFromRemoteViews(launcher, mPreview,
94                         createWidgetInfo.info, maxWidth, previewSizeBeforeScale);
95             }
96             if (preview == null) {
97                 preview = app.getWidgetCache().generateWidgetPreview(launcher,
98                         createWidgetInfo.info, maxWidth, null, previewSizeBeforeScale).first;
99             }
100 
101             if (previewSizeBeforeScale[0] < previewBitmapWidth) {
102                 // The icon has extra padding around it.
103                 int padding = (previewBitmapWidth - previewSizeBeforeScale[0]) / 2;
104                 if (previewBitmapWidth > previewViewWidth) {
105                     padding = padding * previewViewWidth / previewBitmapWidth;
106                 }
107 
108                 previewBounds.left += padding;
109                 previewBounds.right -= padding;
110             }
111             scale = previewBounds.width() / (float) preview.getWidth();
112             launcher.getDragController().addDragListener(new WidgetHostViewLoader(launcher, mView));
113 
114             dragOffset = null;
115             dragRegion = null;
116             draggableView = DraggableView.ofType(DraggableView.DRAGGABLE_WIDGET);
117         } else {
118             PendingAddShortcutInfo createShortcutInfo = (PendingAddShortcutInfo) mAddInfo;
119             Drawable icon = createShortcutInfo.activityInfo.getFullResIcon(app.getIconCache());
120             LauncherIcons li = LauncherIcons.obtain(launcher);
121             preview = li.createScaledBitmapWithoutShadow(icon, 0);
122             li.recycle();
123             scale = ((float) launcher.getDeviceProfile().iconSizePx) / preview.getWidth();
124 
125             dragOffset = new Point(previewPadding / 2, previewPadding / 2);
126 
127             // Create a preview same as the workspace cell size and draw the icon at the
128             // appropriate position.
129             DeviceProfile dp = launcher.getDeviceProfile();
130             int iconSize = dp.iconSizePx;
131 
132             int padding = launcher.getResources()
133                     .getDimensionPixelSize(R.dimen.widget_preview_shortcut_padding);
134             previewBounds.left += padding;
135             previewBounds.top += padding;
136 
137             dragRegion = new Rect();
138             dragRegion.left = (mEstimatedCellSize[0] - iconSize) / 2;
139             dragRegion.right = dragRegion.left + iconSize;
140             dragRegion.top = (mEstimatedCellSize[1]
141                     - iconSize - dp.iconTextSizePx - dp.iconDrawablePaddingPx) / 2;
142             dragRegion.bottom = dragRegion.top + iconSize;
143             draggableView = DraggableView.ofType(DraggableView.DRAGGABLE_ICON);
144         }
145 
146         // Since we are not going through the workspace for starting the drag, set drag related
147         // information on the workspace before starting the drag.
148         launcher.getWorkspace().prepareDragWithProvider(this);
149 
150         int dragLayerX = screenPos.x + previewBounds.left
151                 + (int) ((scale * preview.getWidth() - preview.getWidth()) / 2);
152         int dragLayerY = screenPos.y + previewBounds.top
153                 + (int) ((scale * preview.getHeight() - preview.getHeight()) / 2);
154 
155         // Start the drag
156         launcher.getDragController().startDrag(preview, draggableView, dragLayerX, dragLayerY,
157                 source, mAddInfo, dragOffset, dragRegion, scale, scale, options);
158     }
159 
160     @Override
convertPreviewToAlphaBitmap(Bitmap preview)161     protected Bitmap convertPreviewToAlphaBitmap(Bitmap preview) {
162         if (mAddInfo instanceof PendingAddShortcutInfo || mEstimatedCellSize == null) {
163             return super.convertPreviewToAlphaBitmap(preview);
164         }
165 
166         int w = mEstimatedCellSize[0];
167         int h = mEstimatedCellSize[1];
168         final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ALPHA_8);
169         Rect src = new Rect(0, 0, preview.getWidth(), preview.getHeight());
170 
171         float scaleFactor = Math.min((w - blurSizeOutline) / (float) preview.getWidth(),
172                 (h - blurSizeOutline) / (float) preview.getHeight());
173         int scaledWidth = (int) (scaleFactor * preview.getWidth());
174         int scaledHeight = (int) (scaleFactor * preview.getHeight());
175         Rect dst = new Rect(0, 0, scaledWidth, scaledHeight);
176 
177         // center the image
178         dst.offset((w - scaledWidth) / 2, (h - scaledHeight) / 2);
179         new Canvas(b).drawBitmap(preview, src, dst, new Paint(Paint.FILTER_BITMAP_FLAG));
180         return b;
181     }
182 }
183