• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 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.launcher2;
18 
19 import android.content.Context;
20 import android.graphics.Bitmap;
21 import android.graphics.Point;
22 import android.graphics.Rect;
23 import android.graphics.RectF;
24 import android.os.Handler;
25 import android.os.IBinder;
26 import android.os.Vibrator;
27 import android.util.Log;
28 import android.view.KeyEvent;
29 import android.view.MotionEvent;
30 import android.view.View;
31 import android.view.ViewConfiguration;
32 import android.view.inputmethod.InputMethodManager;
33 
34 import com.android.launcher.R;
35 
36 import java.util.ArrayList;
37 
38 /**
39  * Class for initiating a drag within a view or across multiple views.
40  */
41 public class DragController {
42     @SuppressWarnings({"UnusedDeclaration"})
43     private static final String TAG = "Launcher.DragController";
44 
45     /** Indicates the drag is a move.  */
46     public static int DRAG_ACTION_MOVE = 0;
47 
48     /** Indicates the drag is a copy.  */
49     public static int DRAG_ACTION_COPY = 1;
50 
51     private static final int SCROLL_DELAY = 600;
52     private static final int VIBRATE_DURATION = 35;
53 
54     private static final boolean PROFILE_DRAWING_DURING_DRAG = false;
55 
56     private static final int SCROLL_OUTSIDE_ZONE = 0;
57     private static final int SCROLL_WAITING_IN_ZONE = 1;
58 
59     static final int SCROLL_NONE = -1;
60     static final int SCROLL_LEFT = 0;
61     static final int SCROLL_RIGHT = 1;
62 
63     private Launcher mLauncher;
64     private Handler mHandler;
65     private final Vibrator mVibrator = new Vibrator();
66 
67     // temporaries to avoid gc thrash
68     private Rect mRectTemp = new Rect();
69     private final int[] mCoordinatesTemp = new int[2];
70 
71     /** Whether or not we're dragging. */
72     private boolean mDragging;
73 
74     /** X coordinate of the down event. */
75     private int mMotionDownX;
76 
77     /** Y coordinate of the down event. */
78     private int mMotionDownY;
79 
80     /** the area at the edge of the screen that makes the workspace go left
81      *   or right while you're dragging.
82      */
83     private int mScrollZone;
84 
85     private DropTarget.DragObject mDragObject;
86 
87     /** Who can receive drop events */
88     private ArrayList<DropTarget> mDropTargets = new ArrayList<DropTarget>();
89 
90     private ArrayList<DragListener> mListeners = new ArrayList<DragListener>();
91 
92     /** The window token used as the parent for the DragView. */
93     private IBinder mWindowToken;
94 
95     /** The view that will be scrolled when dragging to the left and right edges of the screen. */
96     private View mScrollView;
97 
98     private View mMoveTarget;
99 
100     private DragScroller mDragScroller;
101     private int mScrollState = SCROLL_OUTSIDE_ZONE;
102     private ScrollRunnable mScrollRunnable = new ScrollRunnable();
103 
104     private RectF mDeleteRegion;
105     private DropTarget mLastDropTarget;
106 
107     private InputMethodManager mInputMethodManager;
108 
109     private int mLastTouch[] = new int[2];
110     private int mDistanceSinceScroll = 0;
111 
112     private int mTmpPoint[] = new int[2];
113     private Rect mDragLayerRect = new Rect();
114 
115     /**
116      * Interface to receive notifications when a drag starts or stops
117      */
118     interface DragListener {
119 
120         /**
121          * A drag has begun
122          *
123          * @param source An object representing where the drag originated
124          * @param info The data associated with the object that is being dragged
125          * @param dragAction The drag action: either {@link DragController#DRAG_ACTION_MOVE}
126          *        or {@link DragController#DRAG_ACTION_COPY}
127          */
onDragStart(DragSource source, Object info, int dragAction)128         void onDragStart(DragSource source, Object info, int dragAction);
129 
130         /**
131          * The drag has ended
132          */
onDragEnd()133         void onDragEnd();
134     }
135 
136     /**
137      * Used to create a new DragLayer from XML.
138      *
139      * @param context The application's context.
140      */
DragController(Launcher launcher)141     public DragController(Launcher launcher) {
142         mLauncher = launcher;
143         mHandler = new Handler();
144         mScrollZone = launcher.getResources().getDimensionPixelSize(R.dimen.scroll_zone);
145     }
146 
dragging()147     public boolean dragging() {
148         return mDragging;
149     }
150 
151     /**
152      * Starts a drag.
153      *
154      * @param v The view that is being dragged
155      * @param source An object representing where the drag originated
156      * @param dragInfo The data associated with the object that is being dragged
157      * @param dragAction The drag action: either {@link #DRAG_ACTION_MOVE} or
158      *        {@link #DRAG_ACTION_COPY}
159      */
startDrag(View v, DragSource source, Object dragInfo, int dragAction)160     public void startDrag(View v, DragSource source, Object dragInfo, int dragAction) {
161         startDrag(v, source, dragInfo, dragAction, null);
162     }
163 
164     /**
165      * Starts a drag.
166      *
167      * @param v The view that is being dragged
168      * @param source An object representing where the drag originated
169      * @param dragInfo The data associated with the object that is being dragged
170      * @param dragAction The drag action: either {@link #DRAG_ACTION_MOVE} or
171      *        {@link #DRAG_ACTION_COPY}
172      * @param dragRegion Coordinates within the bitmap b for the position of item being dragged.
173      *          Makes dragging feel more precise, e.g. you can clip out a transparent border
174      */
startDrag(View v, DragSource source, Object dragInfo, int dragAction, Rect dragRegion)175     public void startDrag(View v, DragSource source, Object dragInfo, int dragAction,
176             Rect dragRegion) {
177         Bitmap b = getViewBitmap(v);
178 
179         if (b == null) {
180             // out of memory?
181             return;
182         }
183 
184         int[] loc = mCoordinatesTemp;
185         mLauncher.getDragLayer().getLocationInDragLayer(v, loc);
186         int dragLayerX = loc[0];
187         int dragLayerY = loc[1];
188 
189         startDrag(b, dragLayerX, dragLayerY, source, dragInfo, dragAction, null, dragRegion);
190         b.recycle();
191 
192         if (dragAction == DRAG_ACTION_MOVE) {
193             v.setVisibility(View.GONE);
194         }
195     }
196 
197     /**
198      * Starts a drag.
199      *
200      * @param v The view that is being dragged
201      * @param bmp The bitmap that represents the view being dragged
202      * @param source An object representing where the drag originated
203      * @param dragInfo The data associated with the object that is being dragged
204      * @param dragAction The drag action: either {@link #DRAG_ACTION_MOVE} or
205      *        {@link #DRAG_ACTION_COPY}
206      * @param dragRegion Coordinates within the bitmap b for the position of item being dragged.
207      *          Makes dragging feel more precise, e.g. you can clip out a transparent border
208      */
startDrag(View v, Bitmap bmp, DragSource source, Object dragInfo, int dragAction, Rect dragRegion)209     public void startDrag(View v, Bitmap bmp, DragSource source, Object dragInfo, int dragAction,
210             Rect dragRegion) {
211         int[] loc = mCoordinatesTemp;
212         mLauncher.getDragLayer().getLocationInDragLayer(v, loc);
213         int dragLayerX = loc[0];
214         int dragLayerY = loc[1];
215 
216         startDrag(bmp, dragLayerX, dragLayerY, source, dragInfo, dragAction, null, dragRegion);
217 
218         if (dragAction == DRAG_ACTION_MOVE) {
219             v.setVisibility(View.GONE);
220         }
221     }
222 
223     /**
224      * Starts a drag.
225      *
226      * @param b The bitmap to display as the drag image.  It will be re-scaled to the
227      *          enlarged size.
228      * @param dragLayerX The x position in the DragLayer of the left-top of the bitmap.
229      * @param dragLayerY The y position in the DragLayer of the left-top of the bitmap.
230      * @param source An object representing where the drag originated
231      * @param dragInfo The data associated with the object that is being dragged
232      * @param dragAction The drag action: either {@link #DRAG_ACTION_MOVE} or
233      *        {@link #DRAG_ACTION_COPY}
234      */
startDrag(Bitmap b, int dragLayerX, int dragLayerY, DragSource source, Object dragInfo, int dragAction)235     public void startDrag(Bitmap b, int dragLayerX, int dragLayerY,
236             DragSource source, Object dragInfo, int dragAction) {
237         startDrag(b, dragLayerX, dragLayerY, source, dragInfo, dragAction, null, null);
238     }
239 
240     /**
241      * Starts a drag.
242      *
243      * @param b The bitmap to display as the drag image.  It will be re-scaled to the
244      *          enlarged size.
245      * @param dragLayerX The x position in the DragLayer of the left-top of the bitmap.
246      * @param dragLayerY The y position in the DragLayer of the left-top of the bitmap.
247      * @param source An object representing where the drag originated
248      * @param dragInfo The data associated with the object that is being dragged
249      * @param dragAction The drag action: either {@link #DRAG_ACTION_MOVE} or
250      *        {@link #DRAG_ACTION_COPY}
251      * @param dragRegion Coordinates within the bitmap b for the position of item being dragged.
252      *          Makes dragging feel more precise, e.g. you can clip out a transparent border
253      */
startDrag(Bitmap b, int dragLayerX, int dragLayerY, DragSource source, Object dragInfo, int dragAction, Point dragOffset, Rect dragRegion)254     public void startDrag(Bitmap b, int dragLayerX, int dragLayerY,
255             DragSource source, Object dragInfo, int dragAction, Point dragOffset, Rect dragRegion) {
256         if (PROFILE_DRAWING_DURING_DRAG) {
257             android.os.Debug.startMethodTracing("Launcher");
258         }
259 
260         // Hide soft keyboard, if visible
261         if (mInputMethodManager == null) {
262             mInputMethodManager = (InputMethodManager)
263                     mLauncher.getSystemService(Context.INPUT_METHOD_SERVICE);
264         }
265         mInputMethodManager.hideSoftInputFromWindow(mWindowToken, 0);
266 
267         for (DragListener listener : mListeners) {
268             listener.onDragStart(source, dragInfo, dragAction);
269         }
270 
271         final int registrationX = mMotionDownX - dragLayerX;
272         final int registrationY = mMotionDownY - dragLayerY;
273 
274         final int dragRegionLeft = dragRegion == null ? 0 : dragRegion.left;
275         final int dragRegionTop = dragRegion == null ? 0 : dragRegion.top;
276 
277         mDragging = true;
278 
279         mDragObject = new DropTarget.DragObject();
280 
281         mDragObject.dragComplete = false;
282         mDragObject.xOffset = mMotionDownX - (dragLayerX + dragRegionLeft);
283         mDragObject.yOffset = mMotionDownY - (dragLayerY + dragRegionTop);
284         mDragObject.dragSource = source;
285         mDragObject.dragInfo = dragInfo;
286 
287         mVibrator.vibrate(VIBRATE_DURATION);
288 
289         final DragView dragView = mDragObject.dragView = new DragView(mLauncher, b, registrationX,
290                 registrationY, 0, 0, b.getWidth(), b.getHeight());
291 
292         if (dragOffset != null) {
293             dragView.setDragVisualizeOffset(new Point(dragOffset));
294         }
295         if (dragRegion != null) {
296             dragView.setDragRegion(new Rect(dragRegion));
297         }
298 
299         dragView.show(mMotionDownX, mMotionDownY);
300         handleMoveEvent(mMotionDownX, mMotionDownY);
301     }
302 
303     /**
304      * Draw the view into a bitmap.
305      */
getViewBitmap(View v)306     Bitmap getViewBitmap(View v) {
307         v.clearFocus();
308         v.setPressed(false);
309 
310         boolean willNotCache = v.willNotCacheDrawing();
311         v.setWillNotCacheDrawing(false);
312 
313         // Reset the drawing cache background color to fully transparent
314         // for the duration of this operation
315         int color = v.getDrawingCacheBackgroundColor();
316         v.setDrawingCacheBackgroundColor(0);
317         float alpha = v.getAlpha();
318         v.setAlpha(1.0f);
319 
320         if (color != 0) {
321             v.destroyDrawingCache();
322         }
323         v.buildDrawingCache();
324         Bitmap cacheBitmap = v.getDrawingCache();
325         if (cacheBitmap == null) {
326             Log.e(TAG, "failed getViewBitmap(" + v + ")", new RuntimeException());
327             return null;
328         }
329 
330         Bitmap bitmap = Bitmap.createBitmap(cacheBitmap);
331 
332         // Restore the view
333         v.destroyDrawingCache();
334         v.setAlpha(alpha);
335         v.setWillNotCacheDrawing(willNotCache);
336         v.setDrawingCacheBackgroundColor(color);
337 
338         return bitmap;
339     }
340 
341     /**
342      * Call this from a drag source view like this:
343      *
344      * <pre>
345      *  @Override
346      *  public boolean dispatchKeyEvent(KeyEvent event) {
347      *      return mDragController.dispatchKeyEvent(this, event)
348      *              || super.dispatchKeyEvent(event);
349      * </pre>
350      */
351     @SuppressWarnings({"UnusedDeclaration"})
dispatchKeyEvent(KeyEvent event)352     public boolean dispatchKeyEvent(KeyEvent event) {
353         return mDragging;
354     }
355 
isDragging()356     public boolean isDragging() {
357         return mDragging;
358     }
359 
360     /**
361      * Stop dragging without dropping.
362      */
cancelDrag()363     public void cancelDrag() {
364         if (mDragging) {
365             if (mLastDropTarget != null) {
366                 mLastDropTarget.onDragExit(mDragObject);
367             }
368             mDragObject.cancelled = true;
369             mDragObject.dragComplete = true;
370             mDragObject.dragSource.onDropCompleted(null, mDragObject, false);
371         }
372         endDrag();
373     }
onAppsRemoved(ArrayList<ApplicationInfo> apps, Context context)374     public void onAppsRemoved(ArrayList<ApplicationInfo> apps, Context context) {
375         // Cancel the current drag if we are removing an app that we are dragging
376         if (mDragObject != null) {
377             Object rawDragInfo = mDragObject.dragInfo;
378             if (rawDragInfo instanceof ShortcutInfo) {
379                 ShortcutInfo dragInfo = (ShortcutInfo) rawDragInfo;
380                 for (ApplicationInfo info : apps) {
381                     if (dragInfo.intent.getComponent().equals(info.intent.getComponent())) {
382                         cancelDrag();
383                         return;
384                     }
385                 }
386             }
387         }
388     }
389 
endDrag()390     private void endDrag() {
391         if (mDragging) {
392             mDragging = false;
393             for (DragListener listener : mListeners) {
394                 listener.onDragEnd();
395             }
396             if (mDragObject.dragView != null) {
397                 mDragObject.dragView.remove();
398                 mDragObject.dragView = null;
399             }
400         }
401     }
402 
403     /**
404      * Clamps the position to the drag layer bounds.
405      */
getClampedDragLayerPos(float x, float y)406     private int[] getClampedDragLayerPos(float x, float y) {
407         mLauncher.getDragLayer().getLocalVisibleRect(mDragLayerRect);
408         mTmpPoint[0] = (int) Math.max(mDragLayerRect.left, Math.min(x, mDragLayerRect.right - 1));
409         mTmpPoint[1] = (int) Math.max(mDragLayerRect.top, Math.min(y, mDragLayerRect.bottom - 1));
410         return mTmpPoint;
411     }
412 
413     /**
414      * Call this from a drag source view.
415      */
onInterceptTouchEvent(MotionEvent ev)416     public boolean onInterceptTouchEvent(MotionEvent ev) {
417         if (false) {
418             Log.d(Launcher.TAG, "DragController.onInterceptTouchEvent " + ev + " mDragging="
419                     + mDragging);
420         }
421         final int action = ev.getAction();
422 
423         final int[] dragLayerPos = getClampedDragLayerPos(ev.getX(), ev.getY());
424         final int dragLayerX = dragLayerPos[0];
425         final int dragLayerY = dragLayerPos[1];
426 
427         switch (action) {
428             case MotionEvent.ACTION_MOVE:
429                 break;
430             case MotionEvent.ACTION_DOWN:
431                 // Remember location of down touch
432                 mMotionDownX = dragLayerX;
433                 mMotionDownY = dragLayerY;
434                 mLastDropTarget = null;
435                 break;
436             case MotionEvent.ACTION_UP:
437                 if (mDragging) {
438                     drop(dragLayerX, dragLayerY);
439                 }
440                 endDrag();
441                 break;
442             case MotionEvent.ACTION_CANCEL:
443                 cancelDrag();
444                 break;
445         }
446 
447         return mDragging;
448     }
449 
450     /**
451      * Sets the view that should handle move events.
452      */
setMoveTarget(View view)453     void setMoveTarget(View view) {
454         mMoveTarget = view;
455     }
456 
dispatchUnhandledMove(View focused, int direction)457     public boolean dispatchUnhandledMove(View focused, int direction) {
458         return mMoveTarget != null && mMoveTarget.dispatchUnhandledMove(focused, direction);
459     }
460 
handleMoveEvent(int x, int y)461     private void handleMoveEvent(int x, int y) {
462         mDragObject.dragView.move(x, y);
463 
464         // Drop on someone?
465         final int[] coordinates = mCoordinatesTemp;
466         DropTarget dropTarget = findDropTarget(x, y, coordinates);
467         mDragObject.x = coordinates[0];
468         mDragObject.y = coordinates[1];
469         if (dropTarget != null) {
470             DropTarget delegate = dropTarget.getDropTargetDelegate(mDragObject);
471             if (delegate != null) {
472                 dropTarget = delegate;
473             }
474 
475             if (mLastDropTarget != dropTarget) {
476                 if (mLastDropTarget != null) {
477                     mLastDropTarget.onDragExit(mDragObject);
478                 }
479                 dropTarget.onDragEnter(mDragObject);
480             }
481             dropTarget.onDragOver(mDragObject);
482         } else {
483             if (mLastDropTarget != null) {
484                 mLastDropTarget.onDragExit(mDragObject);
485             }
486         }
487         mLastDropTarget = dropTarget;
488 
489         // Scroll, maybe, but not if we're in the delete region.
490         boolean inDeleteRegion = false;
491         if (mDeleteRegion != null) {
492             inDeleteRegion = mDeleteRegion.contains(x, y);
493         }
494 
495         // After a scroll, the touch point will still be in the scroll region.
496         // Rather than scrolling immediately, require a bit of twiddling to scroll again
497         final int slop = ViewConfiguration.get(mLauncher).getScaledWindowTouchSlop();
498         mDistanceSinceScroll +=
499             Math.sqrt(Math.pow(mLastTouch[0] - x, 2) + Math.pow(mLastTouch[1] - y, 2));
500         mLastTouch[0] = x;
501         mLastTouch[1] = y;
502 
503         if (!inDeleteRegion && x < mScrollZone) {
504             if (mScrollState == SCROLL_OUTSIDE_ZONE && mDistanceSinceScroll > slop) {
505                 mScrollState = SCROLL_WAITING_IN_ZONE;
506                 if (mDragScroller.onEnterScrollArea(x, y, SCROLL_LEFT)) {
507                     mScrollRunnable.setDirection(SCROLL_LEFT);
508                     mHandler.postDelayed(mScrollRunnable, SCROLL_DELAY);
509                 }
510             }
511         } else if (!inDeleteRegion && x > mScrollView.getWidth() - mScrollZone) {
512             if (mScrollState == SCROLL_OUTSIDE_ZONE && mDistanceSinceScroll > slop) {
513                 mScrollState = SCROLL_WAITING_IN_ZONE;
514                 if (mDragScroller.onEnterScrollArea(x, y, SCROLL_RIGHT)) {
515                     mScrollRunnable.setDirection(SCROLL_RIGHT);
516                     mHandler.postDelayed(mScrollRunnable, SCROLL_DELAY);
517                 }
518             }
519         } else {
520             if (mScrollState == SCROLL_WAITING_IN_ZONE) {
521                 mScrollState = SCROLL_OUTSIDE_ZONE;
522                 mScrollRunnable.setDirection(SCROLL_RIGHT);
523                 mHandler.removeCallbacks(mScrollRunnable);
524                 mDragScroller.onExitScrollArea();
525             }
526         }
527     }
528 
529     /**
530      * Call this from a drag source view.
531      */
onTouchEvent(MotionEvent ev)532     public boolean onTouchEvent(MotionEvent ev) {
533         if (!mDragging) {
534             return false;
535         }
536 
537         final int action = ev.getAction();
538         final int[] dragLayerPos = getClampedDragLayerPos(ev.getX(), ev.getY());
539         final int dragLayerX = dragLayerPos[0];
540         final int dragLayerY = dragLayerPos[1];
541 
542         switch (action) {
543         case MotionEvent.ACTION_DOWN:
544             // Remember where the motion event started
545             mMotionDownX = dragLayerX;
546             mMotionDownY = dragLayerY;
547 
548             if ((dragLayerX < mScrollZone) || (dragLayerX > mScrollView.getWidth() - mScrollZone)) {
549                 mScrollState = SCROLL_WAITING_IN_ZONE;
550                 mHandler.postDelayed(mScrollRunnable, SCROLL_DELAY);
551             } else {
552                 mScrollState = SCROLL_OUTSIDE_ZONE;
553             }
554             break;
555         case MotionEvent.ACTION_MOVE:
556             handleMoveEvent(dragLayerX, dragLayerY);
557             break;
558         case MotionEvent.ACTION_UP:
559             // Ensure that we've processed a move event at the current pointer location.
560             handleMoveEvent(dragLayerX, dragLayerY);
561 
562             mHandler.removeCallbacks(mScrollRunnable);
563             if (mDragging) {
564                 drop(dragLayerX, dragLayerY);
565             }
566             endDrag();
567             break;
568         case MotionEvent.ACTION_CANCEL:
569             cancelDrag();
570             break;
571         }
572 
573         return true;
574     }
575 
drop(float x, float y)576     private void drop(float x, float y) {
577         final int[] coordinates = mCoordinatesTemp;
578         final DropTarget dropTarget = findDropTarget((int) x, (int) y, coordinates);
579 
580         mDragObject.x = coordinates[0];
581         mDragObject.y = coordinates[1];
582         boolean accepted = false;
583         if (dropTarget != null) {
584             mDragObject.dragComplete = true;
585             dropTarget.onDragExit(mDragObject);
586             if (dropTarget.acceptDrop(mDragObject)) {
587                 dropTarget.onDrop(mDragObject);
588                 accepted = true;
589             }
590         }
591         mDragObject.dragSource.onDropCompleted((View) dropTarget, mDragObject, accepted);
592     }
593 
findDropTarget(int x, int y, int[] dropCoordinates)594     private DropTarget findDropTarget(int x, int y, int[] dropCoordinates) {
595         final Rect r = mRectTemp;
596 
597         final ArrayList<DropTarget> dropTargets = mDropTargets;
598         final int count = dropTargets.size();
599         for (int i=count-1; i>=0; i--) {
600             DropTarget target = dropTargets.get(i);
601             if (!target.isDropEnabled())
602                 continue;
603 
604             target.getHitRect(r);
605 
606             // Convert the hit rect to DragLayer coordinates
607             target.getLocationInDragLayer(dropCoordinates);
608             r.offset(dropCoordinates[0] - target.getLeft(), dropCoordinates[1] - target.getTop());
609 
610             mDragObject.x = x;
611             mDragObject.y = y;
612             if (r.contains(x, y)) {
613                 DropTarget delegate = target.getDropTargetDelegate(mDragObject);
614                 if (delegate != null) {
615                     target = delegate;
616                     target.getLocationInDragLayer(dropCoordinates);
617                 }
618 
619                 // Make dropCoordinates relative to the DropTarget
620                 dropCoordinates[0] = x - dropCoordinates[0];
621                 dropCoordinates[1] = y - dropCoordinates[1];
622 
623                 return target;
624             }
625         }
626         return null;
627     }
628 
setDragScoller(DragScroller scroller)629     public void setDragScoller(DragScroller scroller) {
630         mDragScroller = scroller;
631     }
632 
setWindowToken(IBinder token)633     public void setWindowToken(IBinder token) {
634         mWindowToken = token;
635     }
636 
637     /**
638      * Sets the drag listner which will be notified when a drag starts or ends.
639      */
addDragListener(DragListener l)640     public void addDragListener(DragListener l) {
641         mListeners.add(l);
642     }
643 
644     /**
645      * Remove a previously installed drag listener.
646      */
removeDragListener(DragListener l)647     public void removeDragListener(DragListener l) {
648         mListeners.remove(l);
649     }
650 
651     /**
652      * Add a DropTarget to the list of potential places to receive drop events.
653      */
addDropTarget(DropTarget target)654     public void addDropTarget(DropTarget target) {
655         mDropTargets.add(target);
656     }
657 
658     /**
659      * Don't send drop events to <em>target</em> any more.
660      */
removeDropTarget(DropTarget target)661     public void removeDropTarget(DropTarget target) {
662         mDropTargets.remove(target);
663     }
664 
665     /**
666      * Set which view scrolls for touch events near the edge of the screen.
667      */
setScrollView(View v)668     public void setScrollView(View v) {
669         mScrollView = v;
670     }
671 
672     /**
673      * Specifies the delete region.  We won't scroll on touch events over the delete region.
674      *
675      * @param region The rectangle in DragLayer coordinates of the delete region.
676      */
setDeleteRegion(RectF region)677     void setDeleteRegion(RectF region) {
678         mDeleteRegion = region;
679     }
680 
getDragView()681     DragView getDragView() {
682         return mDragObject.dragView;
683     }
684 
685     private class ScrollRunnable implements Runnable {
686         private int mDirection;
687 
ScrollRunnable()688         ScrollRunnable() {
689         }
690 
run()691         public void run() {
692             if (mDragScroller != null) {
693                 if (mDirection == SCROLL_LEFT) {
694                     mDragScroller.scrollLeft();
695                 } else {
696                     mDragScroller.scrollRight();
697                 }
698                 mScrollState = SCROLL_OUTSIDE_ZONE;
699                 mDistanceSinceScroll = 0;
700                 mDragScroller.onExitScrollArea();
701             }
702         }
703 
setDirection(int direction)704         void setDirection(int direction) {
705             mDirection = direction;
706         }
707     }
708 }
709