diff options
author | Winson Chung <winsonc@google.com> | 2012-03-01 16:09:54 -0800 |
---|---|---|
committer | Winson Chung <winsonc@google.com> | 2012-03-20 15:18:05 -0700 |
commit | 043f2af567178b82b0b41f12d379e7dd12da2936 (patch) | |
tree | fc097bc1c6baeee546d3683a2b8ecb05976e2370 /src/com/android/launcher2/DragController.java | |
parent | d1eef3388a518696521ec8d67022c0bf09eef796 (diff) | |
download | android_packages_apps_Trebuchet-043f2af567178b82b0b41f12d379e7dd12da2936.tar.gz android_packages_apps_Trebuchet-043f2af567178b82b0b41f12d379e7dd12da2936.tar.bz2 android_packages_apps_Trebuchet-043f2af567178b82b0b41f12d379e7dd12da2936.zip |
Adding fling-to-delete.
- Also fixing issue where the drop target icon changes color slower than the text.
Change-Id: I0bfa59da5d202016342f1c3de419ebcafd81ff6f
Diffstat (limited to 'src/com/android/launcher2/DragController.java')
-rw-r--r-- | src/com/android/launcher2/DragController.java | 139 |
1 files changed, 130 insertions, 9 deletions
diff --git a/src/com/android/launcher2/DragController.java b/src/com/android/launcher2/DragController.java index 019a749f2..2a889257d 100644 --- a/src/com/android/launcher2/DragController.java +++ b/src/com/android/launcher2/DragController.java @@ -19,6 +19,7 @@ package com.android.launcher2; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Point; +import android.graphics.PointF; import android.graphics.Rect; import android.os.Handler; import android.os.IBinder; @@ -26,6 +27,7 @@ import android.os.Vibrator; import android.util.Log; import android.view.KeyEvent; import android.view.MotionEvent; +import android.view.VelocityTracker; import android.view.View; import android.view.ViewConfiguration; import android.view.inputmethod.InputMethodManager; @@ -60,6 +62,9 @@ public class DragController { static final int SCROLL_LEFT = 0; static final int SCROLL_RIGHT = 1; + private static final float MAX_FLING_DEGREES = 35f; + private static final int FLING_TO_DELETE_THRESHOLD_Y_VELOCITY = -1400; + private Launcher mLauncher; private Handler mHandler; private final Vibrator mVibrator = new Vibrator(); @@ -86,8 +91,8 @@ public class DragController { /** Who can receive drop events */ private ArrayList<DropTarget> mDropTargets = new ArrayList<DropTarget>(); - private ArrayList<DragListener> mListeners = new ArrayList<DragListener>(); + private DropTarget mFlingToDeleteDropTarget; /** The window token used as the parent for the DragView. */ private IBinder mWindowToken; @@ -111,6 +116,9 @@ public class DragController { private int mTmpPoint[] = new int[2]; private Rect mDragLayerRect = new Rect(); + protected int mFlingToDeleteThresholdVelocity; + private VelocityTracker mVelocityTracker; + /** * Interface to receive notifications when a drag starts or stops */ @@ -141,6 +149,10 @@ public class DragController { mLauncher = launcher; mHandler = new Handler(); mScrollZone = launcher.getResources().getDimensionPixelSize(R.dimen.scroll_zone); + mVelocityTracker = VelocityTracker.obtain(); + + float density = launcher.getResources().getDisplayMetrics().density; + mFlingToDeleteThresholdVelocity = (int) (FLING_TO_DELETE_THRESHOLD_Y_VELOCITY * density); } public boolean dragging() { @@ -378,15 +390,35 @@ public class DragController { if (mDragging) { mDragging = false; clearScrollRunnable(); - for (DragListener listener : mListeners) { - listener.onDragEnd(); - } + boolean isDeferred = false; if (mDragObject.dragView != null) { - if (!mDragObject.deferDragViewCleanupPostAnimation) { + isDeferred = mDragObject.deferDragViewCleanupPostAnimation; + if (!isDeferred) { mDragObject.dragView.remove(); } mDragObject.dragView = null; } + + // Only end the drag if we are not deferred + if (!isDeferred) { + for (DragListener listener : mListeners) { + listener.onDragEnd(); + } + } + } + + releaseVelocityTracker(); + } + + /** + * This only gets called as a result of drag view cleanup being deferred in endDrag(); + */ + void onDeferredEndDrag(DragView dragView) { + dragView.remove(); + + // If we skipped calling onDragEnd() before, do it now + for (DragListener listener : mListeners) { + listener.onDragEnd(); } } @@ -408,8 +440,11 @@ public class DragController { Log.d(Launcher.TAG, "DragController.onInterceptTouchEvent " + ev + " mDragging=" + mDragging); } - final int action = ev.getAction(); + // Update the velocity tracker + acquireVelocityTrackerAndAddMovement(ev); + + final int action = ev.getAction(); final int[] dragLayerPos = getClampedDragLayerPos(ev.getX(), ev.getY()); final int dragLayerX = dragLayerPos[0]; final int dragLayerY = dragLayerPos[1]; @@ -425,7 +460,12 @@ public class DragController { break; case MotionEvent.ACTION_UP: if (mDragging) { - drop(dragLayerX, dragLayerY); + PointF vec = isFlingingToDelete(mDragObject.dragSource); + if (vec != null) { + dropOnFlingToDeleteTarget(dragLayerX, dragLayerY, vec); + } else { + drop(dragLayerX, dragLayerY); + } } endDrag(); break; @@ -529,6 +569,9 @@ public class DragController { return false; } + // Update the velocity tracker + acquireVelocityTrackerAndAddMovement(ev); + final int action = ev.getAction(); final int[] dragLayerPos = getClampedDragLayerPos(ev.getX(), ev.getY()); final int dragLayerX = dragLayerPos[0]; @@ -553,10 +596,15 @@ public class DragController { case MotionEvent.ACTION_UP: // Ensure that we've processed a move event at the current pointer location. handleMoveEvent(dragLayerX, dragLayerY); - mHandler.removeCallbacks(mScrollRunnable); + if (mDragging) { - drop(dragLayerX, dragLayerY); + PointF vec = isFlingingToDelete(mDragObject.dragSource); + if (vec != null) { + dropOnFlingToDeleteTarget(dragLayerX, dragLayerY, vec); + } else { + drop(dragLayerX, dragLayerY); + } } endDrag(); break; @@ -569,6 +617,58 @@ public class DragController { return true; } + /** + * Determines whether the user flung the current item to delete it. + * + * @return the vector at which the item was flung, or null if no fling was detected. + */ + private PointF isFlingingToDelete(DragSource source) { + if (mFlingToDeleteDropTarget == null) return null; + if (!source.supportsFlingToDelete()) return null; + + ViewConfiguration config = ViewConfiguration.get(mLauncher); + mVelocityTracker.computeCurrentVelocity(1000, config.getScaledMaximumFlingVelocity()); + + if (mVelocityTracker.getYVelocity() < mFlingToDeleteThresholdVelocity) { + // Do a quick dot product test to ensure that we are flinging upwards + PointF vel = new PointF(mVelocityTracker.getXVelocity(), + mVelocityTracker.getYVelocity()); + PointF upVec = new PointF(0f, -1f); + float theta = (float) Math.acos(((vel.x * upVec.x) + (vel.y * upVec.y)) / + (vel.length() * upVec.length())); + if (theta <= Math.toRadians(MAX_FLING_DEGREES)) { + return vel; + } + } + return null; + } + + private void dropOnFlingToDeleteTarget(float x, float y, PointF vel) { + final int[] coordinates = mCoordinatesTemp; + + mDragObject.x = coordinates[0]; + mDragObject.y = coordinates[1]; + mDragObject.dragComplete = true; + + // Clean up dragging on the target if it's not the current fling delete target otherwise, + // start dragging to it. + if (mLastDropTarget != null && mFlingToDeleteDropTarget != mLastDropTarget) { + mLastDropTarget.onDragExit(mDragObject); + } + + // Drop onto the fling-to-delete target + boolean accepted = false; + mFlingToDeleteDropTarget.onDragEnter(mDragObject); + mFlingToDeleteDropTarget.onDragExit(mDragObject); + if (mFlingToDeleteDropTarget.acceptDrop(mDragObject)) { + mFlingToDeleteDropTarget.onFlingToDelete(mDragObject, mDragObject.x, mDragObject.y, + vel); + accepted = true; + } + mDragObject.dragSource.onDropCompleted((View) mFlingToDeleteDropTarget, mDragObject, + accepted); + } + private void drop(float x, float y) { final int[] coordinates = mCoordinatesTemp; final DropTarget dropTarget = findDropTarget((int) x, (int) y, coordinates); @@ -659,6 +759,27 @@ public class DragController { } /** + * Sets the current fling-to-delete drop target. + */ + public void setFlingToDeleteDropTarget(DropTarget target) { + mFlingToDeleteDropTarget = target; + } + + private void acquireVelocityTrackerAndAddMovement(MotionEvent ev) { + if (mVelocityTracker == null) { + mVelocityTracker = VelocityTracker.obtain(); + } + mVelocityTracker.addMovement(ev); + } + + private void releaseVelocityTracker() { + if (mVelocityTracker != null) { + mVelocityTracker.recycle(); + mVelocityTracker = null; + } + } + + /** * Set which view scrolls for touch events near the edge of the screen. */ public void setScrollView(View v) { |