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