OSDN Git Service

Update icon badges to match spec
[android-x86/packages-apps-Launcher3.git] / src / com / android / launcher3 / dragndrop / PinItemDragListener.java
1 /*
2  * Copyright (C) 2017 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.dragndrop;
18
19 import android.appwidget.AppWidgetManager;
20 import android.content.ClipDescription;
21 import android.content.Intent;
22 import android.graphics.Point;
23 import android.graphics.Rect;
24 import android.os.Bundle;
25 import android.os.Handler;
26 import android.os.Looper;
27 import android.os.Parcel;
28 import android.os.Parcelable;
29 import android.os.SystemClock;
30 import android.util.Log;
31 import android.view.DragEvent;
32 import android.view.View;
33 import android.widget.RemoteViews;
34
35 import com.android.launcher3.DeleteDropTarget;
36 import com.android.launcher3.DragSource;
37 import com.android.launcher3.DropTarget;
38 import com.android.launcher3.ItemInfo;
39 import com.android.launcher3.Launcher;
40 import com.android.launcher3.LauncherAppWidgetProviderInfo;
41 import com.android.launcher3.PendingAddItemInfo;
42 import com.android.launcher3.R;
43 import com.android.launcher3.compat.PinItemRequestCompat;
44 import com.android.launcher3.folder.Folder;
45 import com.android.launcher3.userevent.nano.LauncherLogProto;
46 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
47 import com.android.launcher3.widget.PendingAddShortcutInfo;
48 import com.android.launcher3.widget.PendingAddWidgetInfo;
49 import com.android.launcher3.widget.PendingItemDragHelper;
50 import com.android.launcher3.widget.WidgetAddFlowHandler;
51
52 import java.util.UUID;
53
54 /**
55  * {@link DragSource} for handling drop from a different window. This object is initialized
56  * in the source window and is passed on to the Launcher activity as an Intent extra.
57  */
58 public class PinItemDragListener
59         implements Parcelable, View.OnDragListener, DragSource, DragOptions.PreDragCondition {
60
61     private static final String TAG = "PinItemDragListener";
62
63     private static final String MIME_TYPE_PREFIX = "com.android.launcher3.drag_and_drop/";
64     public static final String EXTRA_PIN_ITEM_DRAG_LISTENER = "pin_item_drag_listener";
65
66     private final PinItemRequestCompat mRequest;
67
68     // Position of preview relative to the touch location
69     private final Rect mPreviewRect;
70
71     private final int mPreviewBitmapWidth;
72     private final int mPreviewViewWidth;
73
74     // Randomly generated id used to verify the drag event.
75     private final String mId;
76
77     private Launcher mLauncher;
78     private DragController mDragController;
79     private long mDragStartTime;
80
81     public PinItemDragListener(PinItemRequestCompat request, Rect previewRect,
82             int previewBitmapWidth, int previewViewWidth) {
83         mRequest = request;
84         mPreviewRect = previewRect;
85         mPreviewBitmapWidth = previewBitmapWidth;
86         mPreviewViewWidth = previewViewWidth;
87         mId = UUID.randomUUID().toString();
88     }
89
90     private PinItemDragListener(Parcel parcel) {
91         mRequest = PinItemRequestCompat.CREATOR.createFromParcel(parcel);
92         mPreviewRect = Rect.CREATOR.createFromParcel(parcel);
93         mPreviewBitmapWidth = parcel.readInt();
94         mPreviewViewWidth = parcel.readInt();
95         mId = parcel.readString();
96     }
97
98     public String getMimeType() {
99         return MIME_TYPE_PREFIX + mId;
100     }
101
102     @Override
103     public int describeContents() {
104         return 0;
105     }
106
107     @Override
108     public void writeToParcel(Parcel parcel, int i) {
109         mRequest.writeToParcel(parcel, i);
110         mPreviewRect.writeToParcel(parcel, i);
111         parcel.writeInt(mPreviewBitmapWidth);
112         parcel.writeInt(mPreviewViewWidth);
113         parcel.writeString(mId);
114     }
115
116     public void setLauncher(Launcher launcher) {
117         mLauncher = launcher;
118         mDragController = launcher.getDragController();
119     }
120
121     @Override
122     public boolean onDrag(View view, DragEvent event) {
123         if (mLauncher == null || mDragController == null) {
124             postCleanup();
125             return false;
126         }
127         if (event.getAction() == DragEvent.ACTION_DRAG_STARTED) {
128             if (onDragStart(event)) {
129                 return true;
130             } else {
131                 postCleanup();
132                 return false;
133             }
134         }
135         return mDragController.onDragEvent(mDragStartTime, event);
136     }
137
138     private boolean onDragStart(DragEvent event) {
139         if (!mRequest.isValid()) {
140             return false;
141         }
142         ClipDescription desc =  event.getClipDescription();
143         if (desc == null || !desc.hasMimeType(getMimeType())) {
144             Log.e(TAG, "Someone started a dragAndDrop before us.");
145             return false;
146         }
147
148         final PendingAddItemInfo item;
149         if (mRequest.getRequestType() == PinItemRequestCompat.REQUEST_TYPE_SHORTCUT) {
150             item = new PendingAddShortcutInfo(
151                     new PinShortcutRequestActivityInfo(mRequest, mLauncher));
152         } else {
153             // mRequest.getRequestType() == PinItemRequestCompat.REQUEST_TYPE_APPWIDGET
154             LauncherAppWidgetProviderInfo providerInfo =
155                     LauncherAppWidgetProviderInfo.fromProviderInfo(
156                             mLauncher, mRequest.getAppWidgetProviderInfo(mLauncher));
157             final PinWidgetFlowHandler flowHandler =
158                     new PinWidgetFlowHandler(providerInfo, mRequest);
159             item = new PendingAddWidgetInfo(providerInfo) {
160                 @Override
161                 public WidgetAddFlowHandler getHandler() {
162                     return flowHandler;
163                 }
164             };
165         }
166         View view = new View(mLauncher);
167         view.setTag(item);
168
169         Point downPos = new Point((int) event.getX(), (int) event.getY());
170         DragOptions options = new DragOptions();
171         options.systemDndStartPoint = downPos;
172         options.preDragCondition = this;
173
174         // We use drag event position as the screenPos for the preview image. Since mPreviewRect
175         // already includes the view position relative to the drag event on the source window,
176         // and the absolute position (position relative to the screen) of drag event is same
177         // across windows, using drag position here give a good estimate for relative position
178         // to source window.
179         PendingItemDragHelper dragHelper = new PendingItemDragHelper(view);
180         if (mRequest.getRequestType() == PinItemRequestCompat.REQUEST_TYPE_APPWIDGET) {
181             dragHelper.setPreview(getPreview(mRequest));
182         }
183
184         dragHelper.startDrag(new Rect(mPreviewRect),
185                 mPreviewBitmapWidth, mPreviewViewWidth, downPos,  this, options);
186         mDragStartTime = SystemClock.uptimeMillis();
187         return true;
188     }
189
190     @Override
191     public boolean shouldStartDrag(double distanceDragged) {
192         // Stay in pre-drag mode, if workspace is locked.
193         return !mLauncher.isWorkspaceLocked();
194     }
195
196     @Override
197     public void onPreDragStart(DropTarget.DragObject dragObject) {
198         // The predrag starts when the workspace is not yet loaded. In some cases we set
199         // the dragLayer alpha to 0 to have a nice fade-in animation. But that will prevent the
200         // dragView from being visible. Instead just skip the fade-in animation here.
201         mLauncher.getDragLayer().setAlpha(1);
202
203         dragObject.dragView.setColor(
204                 mLauncher.getResources().getColor(R.color.delete_target_hover_tint));
205     }
206
207     @Override
208     public void onPreDragEnd(DropTarget.DragObject dragObject, boolean dragStarted) {
209         if (dragStarted) {
210             dragObject.dragView.setColor(0);
211         }
212     }
213
214     @Override
215     public boolean supportsAppInfoDropTarget() {
216         return false;
217     }
218
219     @Override
220     public boolean supportsDeleteDropTarget() {
221         return false;
222     }
223
224     @Override
225     public float getIntrinsicIconScaleFactor() {
226         return 1f;
227     }
228
229     @Override
230     public void onDropCompleted(View target, DropTarget.DragObject d, boolean isFlingToDelete,
231             boolean success) {
232         if (isFlingToDelete || !success || (target != mLauncher.getWorkspace() &&
233                 !(target instanceof DeleteDropTarget) && !(target instanceof Folder))) {
234             // Exit spring loaded mode if we have not successfully dropped or have not handled the
235             // drop in Workspace
236             mLauncher.exitSpringLoadedDragModeDelayed(true,
237                     Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);
238         }
239         postCleanup();
240     }
241
242     @Override
243     public void fillInLogContainerData(View v, ItemInfo info, LauncherLogProto.Target target,
244             LauncherLogProto.Target targetParent) {
245         targetParent.containerType = ContainerType.PINITEM;
246     }
247
248     private void postCleanup() {
249         if (mLauncher != null) {
250             // Remove any drag params from the launcher intent since the drag operation is complete.
251             Intent newIntent = new Intent(mLauncher.getIntent());
252             newIntent.removeExtra(EXTRA_PIN_ITEM_DRAG_LISTENER);
253             mLauncher.setIntent(newIntent);
254         }
255
256         new Handler(Looper.getMainLooper()).post(new Runnable() {
257             @Override
258             public void run() {
259                 removeListener();
260             }
261         });
262     }
263
264     public void removeListener() {
265         if (mLauncher != null) {
266             mLauncher.getDragLayer().setOnDragListener(null);
267         }
268     }
269
270     public static RemoteViews getPreview(PinItemRequestCompat request) {
271         Bundle extras = request.getExtras();
272         if (extras != null &&
273                 extras.get(AppWidgetManager.EXTRA_APPWIDGET_PREVIEW) instanceof RemoteViews) {
274             return (RemoteViews) extras.get(AppWidgetManager.EXTRA_APPWIDGET_PREVIEW);
275         }
276         return null;
277     }
278
279     public static boolean handleDragRequest(Launcher launcher, Intent intent) {
280         if (intent == null || !Intent.ACTION_MAIN.equals(intent.getAction())) {
281             return false;
282         }
283         Parcelable dragExtra = intent.getParcelableExtra(EXTRA_PIN_ITEM_DRAG_LISTENER);
284         if (dragExtra instanceof PinItemDragListener) {
285             PinItemDragListener dragListener = (PinItemDragListener) dragExtra;
286             dragListener.setLauncher(launcher);
287
288             launcher.getDragLayer().setOnDragListener(dragListener);
289             return true;
290         }
291         return false;
292     }
293
294     public static final Parcelable.Creator<PinItemDragListener> CREATOR =
295             new Parcelable.Creator<PinItemDragListener>() {
296                 public PinItemDragListener createFromParcel(Parcel source) {
297                     return new PinItemDragListener(source);
298                 }
299
300                 public PinItemDragListener[] newArray(int size) {
301                     return new PinItemDragListener[size];
302                 }
303             };
304 }