• 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.graphics;
18 
19 import android.content.Context;
20 import android.graphics.Bitmap;
21 import android.graphics.Canvas;
22 import android.graphics.Rect;
23 import android.graphics.drawable.Drawable;
24 import android.view.View;
25 
26 import androidx.annotation.Nullable;
27 
28 import com.android.launcher3.R;
29 import com.android.launcher3.dragndrop.DraggableView;
30 import com.android.launcher3.icons.BitmapRenderer;
31 import com.android.launcher3.icons.FastBitmapDrawable;
32 import com.android.launcher3.util.SafeCloseable;
33 import com.android.launcher3.views.ActivityContext;
34 import com.android.launcher3.widget.LauncherAppWidgetHostView;
35 
36 /**
37  * A utility class to generate preview bitmap for dragging.
38  */
39 public class DragPreviewProvider {
40 
41     private final Rect mTempRect = new Rect();
42 
43     protected final View mView;
44 
45     // The padding added to the drag view during the preview generation.
46     public final int previewPadding;
47 
48     public final int blurSizeOutline;
49 
DragPreviewProvider(View view)50     public DragPreviewProvider(View view) {
51         this(view, view.getContext());
52     }
53 
DragPreviewProvider(View view, Context context)54     public DragPreviewProvider(View view, Context context) {
55         mView = view;
56         blurSizeOutline =
57                 context.getResources().getDimensionPixelSize(R.dimen.blur_size_medium_outline);
58         previewPadding = blurSizeOutline;
59     }
60 
61     /**
62      * Draws the {@link #mView} into the given {@param destCanvas}.
63      */
drawDragView(Canvas destCanvas, float scale)64     protected void drawDragView(Canvas destCanvas, float scale) {
65         int saveCount = destCanvas.save();
66         destCanvas.scale(scale, scale);
67 
68         if (mView instanceof DraggableView) {
69             DraggableView dv = (DraggableView) mView;
70             try (SafeCloseable t = dv.prepareDrawDragView()) {
71                 dv.getSourceVisualDragBounds(mTempRect);
72                 destCanvas.translate(blurSizeOutline / 2 - mTempRect.left,
73                         blurSizeOutline / 2 - mTempRect.top);
74                 mView.draw(destCanvas);
75             }
76         }
77         destCanvas.restoreToCount(saveCount);
78     }
79 
80     /**
81      * Returns a new drawable to show when the {@link #mView} is being dragged around.
82      * Responsibility for the drawable is transferred to the caller.
83      */
createDrawable()84     public Drawable createDrawable() {
85         if (mView instanceof LauncherAppWidgetHostView) {
86             return null;
87         }
88 
89         int width = 0;
90         int height = 0;
91         // Assume scaleX == scaleY, which is always the case for workspace items.
92         float scale = mView.getScaleX();
93         if (mView instanceof DraggableView) {
94             ((DraggableView) mView).getSourceVisualDragBounds(mTempRect);
95             width = mTempRect.width();
96             height = mTempRect.height();
97         } else {
98             width = mView.getWidth();
99             height = mView.getHeight();
100         }
101 
102         return new FastBitmapDrawable(
103                 BitmapRenderer.createHardwareBitmap(width + blurSizeOutline,
104                         height + blurSizeOutline, (c) -> drawDragView(c, scale)));
105     }
106 
107     /**
108      * Returns the content view if the content should be rendered directly in
109      * {@link com.android.launcher3.dragndrop.DragView}. Otherwise, returns null.
110      */
111     @Nullable
getContentView()112     public View getContentView() {
113         if (mView instanceof LauncherAppWidgetHostView) {
114             return mView;
115         }
116         return null;
117     }
118 
getDrawableBounds(Drawable d)119     protected static Rect getDrawableBounds(Drawable d) {
120         Rect bounds = new Rect();
121         d.copyBounds(bounds);
122         if (bounds.width() == 0 || bounds.height() == 0) {
123             bounds.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
124         } else {
125             bounds.offsetTo(0, 0);
126         }
127         return bounds;
128     }
129 
getScaleAndPosition(Drawable preview, int[] outPos)130     public float getScaleAndPosition(Drawable preview, int[] outPos) {
131         float scale = ActivityContext.lookupContext(mView.getContext())
132                 .getDragLayer().getLocationInDragLayer(mView, outPos);
133         if (mView instanceof LauncherAppWidgetHostView) {
134             // App widgets are technically scaled, but are drawn at their expected size -- so the
135             // app widget scale should not affect the scale of the preview.
136             scale /= ((LauncherAppWidgetHostView) mView).getScaleToFit();
137         }
138 
139         outPos[0] = Math.round(outPos[0] -
140                 (preview.getIntrinsicWidth() - scale * mView.getWidth() * mView.getScaleX()) / 2);
141         outPos[1] = Math.round(outPos[1] - (1 - scale) * preview.getIntrinsicHeight() / 2
142                 - previewPadding / 2);
143         return scale;
144     }
145 
146     /** Returns the scale and position of a given view for drag-n-drop. */
getScaleAndPosition(View view, int[] outPos)147     public float getScaleAndPosition(View view, int[] outPos) {
148         float scale = ActivityContext.lookupContext(mView.getContext())
149                 .getDragLayer().getLocationInDragLayer(mView, outPos);
150         if (mView instanceof LauncherAppWidgetHostView) {
151             // App widgets are technically scaled, but are drawn at their expected size -- so the
152             // app widget scale should not affect the scale of the preview.
153             scale /= ((LauncherAppWidgetHostView) mView).getScaleToFit();
154         }
155 
156         outPos[0] = Math.round(outPos[0]
157                 - (view.getWidth() - scale * mView.getWidth() * mView.getScaleX()) / 2);
158         outPos[1] = Math.round(outPos[1] - (1 - scale) * view.getHeight() / 2 - previewPadding / 2);
159         return scale;
160     }
161 
convertPreviewToAlphaBitmap(Bitmap preview)162     protected Bitmap convertPreviewToAlphaBitmap(Bitmap preview) {
163         return preview.copy(Bitmap.Config.ALPHA_8, true);
164     }
165 }
166