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