summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorWinson Chung <winsonc@google.com>2012-03-20 15:22:41 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2012-03-20 15:22:41 -0700
commitcf4b91fa3f4d2c6b4bce5f6cf177979ea9ca7aad (patch)
tree8b3d92a9e42874bc0d170249f64bbcf06f076fb6 /src
parent47a876d443ddc65c8d9a0c95da58d892dbb1faea (diff)
parent043f2af567178b82b0b41f12d379e7dd12da2936 (diff)
downloadandroid_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.java4
-rw-r--r--src/com/android/launcher2/ButtonDropTarget.java6
-rw-r--r--src/com/android/launcher2/DeleteDropTarget.java184
-rw-r--r--src/com/android/launcher2/DragController.java139
-rw-r--r--src/com/android/launcher2/DragLayer.java71
-rw-r--r--src/com/android/launcher2/DragSource.java1
-rw-r--r--src/com/android/launcher2/DragView.java18
-rw-r--r--src/com/android/launcher2/DropTarget.java8
-rw-r--r--src/com/android/launcher2/Folder.java10
-rw-r--r--src/com/android/launcher2/SearchDropTargetBar.java8
-rw-r--r--src/com/android/launcher2/Workspace.java9
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;
}