diff options
author | Winson Chung <winsonc@google.com> | 2012-03-20 15:22:41 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2012-03-20 15:22:41 -0700 |
commit | cf4b91fa3f4d2c6b4bce5f6cf177979ea9ca7aad (patch) | |
tree | 8b3d92a9e42874bc0d170249f64bbcf06f076fb6 /src | |
parent | 47a876d443ddc65c8d9a0c95da58d892dbb1faea (diff) | |
parent | 043f2af567178b82b0b41f12d379e7dd12da2936 (diff) | |
download | android_packages_apps_Trebuchet-cf4b91fa3f4d2c6b4bce5f6cf177979ea9ca7aad.tar.gz android_packages_apps_Trebuchet-cf4b91fa3f4d2c6b4bce5f6cf177979ea9ca7aad.tar.bz2 android_packages_apps_Trebuchet-cf4b91fa3f4d2c6b4bce5f6cf177979ea9ca7aad.zip |
Merge "Adding fling-to-delete."
Diffstat (limited to 'src')
-rw-r--r-- | src/com/android/launcher2/AppsCustomizePagedView.java | 4 | ||||
-rw-r--r-- | src/com/android/launcher2/ButtonDropTarget.java | 6 | ||||
-rw-r--r-- | src/com/android/launcher2/DeleteDropTarget.java | 184 | ||||
-rw-r--r-- | src/com/android/launcher2/DragController.java | 139 | ||||
-rw-r--r-- | src/com/android/launcher2/DragLayer.java | 71 | ||||
-rw-r--r-- | src/com/android/launcher2/DragSource.java | 1 | ||||
-rw-r--r-- | src/com/android/launcher2/DragView.java | 18 | ||||
-rw-r--r-- | src/com/android/launcher2/DropTarget.java | 8 | ||||
-rw-r--r-- | src/com/android/launcher2/Folder.java | 10 | ||||
-rw-r--r-- | src/com/android/launcher2/SearchDropTargetBar.java | 8 | ||||
-rw-r--r-- | src/com/android/launcher2/Workspace.java | 9 |
11 files changed, 415 insertions, 43 deletions
diff --git a/src/com/android/launcher2/AppsCustomizePagedView.java b/src/com/android/launcher2/AppsCustomizePagedView.java index 3fcff726f..a7ff3095c 100644 --- a/src/com/android/launcher2/AppsCustomizePagedView.java +++ b/src/com/android/launcher2/AppsCustomizePagedView.java @@ -760,6 +760,10 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen mDraggingWidget = false; } + public boolean supportsFlingToDelete() { + return false; + } + @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); diff --git a/src/com/android/launcher2/ButtonDropTarget.java b/src/com/android/launcher2/ButtonDropTarget.java index dc34d8828..e9f8ce8b5 100644 --- a/src/com/android/launcher2/ButtonDropTarget.java +++ b/src/com/android/launcher2/ButtonDropTarget.java @@ -18,7 +18,7 @@ package com.android.launcher2; import android.content.Context; import android.content.res.Resources; -import android.graphics.Paint; +import android.graphics.PointF; import android.graphics.Rect; import android.util.AttributeSet; import android.widget.TextView; @@ -71,6 +71,10 @@ public class ButtonDropTarget extends TextView implements DropTarget, DragContro public void onDrop(DragObject d) { } + public void onFlingToDelete(DragObject d, int x, int y, PointF vec) { + // Do nothing + } + public void onDragEnter(DragObject d) { d.dragView.setColor(mHoverColor); } diff --git a/src/com/android/launcher2/DeleteDropTarget.java b/src/com/android/launcher2/DeleteDropTarget.java index 4621dea85..6f455905f 100644 --- a/src/com/android/launcher2/DeleteDropTarget.java +++ b/src/com/android/launcher2/DeleteDropTarget.java @@ -16,24 +16,33 @@ package com.android.launcher2; +import android.animation.TimeInterpolator; +import android.animation.ValueAnimator; +import android.animation.ValueAnimator.AnimatorUpdateListener; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.Configuration; import android.content.res.Resources; +import android.graphics.PointF; import android.graphics.Rect; import android.graphics.drawable.TransitionDrawable; import android.util.AttributeSet; import android.view.View; +import android.view.ViewConfiguration; import android.view.ViewGroup; -import android.view.animation.AccelerateInterpolator; +import android.view.animation.AnimationUtils; import android.view.animation.DecelerateInterpolator; import android.view.animation.LinearInterpolator; import com.android.launcher.R; public class DeleteDropTarget extends ButtonDropTarget { + private static int DELETE_ANIMATION_DURATION = 285; + private static int MODE_FLING_DELETE_TO_TRASH = 0; + private static int MODE_FLING_DELETE_ALONG_VECTOR = 1; + + private final int mFlingDeleteMode = MODE_FLING_DELETE_ALONG_VECTOR; - private static int DELETE_ANIMATION_DURATION = 300; private ColorStateList mOriginalTextColor; private TransitionDrawable mUninstallDrawable; private TransitionDrawable mRemoveDrawable; @@ -223,4 +232,175 @@ public class DeleteDropTarget extends ButtonDropTarget { public void onDrop(DragObject d) { animateToTrashAndCompleteDrop(d); } + + /** + * Creates an animation from the current drag view to the delete trash icon. + */ + private AnimatorUpdateListener createFlingToTrashAnimatorListener(final DragLayer dragLayer, + DragObject d, PointF vel, ViewConfiguration config) { + final Rect to = getIconRect(d.dragView.getMeasuredWidth(), d.dragView.getMeasuredHeight(), + mCurrentDrawable.getIntrinsicWidth(), mCurrentDrawable.getIntrinsicHeight()); + final Rect from = new Rect(); + dragLayer.getViewRectRelativeToSelf(d.dragView, from); + + // Calculate how far along the velocity vector we should put the intermediate point on + // the bezier curve + float velocity = Math.abs(vel.length()); + float vp = Math.min(1f, velocity / (config.getScaledMaximumFlingVelocity() / 2f)); + int offsetY = (int) (-from.top * vp); + int offsetX = (int) (offsetY / (vel.y / vel.x)); + final float y2 = from.top + offsetY; // intermediate t/l + final float x2 = from.left + offsetX; + final float x1 = from.left; // drag view t/l + final float y1 = from.top; + final float x3 = to.left; // delete target t/l + final float y3 = to.top; + + final TimeInterpolator scaleAlphaInterpolator = new TimeInterpolator() { + @Override + public float getInterpolation(float t) { + return t * t * t * t * t * t * t * t; + } + }; + return new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + final DragView dragView = (DragView) dragLayer.getAnimatedView(); + float t = ((Float) animation.getAnimatedValue()).floatValue(); + float tp = scaleAlphaInterpolator.getInterpolation(t); + float initialScale = dragView.getInitialScale(); + float finalAlpha = 0.5f; + float scale = dragView.getScaleX(); + float x1o = ((1f - scale) * dragView.getMeasuredWidth()) / 2f; + float y1o = ((1f - scale) * dragView.getMeasuredHeight()) / 2f; + float x = (1f - t) * (1f - t) * (x1 - x1o) + 2 * (1f - t) * t * (x2 - x1o) + + (t * t) * x3; + float y = (1f - t) * (1f - t) * (y1 - y1o) + 2 * (1f - t) * t * (y2 - x1o) + + (t * t) * y3; + + dragView.setTranslationX(x); + dragView.setTranslationY(y); + dragView.setScaleX(initialScale * (1f - tp)); + dragView.setScaleY(initialScale * (1f - tp)); + dragView.setAlpha(finalAlpha + (1f - finalAlpha) * (1f - tp)); + } + }; + } + + /** + * Creates an animation from the current drag view along its current velocity vector. + * For this animation, the alpha runs for a fixed duration and we update the position + * progressively. + */ + private static class FlingAlongVectorAnimatorUpdateListener implements AnimatorUpdateListener { + private static float FRICTION = 0.93f; + + private DragLayer mDragLayer; + private PointF mVelocity; + private Rect mFrom; + private long mPrevTime; + private boolean mHasOffsetForScale; + + private final TimeInterpolator mAlphaInterpolator = new DecelerateInterpolator(1.5f); + + public FlingAlongVectorAnimatorUpdateListener(DragLayer dragLayer, PointF vel, Rect from, + long startTime) { + mDragLayer = dragLayer; + mVelocity = vel; + mFrom = from; + mPrevTime = startTime; + } + + @Override + public void onAnimationUpdate(ValueAnimator animation) { + final DragView dragView = (DragView) mDragLayer.getAnimatedView(); + float t = ((Float) animation.getAnimatedValue()).floatValue(); + long curTime = AnimationUtils.currentAnimationTimeMillis(); + + if (!mHasOffsetForScale) { + mHasOffsetForScale = true; + float scale = dragView.getScaleX(); + float xOffset = ((scale - 1f) * dragView.getMeasuredWidth()) / 2f; + float yOffset = ((scale - 1f) * dragView.getMeasuredHeight()) / 2f; + + mFrom.left += xOffset; + mFrom.top += yOffset; + } + + mFrom.left += (mVelocity.x * (curTime - mPrevTime) / 1000f); + mFrom.top += (mVelocity.y * (curTime - mPrevTime) / 1000f); + + dragView.setTranslationX(mFrom.left); + dragView.setTranslationY(mFrom.top); + dragView.setAlpha(1f - mAlphaInterpolator.getInterpolation(t)); + + mVelocity.x *= FRICTION; + mVelocity.y *= FRICTION; + mPrevTime = curTime; + } + }; + private AnimatorUpdateListener createFlingAlongVectorAnimatorListener(final DragLayer dragLayer, + DragObject d, PointF vel, final long startTime, final int duration, + ViewConfiguration config) { + final Rect from = new Rect(); + dragLayer.getViewRectRelativeToSelf(d.dragView, from); + + return new FlingAlongVectorAnimatorUpdateListener(dragLayer, vel, from, startTime); + } + + public void onFlingToDelete(final DragObject d, int x, int y, PointF vel) { + // Don't highlight the icon as it's animating + d.dragView.setColor(0); + d.dragView.updateInitialScaleToCurrentScale(); + + if (mFlingDeleteMode == MODE_FLING_DELETE_TO_TRASH) { + // Defer animating out the drop target if we are animating to it + mSearchDropTargetBar.deferOnDragEnd(); + mSearchDropTargetBar.finishAnimations(); + } + + final ViewConfiguration config = ViewConfiguration.get(mLauncher); + final DragLayer dragLayer = mLauncher.getDragLayer(); + final int duration = DELETE_ANIMATION_DURATION; + final long startTime = AnimationUtils.currentAnimationTimeMillis(); + + // NOTE: Because it takes time for the first frame of animation to actually be + // called and we expect the animation to be a continuation of the fling, we have + // to account for the time that has elapsed since the fling finished. And since + // we don't have a startDelay, we will always get call to update when we call + // start() (which we want to ignore). + final TimeInterpolator tInterpolator = new TimeInterpolator() { + private int mCount = -1; + private float mOffset = 0f; + + @Override + public float getInterpolation(float t) { + if (mCount < 0) { + mCount++; + } else if (mCount == 0) { + mOffset = Math.min(0.5f, (float) (AnimationUtils.currentAnimationTimeMillis() - + startTime) / duration); + mCount++; + } + return Math.min(1f, mOffset + t); + } + }; + AnimatorUpdateListener updateCb = null; + if (mFlingDeleteMode == MODE_FLING_DELETE_TO_TRASH) { + updateCb = createFlingToTrashAnimatorListener(dragLayer, d, vel, config); + } else if (mFlingDeleteMode == MODE_FLING_DELETE_ALONG_VECTOR) { + updateCb = createFlingAlongVectorAnimatorListener(dragLayer, d, vel, startTime, + duration, config); + } + Runnable onAnimationEndRunnable = new Runnable() { + @Override + public void run() { + mSearchDropTargetBar.onDragEnd(); + mLauncher.exitSpringLoadedDragMode(); + completeDrop(d); + } + }; + dragLayer.animateView(d.dragView, updateCb, duration, tInterpolator, onAnimationEndRunnable, + DragLayer.ANIMATION_END_DISAPPEAR, null); + } } 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) { diff --git a/src/com/android/launcher2/DragLayer.java b/src/com/android/launcher2/DragLayer.java index ce5c8c517..4754235ef 100644 --- a/src/com/android/launcher2/DragLayer.java +++ b/src/com/android/launcher2/DragLayer.java @@ -18,15 +18,15 @@ package com.android.launcher2; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; -import android.animation.ObjectAnimator; import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import android.animation.ValueAnimator.AnimatorUpdateListener; import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PointF; import android.graphics.Rect; -import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.MotionEvent; @@ -34,6 +34,7 @@ import android.view.View; import android.view.ViewParent; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; +import android.view.animation.AnimationUtils; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; import android.widget.FrameLayout; @@ -542,35 +543,17 @@ public class DragLayer extends FrameLayout { duration = Math.max(duration, res.getInteger(R.integer.config_dropAnimMinDuration)); } - if (mDropAnim != null) { - mDropAnim.cancel(); - } - - if (mFadeOutAnim != null) { - mFadeOutAnim.cancel(); - } - - // Show the drop view if it was previously hidden - mDropView = view; - mDropView.cancelAnimation(); - mDropView.resetLayoutParams(); - mDropAnim = new ValueAnimator(); + // Fall back to cubic ease out interpolator for the animation if none is specified + TimeInterpolator interpolator = null; if (alphaInterpolator == null || motionInterpolator == null) { - mDropAnim.setInterpolator(mCubicEaseOutInterpolator); + interpolator = mCubicEaseOutInterpolator; } - if (anchorView != null) { - mAnchorViewInitialScrollX = anchorView.getScrollX(); - } - mAnchorView = anchorView; - + // Animate the view final float initAlpha = view.getAlpha(); - final float dropViewScale = mDropView.getScaleX(); - - mDropAnim.setDuration(duration); - mDropAnim.setFloatValues(0.0f, 1.0f); - mDropAnim.removeAllUpdateListeners(); - mDropAnim.addUpdateListener(new AnimatorUpdateListener() { + final float dropViewScale = view.getScaleX(); + AnimatorUpdateListener updateCb = new AnimatorUpdateListener() { + @Override public void onAnimationUpdate(ValueAnimator animation) { final float percent = (Float) animation.getAnimatedValue(); final int width = view.getMeasuredWidth(); @@ -603,7 +586,35 @@ public class DragLayer extends FrameLayout { mDropView.setScaleY(scaleY); mDropView.setAlpha(alpha); } - }); + }; + animateView(view, updateCb, duration, interpolator, onCompleteRunnable, animationEndStyle, + anchorView); + } + + public void animateView(final DragView view, AnimatorUpdateListener updateCb, int duration, + TimeInterpolator interpolator, final Runnable onCompleteRunnable, + final int animationEndStyle, View anchorView) { + // Clean up the previous animations + if (mDropAnim != null) mDropAnim.cancel(); + if (mFadeOutAnim != null) mFadeOutAnim.cancel(); + + // Show the drop view if it was previously hidden + mDropView = view; + mDropView.cancelAnimation(); + mDropView.resetLayoutParams(); + + // Set the anchor view if the page is scrolling + if (anchorView != null) { + mAnchorViewInitialScrollX = anchorView.getScrollX(); + } + mAnchorView = anchorView; + + // Create and start the animation + mDropAnim = new ValueAnimator(); + mDropAnim.setInterpolator(interpolator); + mDropAnim.setDuration(duration); + mDropAnim.setFloatValues(0f, 1f); + mDropAnim.addUpdateListener(updateCb); mDropAnim.addListener(new AnimatorListenerAdapter() { public void onAnimationEnd(Animator animation) { if (onCompleteRunnable != null) { @@ -629,7 +640,7 @@ public class DragLayer extends FrameLayout { mDropAnim.cancel(); } if (mDropView != null) { - mDropView.remove(); + mDragController.onDeferredEndDrag(mDropView); } mDropView = null; invalidate(); @@ -655,7 +666,7 @@ public class DragLayer extends FrameLayout { mFadeOutAnim.addListener(new AnimatorListenerAdapter() { public void onAnimationEnd(Animator animation) { if (mDropView != null) { - mDropView.remove(); + mDragController.onDeferredEndDrag(mDropView); } mDropView = null; invalidate(); diff --git a/src/com/android/launcher2/DragSource.java b/src/com/android/launcher2/DragSource.java index 06f5ee1e6..a654b93c9 100644 --- a/src/com/android/launcher2/DragSource.java +++ b/src/com/android/launcher2/DragSource.java @@ -25,5 +25,6 @@ import com.android.launcher2.DropTarget.DragObject; * */ public interface DragSource { + boolean supportsFlingToDelete(); void onDropCompleted(View target, DragObject d, boolean success); } diff --git a/src/com/android/launcher2/DragView.java b/src/com/android/launcher2/DragView.java index 3090e8f66..5636f995d 100644 --- a/src/com/android/launcher2/DragView.java +++ b/src/com/android/launcher2/DragView.java @@ -51,6 +51,7 @@ public class DragView extends View { ValueAnimator mAnim; private float mOffsetX = 0.0f; private float mOffsetY = 0.0f; + private float mInitialScale = 1f; /** * Construct the drag view. @@ -67,6 +68,7 @@ public class DragView extends View { int left, int top, int width, int height, final float initialScale) { super(launcher); mDragLayer = launcher.getDragLayer(); + mInitialScale = initialScale; final Resources res = getResources(); final float offsetX = res.getDimensionPixelSize(R.dimen.dragViewOffsetX); @@ -151,6 +153,14 @@ public class DragView extends View { return mDragRegion; } + public float getInitialScale() { + return mInitialScale; + } + + public void updateInitialScaleToCurrentScale() { + mInitialScale = getScaleX(); + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(mBitmap.getWidth(), mBitmap.getHeight()); @@ -233,6 +243,11 @@ public class DragView extends View { */ public void show(int touchX, int touchY) { mDragLayer.addView(this); + + // Enable hw-layers on this view + setLayerType(View.LAYER_TYPE_HARDWARE, null); + + // Start the pick-up animation DragLayer.LayoutParams lp = new DragLayer.LayoutParams(0, 0); lp.width = mBitmap.getWidth(); lp.height = mBitmap.getHeight(); @@ -267,6 +282,9 @@ public class DragView extends View { void remove() { if (getParent() != null) { + // Disable hw-layers on this view + setLayerType(View.LAYER_TYPE_NONE, null); + mDragLayer.removeView(DragView.this); } } diff --git a/src/com/android/launcher2/DropTarget.java b/src/com/android/launcher2/DropTarget.java index e49f7829b..fb714c60a 100644 --- a/src/com/android/launcher2/DropTarget.java +++ b/src/com/android/launcher2/DropTarget.java @@ -16,6 +16,7 @@ package com.android.launcher2; +import android.graphics.PointF; import android.graphics.Rect; /** @@ -92,6 +93,13 @@ public interface DropTarget { void onDragExit(DragObject dragObject); /** + * Handle an object being dropped as a result of flinging to delete and will be called in place + * of onDrop(). (This is only called on objects that are set as the DragController's + * fling-to-delete target. + */ + void onFlingToDelete(DragObject dragObject, int x, int y, PointF vec); + + /** * Allows a DropTarget to delegate drag and drop events to another object. * * Most subclasses will should just return null from this method. diff --git a/src/com/android/launcher2/Folder.java b/src/com/android/launcher2/Folder.java index 07e76c9ef..3e8c4a3e7 100644 --- a/src/com/android/launcher2/Folder.java +++ b/src/com/android/launcher2/Folder.java @@ -22,6 +22,7 @@ import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.content.Context; import android.content.res.Resources; +import android.graphics.PointF; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.text.InputType; @@ -35,7 +36,6 @@ import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; -import android.view.View.MeasureSpec; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.inputmethod.EditorInfo; @@ -653,6 +653,10 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList updateItemLocationsInDatabase(); } + public boolean supportsFlingToDelete() { + return true; + } + private void updateItemLocationsInDatabase() { ArrayList<View> list = getItemsInReadingOrder(); for (int i = 0; i < list.size(); i++) { @@ -924,6 +928,10 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList mInfo.add(item); } + public void onFlingToDelete(DragObject d, int x, int y, PointF vec) { + // Do nothing + } + public void onAdd(ShortcutInfo item) { mItemsInvalidated = true; // If the item was dropped onto this open folder, we have done the work associated diff --git a/src/com/android/launcher2/SearchDropTargetBar.java b/src/com/android/launcher2/SearchDropTargetBar.java index 03ca38fb4..76d707618 100644 --- a/src/com/android/launcher2/SearchDropTargetBar.java +++ b/src/com/android/launcher2/SearchDropTargetBar.java @@ -69,6 +69,7 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D dragController.addDragListener(mDeleteDropTarget); dragController.addDropTarget(mInfoDropTarget); dragController.addDropTarget(mDeleteDropTarget); + dragController.setFlingToDeleteDropTarget(mDeleteDropTarget); mInfoDropTarget.setLauncher(launcher); mDeleteDropTarget.setLauncher(launcher); } @@ -153,6 +154,13 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D }); } + public void finishAnimations() { + mDropTargetBarFadeInAnim.end(); + mDropTargetBarFadeOutAnim.end(); + mQSBSearchBarFadeInAnim.end(); + mQSBSearchBarFadeOutAnim.end(); + } + private void cancelAnimations() { mDropTargetBarFadeInAnim.cancel(); mDropTargetBarFadeOutAnim.cancel(); diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java index 76070c4f7..79c262d9c 100644 --- a/src/com/android/launcher2/Workspace.java +++ b/src/com/android/launcher2/Workspace.java @@ -38,6 +38,7 @@ import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Point; +import android.graphics.PointF; import android.graphics.Rect; import android.graphics.Region.Op; import android.graphics.drawable.Drawable; @@ -2333,6 +2334,10 @@ public class Workspace extends SmoothPagedView } } + public void onFlingToDelete(DragObject d, int x, int y, PointF vec) { + // Do nothing + } + public void setFinalScrollForPageChange(int screen) { if (screen >= 0) { mSavedScrollX = getScrollX(); @@ -3325,6 +3330,10 @@ public class Workspace extends SmoothPagedView } } + public boolean supportsFlingToDelete() { + return true; + } + public boolean isDropEnabled() { return true; } |