use of android.view.VelocityTracker in project platform_frameworks_base by android.
the class RotarySelector method onTouchEvent.
/**
* Handle touch screen events.
*
* @param event The motion event.
* @return True if the event was handled, false otherwise.
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mAnimating) {
return true;
}
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(event);
final int height = getHeight();
final int eventX = isHoriz() ? (int) event.getX() : height - ((int) event.getY());
final int hitWindow = mDimpleWidth;
final int action = event.getAction();
switch(action) {
case MotionEvent.ACTION_DOWN:
if (DBG)
log("touch-down");
mTriggered = false;
if (mGrabbedState != NOTHING_GRABBED) {
reset();
invalidate();
}
if (eventX < mLeftHandleX + hitWindow) {
mRotaryOffsetX = eventX - mLeftHandleX;
setGrabbedState(LEFT_HANDLE_GRABBED);
invalidate();
vibrate(VIBRATE_SHORT);
} else if (eventX > mRightHandleX - hitWindow) {
mRotaryOffsetX = eventX - mRightHandleX;
setGrabbedState(RIGHT_HANDLE_GRABBED);
invalidate();
vibrate(VIBRATE_SHORT);
}
break;
case MotionEvent.ACTION_MOVE:
if (DBG)
log("touch-move");
if (mGrabbedState == LEFT_HANDLE_GRABBED) {
mRotaryOffsetX = eventX - mLeftHandleX;
invalidate();
final int rightThresh = isHoriz() ? getRight() : height;
if (eventX >= rightThresh - mEdgeTriggerThresh && !mTriggered) {
mTriggered = true;
dispatchTriggerEvent(OnDialTriggerListener.LEFT_HANDLE);
final VelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
final int rawVelocity = isHoriz() ? (int) velocityTracker.getXVelocity() : -(int) velocityTracker.getYVelocity();
final int velocity = Math.max(mMinimumVelocity, rawVelocity);
mDimplesOfFling = Math.max(8, Math.abs(velocity / mDimpleSpacing));
startAnimationWithVelocity(eventX - mLeftHandleX, mDimplesOfFling * mDimpleSpacing, velocity);
}
} else if (mGrabbedState == RIGHT_HANDLE_GRABBED) {
mRotaryOffsetX = eventX - mRightHandleX;
invalidate();
if (eventX <= mEdgeTriggerThresh && !mTriggered) {
mTriggered = true;
dispatchTriggerEvent(OnDialTriggerListener.RIGHT_HANDLE);
final VelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
final int rawVelocity = isHoriz() ? (int) velocityTracker.getXVelocity() : -(int) velocityTracker.getYVelocity();
final int velocity = Math.min(-mMinimumVelocity, rawVelocity);
mDimplesOfFling = Math.max(8, Math.abs(velocity / mDimpleSpacing));
startAnimationWithVelocity(eventX - mRightHandleX, -(mDimplesOfFling * mDimpleSpacing), velocity);
}
}
break;
case MotionEvent.ACTION_UP:
if (DBG)
log("touch-up");
// handle animating back to start if they didn't trigger
if (mGrabbedState == LEFT_HANDLE_GRABBED && Math.abs(eventX - mLeftHandleX) > 5) {
// set up "snap back" animation
startAnimation(eventX - mLeftHandleX, 0, SNAP_BACK_ANIMATION_DURATION_MILLIS);
} else if (mGrabbedState == RIGHT_HANDLE_GRABBED && Math.abs(eventX - mRightHandleX) > 5) {
// set up "snap back" animation
startAnimation(eventX - mRightHandleX, 0, SNAP_BACK_ANIMATION_DURATION_MILLIS);
}
mRotaryOffsetX = 0;
setGrabbedState(NOTHING_GRABBED);
invalidate();
if (mVelocityTracker != null) {
// wishin' we had generational GC
mVelocityTracker.recycle();
mVelocityTracker = null;
}
break;
case MotionEvent.ACTION_CANCEL:
if (DBG)
log("touch-cancel");
reset();
invalidate();
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
break;
}
return true;
}
use of android.view.VelocityTracker in project mobile-android by photo.
the class Workspace method onTouchEvent.
/*
* (non-Javadoc)
*
* @see android.view.View#onTouchEvent(android.view.MotionEvent)
*/
@Override
public boolean onTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
if (!isEnabled()) {
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
snapToScreen(mCurrentScreen);
// We don't want the events. Let them fall through to the all apps view.
return false;
}
acquireVelocityTrackerAndAddMovement(ev);
switch(action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
// Remember where the motion event started
mLastMotionX = ev.getX();
mLastMotionX2 = ev.getX();
mActivePointerId = ev.getPointerId(0);
if (mTouchState == TOUCH_STATE_SCROLLING) {
enableChildrenCache(mCurrentScreen - 1, mCurrentScreen + 1);
}
break;
case MotionEvent.ACTION_MOVE:
if (mTouchState == TOUCH_STATE_SCROLLING) {
// Scroll to follow the motion event
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
final float x = ev.getX(pointerIndex);
final float deltaX = mLastMotionX - x;
final float deltaX2 = mLastMotionX2 - x;
final int mode = mOverScrollMode;
mLastMotionX = x;
if (deltaX < 0) {
mTouchX += deltaX;
mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
if (mTouchX < 0 && mode != OVER_SCROLL_NEVER) {
mTouchX = mLastMotionX = 0;
if (mEdgeGlowLeft != null && deltaX2 < 0) {
float overscroll = ((float) -deltaX2 * 1.5f) / getWidth();
mEdgeGlowLeft.onPull(overscroll);
if (!mEdgeGlowRight.isFinished()) {
mEdgeGlowRight.onRelease();
}
}
}
invalidate();
} else if (deltaX > 0) {
final int totalWidth = getScreenScrollPositionX(mItemCount - 1);
final float availableToScroll = getScreenScrollPositionX(mItemCount) - mTouchX;
mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
mTouchX += Math.min(availableToScroll, deltaX);
if (availableToScroll <= getWidth() && mode != OVER_SCROLL_NEVER) {
mTouchX = mLastMotionX = totalWidth;
if (mEdgeGlowLeft != null && deltaX2 > 0) {
float overscroll = ((float) deltaX2 * 1.5f) / getWidth();
mEdgeGlowRight.onPull(overscroll);
if (!mEdgeGlowLeft.isFinished()) {
mEdgeGlowLeft.onRelease();
}
}
}
invalidate();
} else {
awakenScrollBars();
}
}
break;
case MotionEvent.ACTION_UP:
if (mTouchState == TOUCH_STATE_SCROLLING) {
final VelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
final int velocityX = (int) velocityTracker.getXVelocity(mActivePointerId);
final int screenWidth = getWidth();
final int whichScreen = (getScrollX() + (screenWidth / 2)) / screenWidth;
final float scrolledPos = (float) getScrollX() / screenWidth;
if (velocityX > SNAP_VELOCITY && mCurrentScreen > 0) {
// Fling hard enough to move left.
// Don't fling across more than one screen at a time.
final int bound = scrolledPos < whichScreen ? mCurrentScreen - 1 : mCurrentScreen;
snapToScreen(Math.min(whichScreen, bound), velocityX, true);
} else if (velocityX < -SNAP_VELOCITY && mCurrentScreen < mItemCount - 1) {
// Fling hard enough to move right
// Don't fling across more than one screen at a time.
final int bound = scrolledPos > whichScreen ? mCurrentScreen + 1 : mCurrentScreen;
snapToScreen(Math.max(whichScreen, bound), velocityX, true);
} else {
snapToScreen(whichScreen, 0, true);
}
if (mEdgeGlowLeft != null) {
mEdgeGlowLeft.onRelease();
mEdgeGlowRight.onRelease();
}
}
mTouchState = TOUCH_STATE_REST;
mActivePointerId = INVALID_POINTER;
releaseVelocityTracker();
break;
case MotionEvent.ACTION_CANCEL:
if (mTouchState == TOUCH_STATE_SCROLLING) {
final int screenWidth = getWidth();
final int whichScreen = (getScrollX() + (screenWidth / 2)) / screenWidth;
snapToScreen(whichScreen, 0, true);
}
mTouchState = TOUCH_STATE_REST;
mActivePointerId = INVALID_POINTER;
releaseVelocityTracker();
if (mEdgeGlowLeft != null) {
mEdgeGlowLeft.onRelease();
mEdgeGlowRight.onRelease();
}
break;
case MotionEvent.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
break;
}
return true;
}
use of android.view.VelocityTracker in project android_frameworks_base by ParanoidAndroid.
the class PagedView method onTouchEvent.
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (DISABLE_TOUCH_INTERACTION) {
return false;
}
// Skip touch handling if there are no pages to swipe
if (getChildCount() <= 0)
return super.onTouchEvent(ev);
acquireVelocityTrackerAndAddMovement(ev);
final int action = ev.getAction();
switch(action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
/*
* If being flinged and user touches, stop the fling. isFinished
* will be false if being flinged.
*/
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
// Remember where the motion event started
mDownMotionX = mLastMotionX = ev.getX();
mDownMotionY = mLastMotionY = ev.getY();
mDownScrollX = getScrollX();
float[] p = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
mParentDownMotionX = p[0];
mParentDownMotionY = p[1];
mLastMotionXRemainder = 0;
mTotalMotionX = 0;
mActivePointerId = ev.getPointerId(0);
// Determine if the down event is within the threshold to be an edge swipe
int leftEdgeBoundary = getViewportOffsetX() + mEdgeSwipeRegionSize;
int rightEdgeBoundary = getMeasuredWidth() - getViewportOffsetX() - mEdgeSwipeRegionSize;
if ((mDownMotionX <= leftEdgeBoundary || mDownMotionX >= rightEdgeBoundary)) {
mDownEventOnEdge = true;
}
if (mTouchState == TOUCH_STATE_SCROLLING) {
pageBeginMoving();
}
break;
case MotionEvent.ACTION_MOVE:
if (mTouchState == TOUCH_STATE_SCROLLING) {
// Scroll to follow the motion event
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
if (pointerIndex == -1)
return true;
final float x = ev.getX(pointerIndex);
final float deltaX = mLastMotionX + mLastMotionXRemainder - x;
mTotalMotionX += Math.abs(deltaX);
// scrolled position (which is discrete).
if (Math.abs(deltaX) >= 1.0f) {
mTouchX += deltaX;
mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
if (!mDeferScrollUpdate) {
scrollBy((int) deltaX, 0);
if (DEBUG)
Log.d(TAG, "onTouchEvent().Scrolling: " + deltaX);
} else {
invalidate();
}
mLastMotionX = x;
mLastMotionXRemainder = deltaX - (int) deltaX;
} else {
awakenScrollBars();
}
} else if (mTouchState == TOUCH_STATE_REORDERING) {
// Update the last motion position
mLastMotionX = ev.getX();
mLastMotionY = ev.getY();
// Update the parent down so that our zoom animations take this new movement into
// account
float[] pt = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
mParentDownMotionX = pt[0];
mParentDownMotionY = pt[1];
updateDragViewTranslationDuringDrag();
// Find the closest page to the touch point
final int dragViewIndex = indexOfChild(mDragView);
int bufferSize = (int) (REORDERING_SIDE_PAGE_BUFFER_PERCENTAGE * getViewportWidth());
int leftBufferEdge = (int) (mapPointFromViewToParent(this, mViewport.left, 0)[0] + bufferSize);
int rightBufferEdge = (int) (mapPointFromViewToParent(this, mViewport.right, 0)[0] - bufferSize);
// Change the drag view if we are hovering over the drop target
boolean isHoveringOverDelete = isHoveringOverDeleteDropTarget((int) mParentDownMotionX, (int) mParentDownMotionY);
setPageHoveringOverDeleteDropTarget(dragViewIndex, isHoveringOverDelete);
if (DEBUG)
Log.d(TAG, "leftBufferEdge: " + leftBufferEdge);
if (DEBUG)
Log.d(TAG, "rightBufferEdge: " + rightBufferEdge);
if (DEBUG)
Log.d(TAG, "mLastMotionX: " + mLastMotionX);
if (DEBUG)
Log.d(TAG, "mLastMotionY: " + mLastMotionY);
if (DEBUG)
Log.d(TAG, "mParentDownMotionX: " + mParentDownMotionX);
if (DEBUG)
Log.d(TAG, "mParentDownMotionY: " + mParentDownMotionY);
float parentX = mParentDownMotionX;
int pageIndexToSnapTo = -1;
if (parentX < leftBufferEdge && dragViewIndex > 0) {
pageIndexToSnapTo = dragViewIndex - 1;
} else if (parentX > rightBufferEdge && dragViewIndex < getChildCount() - 1) {
pageIndexToSnapTo = dragViewIndex + 1;
}
final int pageUnderPointIndex = pageIndexToSnapTo;
if (pageUnderPointIndex > -1 && !isHoveringOverDelete) {
mTempVisiblePagesRange[0] = 0;
mTempVisiblePagesRange[1] = getPageCount() - 1;
boundByReorderablePages(true, mTempVisiblePagesRange);
if (mTempVisiblePagesRange[0] <= pageUnderPointIndex && pageUnderPointIndex <= mTempVisiblePagesRange[1] && pageUnderPointIndex != mSidePageHoverIndex && mScroller.isFinished()) {
mSidePageHoverIndex = pageUnderPointIndex;
mSidePageHoverRunnable = new Runnable() {
@Override
public void run() {
// Update the down scroll position to account for the fact that the
// current page is moved
mDownScrollX = getChildOffset(pageUnderPointIndex) - getRelativeChildOffset(pageUnderPointIndex);
// Setup the scroll to the correct page before we swap the views
snapToPage(pageUnderPointIndex);
// For each of the pages between the paged view and the drag view,
// animate them from the previous position to the new position in
// the layout (as a result of the drag view moving in the layout)
int shiftDelta = (dragViewIndex < pageUnderPointIndex) ? -1 : 1;
int lowerIndex = (dragViewIndex < pageUnderPointIndex) ? dragViewIndex + 1 : pageUnderPointIndex;
int upperIndex = (dragViewIndex > pageUnderPointIndex) ? dragViewIndex - 1 : pageUnderPointIndex;
for (int i = lowerIndex; i <= upperIndex; ++i) {
View v = getChildAt(i);
// dragViewIndex < pageUnderPointIndex, so after we remove the
// drag view all subsequent views to pageUnderPointIndex will
// shift down.
int oldX = getViewportOffsetX() + getChildOffset(i);
int newX = getViewportOffsetX() + getChildOffset(i + shiftDelta);
// Animate the view translation from its old position to its new
// position
AnimatorSet anim = (AnimatorSet) v.getTag();
if (anim != null) {
anim.cancel();
}
v.setTranslationX(oldX - newX);
anim = new AnimatorSet();
anim.setDuration(REORDERING_REORDER_REPOSITION_DURATION);
anim.playTogether(ObjectAnimator.ofFloat(v, "translationX", 0f));
anim.start();
v.setTag(anim);
}
removeView(mDragView);
onRemoveView(mDragView, false);
addView(mDragView, pageUnderPointIndex);
onAddView(mDragView, pageUnderPointIndex);
mSidePageHoverIndex = -1;
}
};
postDelayed(mSidePageHoverRunnable, REORDERING_SIDE_PAGE_HOVER_TIMEOUT);
}
} else {
removeCallbacks(mSidePageHoverRunnable);
mSidePageHoverIndex = -1;
}
} else {
determineScrollingStart(ev);
}
break;
case MotionEvent.ACTION_UP:
if (mTouchState == TOUCH_STATE_SCROLLING) {
final int activePointerId = mActivePointerId;
final int pointerIndex = ev.findPointerIndex(activePointerId);
final float x = ev.getX(pointerIndex);
final VelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
int velocityX = (int) velocityTracker.getXVelocity(activePointerId);
final int deltaX = (int) (x - mDownMotionX);
final int pageWidth = getScaledMeasuredWidth(getPageAt(mCurrentPage));
boolean isSignificantMove = Math.abs(deltaX) > pageWidth * SIGNIFICANT_MOVE_THRESHOLD;
mTotalMotionX += Math.abs(mLastMotionX + mLastMotionXRemainder - x);
boolean isFling = mTotalMotionX > MIN_LENGTH_FOR_FLING && Math.abs(velocityX) > mFlingThresholdVelocity;
// In the case that the page is moved far to one direction and then is flung
// in the opposite direction, we use a threshold to determine whether we should
// just return to the starting page, or if we should skip one further.
boolean returnToOriginalPage = false;
if (Math.abs(deltaX) > pageWidth * RETURN_TO_ORIGINAL_PAGE_THRESHOLD && Math.signum(velocityX) != Math.signum(deltaX) && isFling) {
returnToOriginalPage = true;
}
int finalPage;
// move to the left and fling to the right will register as a fling to the right.
if (((isSignificantMove && deltaX > 0 && !isFling) || (isFling && velocityX > 0)) && mCurrentPage > 0) {
finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage - 1;
snapToPageWithVelocity(finalPage, velocityX);
} else if (((isSignificantMove && deltaX < 0 && !isFling) || (isFling && velocityX < 0)) && mCurrentPage < getChildCount() - 1) {
finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage + 1;
snapToPageWithVelocity(finalPage, velocityX);
} else {
snapToDestination();
}
} else if (mTouchState == TOUCH_STATE_PREV_PAGE) {
// at this point we have not moved beyond the touch slop
// (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so
// we can just page
int nextPage = Math.max(0, mCurrentPage - 1);
if (nextPage != mCurrentPage) {
snapToPage(nextPage);
} else {
snapToDestination();
}
} else if (mTouchState == TOUCH_STATE_NEXT_PAGE) {
// at this point we have not moved beyond the touch slop
// (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so
// we can just page
int nextPage = Math.min(getChildCount() - 1, mCurrentPage + 1);
if (nextPage != mCurrentPage) {
snapToPage(nextPage);
} else {
snapToDestination();
}
} else if (mTouchState == TOUCH_STATE_REORDERING) {
// Update the last motion position
mLastMotionX = ev.getX();
mLastMotionY = ev.getY();
// Update the parent down so that our zoom animations take this new movement into
// account
float[] pt = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
mParentDownMotionX = pt[0];
mParentDownMotionY = pt[1];
updateDragViewTranslationDuringDrag();
boolean handledFling = false;
if (!DISABLE_FLING_TO_DELETE) {
// Check the velocity and see if we are flinging-to-delete
PointF flingToDeleteVector = isFlingingToDelete();
if (flingToDeleteVector != null) {
onFlingToDelete(flingToDeleteVector);
handledFling = true;
}
}
if (!handledFling && isHoveringOverDeleteDropTarget((int) mParentDownMotionX, (int) mParentDownMotionY)) {
onDropToDelete();
}
} else {
onUnhandledTap(ev);
}
// Remove the callback to wait for the side page hover timeout
removeCallbacks(mSidePageHoverRunnable);
// End any intermediate reordering states
resetTouchState();
break;
case MotionEvent.ACTION_CANCEL:
if (mTouchState == TOUCH_STATE_SCROLLING) {
snapToDestination();
}
resetTouchState();
break;
case MotionEvent.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
break;
}
return true;
}
use of android.view.VelocityTracker in project android_frameworks_base by ParanoidAndroid.
the class VelocityTest method testStabilityInTime.
/**
* Velocity is independent of the time when the events occurs,
* it only depends on delays between the events.
*/
@MediumTest
public void testStabilityInTime() {
long t = System.currentTimeMillis();
VelocityTracker vt = VelocityTracker.obtain();
drag(vt, 100, 200, 100, 200, 10, t, 400);
vt.computeCurrentVelocity(1);
float firstX = vt.getXVelocity();
float firstY = vt.getYVelocity();
vt.clear();
// on hour later
drag(vt, 100, 200, 100, 200, 10, t + 3600 * 1000, 400);
vt.computeCurrentVelocity(1);
float secondX = vt.getXVelocity();
float secondY = vt.getYVelocity();
assertEqualFuzzy(firstX, secondX, 0.1f);
assertEqualFuzzy(firstY, secondY, 0.1f);
vt.recycle();
}
use of android.view.VelocityTracker in project android_frameworks_base by ParanoidAndroid.
the class VelocityTest method testStabilityOfUnits.
/**
* Test the units parameter of {@link android.view.VelocityTracker}.computeCurrentVelocity()
*/
@MediumTest
public void testStabilityOfUnits() {
long t = System.currentTimeMillis();
VelocityTracker vt = VelocityTracker.obtain();
drag(vt, 100, 200, 100, 200, 10, t, 300);
vt.computeCurrentVelocity(1);
float firstX = vt.getXVelocity();
float firstY = vt.getYVelocity();
vt.computeCurrentVelocity(1000);
float secondX = vt.getXVelocity();
float secondY = vt.getYVelocity();
assertEqualFuzzy(firstX, secondX / 1000.0f, 0.1f);
assertEqualFuzzy(firstY, secondY / 1000.0f, 0.1f);
vt.recycle();
}
Aggregations