• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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.content.ClipData;
20 import android.content.ClipDescription;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.view.DragEvent;
24 import android.view.MotionEvent;
25 
26 import com.android.launcher3.DropTarget;
27 import com.android.launcher3.DropTarget.DragObject;
28 import com.android.launcher3.InstallShortcutReceiver;
29 import com.android.launcher3.ShortcutInfo;
30 import com.android.launcher3.Utilities;
31 
32 import java.util.ArrayList;
33 
34 /**
35  * Base class for driving a drag/drop operation.
36  */
37 public abstract class DragDriver {
38     protected final EventListener mEventListener;
39 
40     public interface EventListener {
onDriverDragMove(float x, float y)41         void onDriverDragMove(float x, float y);
onDriverDragExitWindow()42         void onDriverDragExitWindow();
onDriverDragEnd(float x, float y, DropTarget dropTargetOverride)43         void onDriverDragEnd(float x, float y, DropTarget dropTargetOverride);
onDriverDragCancel()44         void onDriverDragCancel();
45     }
46 
DragDriver(EventListener eventListener)47     public DragDriver(EventListener eventListener) {
48         mEventListener = eventListener;
49     }
50 
51     /**
52      * Handles ending of the DragView animation.
53      */
onDragViewAnimationEnd()54     public void onDragViewAnimationEnd() { }
55 
onTouchEvent(MotionEvent ev)56     public boolean onTouchEvent(MotionEvent ev) {
57         final int action = ev.getAction();
58 
59         switch (action) {
60             case MotionEvent.ACTION_MOVE:
61                 mEventListener.onDriverDragMove(ev.getX(), ev.getY());
62                 break;
63             case MotionEvent.ACTION_UP:
64                 mEventListener.onDriverDragMove(ev.getX(), ev.getY());
65                 mEventListener.onDriverDragEnd(ev.getX(), ev.getY(), null);
66                 break;
67             case MotionEvent.ACTION_CANCEL:
68                 mEventListener.onDriverDragCancel();
69                 break;
70         }
71 
72         return true;
73     }
74 
onDragEvent(DragEvent event)75     public abstract boolean onDragEvent (DragEvent event);
76 
77 
onInterceptTouchEvent(MotionEvent ev)78     public boolean onInterceptTouchEvent(MotionEvent ev) {
79         final int action = ev.getAction();
80 
81         switch (action) {
82             case MotionEvent.ACTION_UP:
83                 mEventListener.onDriverDragEnd(ev.getX(), ev.getY(), null);
84                 break;
85             case MotionEvent.ACTION_CANCEL:
86                 mEventListener.onDriverDragCancel();
87                 break;
88         }
89 
90         return true;
91     }
92 
create(Context context, DragController dragController, DragObject dragObject, DragOptions options)93     public static DragDriver create(Context context, DragController dragController,
94             DragObject dragObject, DragOptions options) {
95         if (Utilities.isNycOrAbove() && options.systemDndStartPoint != null) {
96             return new SystemDragDriver(dragController, context, dragObject);
97         } else {
98             return new InternalDragDriver(dragController);
99         }
100     }
101 }
102 
103 /**
104  * Class for driving a system (i.e. framework) drag/drop operation.
105  */
106 class SystemDragDriver extends DragDriver {
107 
108     private final DragObject mDragObject;
109     private final Context mContext;
110 
111     boolean mReceivedDropEvent = false;
112     float mLastX = 0;
113     float mLastY = 0;
114 
SystemDragDriver(DragController dragController, Context context, DragObject dragObject)115     public SystemDragDriver(DragController dragController, Context context, DragObject dragObject) {
116         super(dragController);
117         mDragObject = dragObject;
118         mContext = context;
119     }
120 
121     @Override
onTouchEvent(MotionEvent ev)122     public boolean onTouchEvent(MotionEvent ev) {
123         return false;
124     }
125 
126     @Override
onInterceptTouchEvent(MotionEvent ev)127     public boolean onInterceptTouchEvent(MotionEvent ev) {
128         return false;
129     }
130 
131     @Override
onDragEvent(DragEvent event)132     public boolean onDragEvent (DragEvent event) {
133         final int action = event.getAction();
134 
135         switch (action) {
136             case DragEvent.ACTION_DRAG_STARTED:
137                 mLastX = event.getX();
138                 mLastY = event.getY();
139                 return true;
140 
141             case DragEvent.ACTION_DRAG_ENTERED:
142                 return true;
143 
144             case DragEvent.ACTION_DRAG_LOCATION:
145                 mLastX = event.getX();
146                 mLastY = event.getY();
147                 mEventListener.onDriverDragMove(event.getX(), event.getY());
148                 return true;
149 
150             case DragEvent.ACTION_DROP:
151                 mLastX = event.getX();
152                 mLastY = event.getY();
153                 mReceivedDropEvent =
154                         updateInfoFromClipData(event.getClipData(), event.getClipDescription());
155                 return mReceivedDropEvent;
156 
157             case DragEvent.ACTION_DRAG_EXITED:
158                 mEventListener.onDriverDragExitWindow();
159                 return true;
160 
161             case DragEvent.ACTION_DRAG_ENDED:
162                 if (mReceivedDropEvent) {
163                     mEventListener.onDriverDragEnd(mLastX, mLastY, null);
164                 } else {
165                     mEventListener.onDriverDragCancel();
166                 }
167                 return true;
168 
169             default:
170                 return false;
171         }
172     }
173 
updateInfoFromClipData(ClipData data, ClipDescription desc)174     private boolean updateInfoFromClipData(ClipData data, ClipDescription desc) {
175         if (data == null) {
176             return false;
177         }
178         ArrayList<Intent> intents = new ArrayList<>();
179         int itemCount = data.getItemCount();
180         for (int i = 0; i < itemCount; i++) {
181             Intent intent = data.getItemAt(i).getIntent();
182             if (intent == null) {
183                 continue;
184             }
185 
186             // Give preference to shortcut intents.
187             if (!Intent.ACTION_CREATE_SHORTCUT.equals(intent.getAction())) {
188                 intents.add(intent);
189                 continue;
190             }
191             ShortcutInfo info = InstallShortcutReceiver.fromShortcutIntent(mContext, intent);
192             if (info != null) {
193                 mDragObject.dragInfo = info;
194                 return true;
195             }
196             return true;
197         }
198 
199         // Try creating shortcuts just using the intent and label
200         Intent fullIntent = new Intent().putExtra(Intent.EXTRA_SHORTCUT_NAME, desc.getLabel());
201         for (Intent intent : intents) {
202             fullIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, intent);
203             ShortcutInfo info = InstallShortcutReceiver.fromShortcutIntent(mContext, fullIntent);
204             if (info != null) {
205                 mDragObject.dragInfo = info;
206                 return true;
207             }
208         }
209 
210         return false;
211     }
212 }
213 
214 /**
215  * Class for driving an internal (i.e. not using framework) drag/drop operation.
216  */
217 class InternalDragDriver extends DragDriver {
InternalDragDriver(DragController dragController)218     public InternalDragDriver(DragController dragController) {
219         super(dragController);
220     }
221 
222     @Override
onDragEvent(DragEvent event)223     public boolean onDragEvent (DragEvent event) { return false; }
224 };
225