protected MotionEvent createLongLeftMoveEvent() { MotionEvent event = mock(MotionEvent.class); when(event.getAction()).thenReturn(MotionEvent.ACTION_MOVE); when(event.getX()).thenReturn(50f); when(event.getY()).thenReturn(150f); when(event.getX(0)).thenReturn(50f); when(event.getY(0)).thenReturn(150f); when(event.getHistorySize()).thenReturn(1); when(event.getHistoricalX(eq(0))).thenReturn(100f); when(event.getHistoricalY(eq(0))).thenReturn(200f); when(event.getHistoricalX(eq(0), eq(0))).thenReturn(100f); when(event.getHistoricalY(eq(0), eq(0))).thenReturn(200f); return event; }
@Override public boolean onTouchEvent(MotionEvent event) { float mCurX; float mCurY; // API level 9 and above supports "Major" property on event which // gives // the size of the touch area at the point of contact // so for now we just hard code float TOUCH_AREA_SIZE = penWidth; int action = event.getAction(); if (action != MotionEvent.ACTION_UP && action != MotionEvent.ACTION_CANCEL) { int N = event.getHistorySize(); int P = event.getPointerCount(); for (int i = 0; i < N; i++) { for (int j = 0; j < P; j++) { mCurX = event.getHistoricalX(j, i); mCurY = event.getHistoricalY(j, i); drawPoint(mCurX, mCurY, event.getHistoricalPressure(j, i), TOUCH_AREA_SIZE); } } for (int j = 0; j < P; j++) { mCurX = event.getX(j); mCurY = event.getY(j); drawPoint(mCurX, mCurY, event.getPressure(j), TOUCH_AREA_SIZE); } } unsaved = true; return true; }
@Test public void onTouchMoveAction_2ndLeftDragInRightEnd_overscrollLeftFurther() throws Exception { // Arrange // Bring UUT to a left-overscroll state MotionEvent event1 = createShortLeftMoveEvent(); when(mViewAdapter.isInAbsoluteStart()).thenReturn(false); when(mViewAdapter.isInAbsoluteEnd()).thenReturn(true); HorizontalOverScrollBounceEffectDecorator uut = getUUT(); uut.onTouch(mView, event1); reset(mView); // Create 2nd left-drag event MotionEvent event2 = createLongLeftMoveEvent(); // Act boolean ret = uut.onTouch(mView, event2); // Assert float expectedTransX = (event2.getX() - event2.getHistoricalX(0)) / DEFAULT_TOUCH_DRAG_MOVE_RATIO_FWD; verify(mView).setTranslationX(expectedTransX); verify(mView, never()).setTranslationY(anyFloat()); assertTrue(ret); }
public boolean onTouch(View view, MotionEvent event) { float x = event.getX(); float y = event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: path.moveTo(x, y); return true; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_MOVE: l = x; r = x; t = y; b = y; for (int i = 0; i < event.getHistorySize(); i++) { float newX = event.getHistoricalX(i); float newY = event.getHistoricalY(i); path.lineTo(newX, newY); l = newX < l ? newX : l; t = newY < t ? newY : t; r = newX > r ? newX : r; b = newY > b ? newY : b; } rect.set(l, t, r, b); Log.d("TAG", rect.toShortString()); invalidate( (int) rect.left - 5, (int) rect.top - 5, (int) rect.right + 5, (int) rect.bottom + 5); break; default: } return super.onTouchEvent(event); }
// @!ANDROID-4 private static int getAction(int index, MotionEvent event) { int action = event.getAction(); if (action == MotionEvent.ACTION_MOVE) { int hsz = event.getHistorySize(); if (hsz > 0) { if (Math.abs(event.getX(index) - event.getHistoricalX(index, hsz - 1)) > 1 || Math.abs(event.getY(index) - event.getHistoricalY(index, hsz - 1)) > 1) return 1; else return 2; } return 1; } switch (index) { case 0: if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_1_DOWN) return 0; if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_1_UP) return 3; break; case 1: if (action == MotionEvent.ACTION_POINTER_2_DOWN || action == MotionEvent.ACTION_POINTER_DOWN) return 0; if (action == MotionEvent.ACTION_POINTER_2_UP || action == MotionEvent.ACTION_POINTER_UP) return 3; break; case 2: if (action == MotionEvent.ACTION_POINTER_3_DOWN || action == MotionEvent.ACTION_POINTER_DOWN) return 0; if (action == MotionEvent.ACTION_POINTER_3_UP || action == MotionEvent.ACTION_POINTER_UP) return 3; break; } return 2; }
@Override public boolean onTouchEvent(final ViewGroup view, final MotionEvent event) { if (mIsVerticalScrolling && !mController.isScrolling() || mShouldDisableScroll) return true; switch (event.getAction()) { case MotionEvent.ACTION_DOWN: { mTempDeltaX = 0; mTotalMoveX = 0; mTotalMoveY = 0; mActualMoveX = 0; mIsVerticalScrolling = false; mController.reset(); break; } case MotionEvent.ACTION_MOVE: { final int hist_size = event.getHistorySize(); if (hist_size == 0) { break; } final float distanceX = mTempDeltaX = event.getX() - event.getHistoricalX(0); mActualMoveX = mTotalMoveX += mTempDeltaX; mController.scrollBy((int) -distanceX); break; } } return true; }
private void track(MotionEvent event) { mX.saveTouchPos(); mY.saveTouchPos(); for (int i = 0; i < event.getHistorySize(); i++) { track( event.getHistoricalX(0, i), event.getHistoricalY(0, i), event.getHistoricalEventTime(i)); } track(event.getX(0), event.getY(0), event.getEventTime()); if (stopped()) { if (mState == PanZoomState.PANNING) { setState(PanZoomState.PANNING_HOLD); } else if (mState == PanZoomState.PANNING_LOCKED) { setState(PanZoomState.PANNING_HOLD_LOCKED); } else { // should never happen, but handle anyway for robustness Log.e(LOGTAG, "Impossible case " + mState + " when stopped in track"); setState(PanZoomState.PANNING_HOLD_LOCKED); } } mX.startPan(); mY.startPan(); updatePosition(); }
/** * Extracts the touch point data from a MotionEvent, converts each point into a marshallable * object and passes the set of points to the JNI layer to be transmitted to the remote host. * * @param event The event to send to the remote host for injection. NOTE: This object must be * updated to represent the remote machine's coordinate system before calling this function. */ public void sendTouchEvent(MotionEvent event) { int action = event.getActionMasked(); TouchEventData.EventType touchEventType = TouchEventData.EventType.fromMaskedAction(action); List<TouchEventData> touchEventList = new ArrayList<TouchEventData>(); if (action == MotionEvent.ACTION_MOVE) { // In order to process all of the events associated with an ACTION_MOVE event, we need // to walk the list of historical events in order and add each event to our list, then // retrieve the current move event data. int pointerCount = event.getPointerCount(); int historySize = event.getHistorySize(); for (int h = 0; h < historySize; ++h) { for (int p = 0; p < pointerCount; ++p) { touchEventList.add( new TouchEventData( event.getPointerId(p), event.getHistoricalX(p, h), event.getHistoricalY(p, h), event.getHistoricalSize(p, h), event.getHistoricalSize(p, h), event.getHistoricalOrientation(p, h), event.getHistoricalPressure(p, h))); } } for (int p = 0; p < pointerCount; p++) { touchEventList.add( new TouchEventData( event.getPointerId(p), event.getX(p), event.getY(p), event.getSize(p), event.getSize(p), event.getOrientation(p), event.getPressure(p))); } } else { // For all other events, we only want to grab the current/active pointer. The event // contains a list of every active pointer but passing all of of these to the host can // cause confusion on the remote OS side and result in broken touch gestures. int activePointerIndex = event.getActionIndex(); touchEventList.add( new TouchEventData( event.getPointerId(activePointerIndex), event.getX(activePointerIndex), event.getY(activePointerIndex), event.getSize(activePointerIndex), event.getSize(activePointerIndex), event.getOrientation(activePointerIndex), event.getPressure(activePointerIndex))); } if (!touchEventList.isEmpty()) { mInjector.sendTouchEvent(touchEventType, touchEventList.toArray(new TouchEventData[0])); } }
@Override public boolean onTouchEvent(MotionEvent event) { float mCurX; float mCurY; ArrayList<Point> eraserpoints = new ArrayList<Point>(); int action = event.getAction(); if (action != MotionEvent.ACTION_UP && action != MotionEvent.ACTION_CANCEL) { // Log.d(TAG, "PEN UP"); } if (action == MotionEvent.ACTION_DOWN) { // start recording points mCurrentPath = new Path(); mCurrentPath.moveTo(event.getX(), event.getY()); } if (action == MotionEvent.ACTION_MOVE) { // start recording points int N = event.getHistorySize(); int P = event.getPointerCount(); for (int i = 0; i < N; i++) { for (int j = 0; j < P; j++) { mCurX = event.getHistoricalX(j, i); mCurY = event.getHistoricalY(j, i); if (mEraserMode == true) { if (eraserpoints != null) { eraserpoints.add(new Point(Math.round(mCurX), Math.round(mCurY))); } else { Log.e(TAG, "no eraserpoints array defined, skipping adding erase point"); } } else { if (mCurrentPath != null) { mCurrentPath.lineTo(mCurX, mCurY); } else { Log.e(TAG, "NO PATH TO ADD POINT" + mCurX + "," + mCurY); } } } } if (mCurrentPath != null) { mCurrentPath.lineTo(event.getX(), event.getY()); mCanvas.drawPath(mCurrentPath, (mEraserMode == true ? mEraserPainter : mPenPainter)); invalidate(); } else { Log.e(TAG, "Missing CurrentPath object"); } } mUnsaved = true; return true; }
public void c(MotionEvent paramMotionEvent) { int j = paramMotionEvent.getHistorySize(); int i = 0; while (i < j) { a( paramMotionEvent.getActionMasked(), paramMotionEvent.getHistoricalX(0, i), paramMotionEvent.getHistoricalY(0, i)); i += 1; } a(paramMotionEvent.getActionMasked(), paramMotionEvent.getX(), paramMotionEvent.getY()); }
@Override public boolean onTouch(final View view, final MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: { mTempDeltaX = 0; mTotalMoveX = 0; mIsScrolling = false; // final View layout = mParent.getRightPaneLayout(); mShouldDisableScroll = !(mContext instanceof DualPaneActivity && ((DualPaneActivity) mContext).isRightPaneUsed()); if (!mShouldDisableScroll) { mController.reset(); } else return false; break; } case MotionEvent.ACTION_MOVE: { if (mShouldDisableScroll) return false; final int hist_size = event.getHistorySize(); if (hist_size == 0) { break; } final float distanceX = mTempDeltaX = event.getX() - event.getHistoricalX(0); mTotalMoveX += mTempDeltaX; if (Math.abs(mTotalMoveX) >= mScaledTouchSlop) { mIsScrolling = true; } if (mIsScrolling) { mController.scrollBy((int) -distanceX); } break; } case MotionEvent.ACTION_UP: { if (mIsScrolling) { mController.release(-mTempDeltaX, -mTotalMoveX); } mTempDeltaX = 0; mTotalMoveX = 0; mIsScrolling = false; if (mShouldDisableScroll) { mShouldDisableScroll = false; return false; } mShouldDisableScroll = false; break; } } return true; }
/** * When over-scroll has already started (to the left in this case) and suddenly the user changes * their mind and scrolls a bit in the other direction: <br> * We expect the <b>touch to still be intercepted</b> in that case, and the <b>overscroll to * remain in effect</b>. */ @Test public void onTouchMoveAction_dragRightWhenLeftOverscolled_continueOverscrollingRight() throws Exception { // Arrange // In left & right tests we use equal ratios to avoid the effect's under-scroll handling final float touchDragRatioFwd = 3f; final float touchDragRatioBck = 3f; // Bring UUT to a left-overscroll state when(mViewAdapter.isInAbsoluteStart()).thenReturn(false); when(mViewAdapter.isInAbsoluteEnd()).thenReturn(true); HorizontalOverScrollBounceEffectDecorator uut = getUUT(touchDragRatioFwd, touchDragRatioBck); MotionEvent eventMoveLeft = createLongLeftMoveEvent(); uut.onTouch(mView, eventMoveLeft); reset(mView); float startTransX = (eventMoveLeft.getX() - eventMoveLeft.getHistoricalX(0)) / touchDragRatioFwd; when(mView.getTranslationX()).thenReturn(startTransX); // Create the right-drag event MotionEvent eventMoveRight = createShortRightMoveEvent(); // Act boolean ret = uut.onTouch(mView, eventMoveRight); // Assert float expectedTransX = startTransX + (eventMoveRight.getX() - eventMoveRight.getHistoricalX(0)) / touchDragRatioBck; verify(mView).setTranslationX(expectedTransX); verify(mView, never()).setTranslationY(anyFloat()); assertTrue(ret); }
@Override public boolean onTouchEvent(MotionEvent event) { float eventX = event.getX(); float eventY = event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: path.moveTo(eventX, eventY); lastTouchX = eventX; lastTouchY = eventY; // There is no end point yet, so don't waste cycles invalidating. return true; case MotionEvent.ACTION_MOVE: case MotionEvent.ACTION_UP: // Start tracking the dirty region. resetDirtyRect(eventX, eventY); // When the hardware tracks events faster than they are delivered, the // event will contain a history of those skipped points. int historySize = event.getHistorySize(); for (int i = 0; i < historySize; i++) { float historicalX = event.getHistoricalX(i); float historicalY = event.getHistoricalY(i); expandDirtyRect(historicalX, historicalY); path.lineTo(historicalX, historicalY); } // After replaying history, connect the line to the touch point. path.lineTo(eventX, eventY); break; default: Log.d("default", "Ignored touch event: " + event.toString()); return false; } // Include half the stroke width to avoid clipping. invalidate( (int) (dirtyRect.left - HALF_STROKE_WIDTH), (int) (dirtyRect.top - HALF_STROKE_WIDTH), (int) (dirtyRect.right + HALF_STROKE_WIDTH), (int) (dirtyRect.bottom + HALF_STROKE_WIDTH)); lastTouchX = eventX; lastTouchY = eventY; return true; }
/** * Add a user's movement to the tracker. You should call this for the initial {@link * MotionEvent#ACTION_DOWN}, the following {@link MotionEvent#ACTION_MOVE} events that you * receive, and the final {@link MotionEvent#ACTION_UP}. You can, however, call this for whichever * events you desire. * * @param ev The MotionEvent you received and would like to track. */ public void addMovement(MotionEvent ev) { final int mN = ev.getHistorySize(); if (++mLastTouch >= NUM_PAST) { mLastTouch = 0; } for (int i = 0; i < mN; ++i) { mPastX[mLastTouch] = ev.getHistoricalX(i); mPastY[mLastTouch] = ev.getHistoricalY(i); mPastTime[mLastTouch] = ev.getHistoricalEventTime(i); if (++mLastTouch >= NUM_PAST) { mLastTouch = 0; } } mPastX[mLastTouch] = ev.getX(); mPastY[mLastTouch] = ev.getY(); mPastTime[mLastTouch] = ev.getEventTime(); }
@Override public boolean onInterceptTouchEvent(final ViewGroup view, final MotionEvent event) { mShouldDisableScroll = !(isTouchEventHandled(view, event) || mContext instanceof DualPaneActivity && ((DualPaneActivity) mContext).isRightPaneUsed()); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: { mFirstDownHandled = !mShouldDisableScroll; mTempDeltaX = 0; mTotalMoveX = 0; mTotalMoveY = 0; mActualMoveX = 0; mIsVerticalScrolling = false; if (mFirstDownHandled) { mParent.animateOpen(); } break; } case MotionEvent.ACTION_MOVE: { final int hist_size = event.getHistorySize(); if (hist_size == 0) { break; } mTempDeltaX = event.getX() - event.getHistoricalX(0); mTotalMoveX += mTempDeltaX; final float deltaY = event.getY() - event.getHistoricalY(0); mTotalMoveY += deltaY; if (Math.abs(mTempDeltaX) > Math.abs(deltaY) && !mIsVerticalScrolling && Math.abs(mTotalMoveX) >= mScaledTouchSlop) return true; if (Math.abs(mTempDeltaX) < Math.abs(deltaY) && Math.abs(mTotalMoveY) >= mScaledTouchSlop) { mIsVerticalScrolling = true; return false; } break; } } return false; }
@Override public boolean onTouchEvent(MotionEvent event) { float eventX = event.getX(); float eventY = event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: path.moveTo(eventX, eventY); lastTouchX = eventX; lastTouchY = eventY; return true; case MotionEvent.ACTION_MOVE: case MotionEvent.ACTION_UP: resetDirtyRect(eventX, eventY); int historySize = event.getHistorySize(); for (int i = 0; i < historySize; i++) { float historicalX = event.getHistoricalX(i); float historicalY = event.getHistoricalY(i); expandDirtyRect(historicalX, historicalY); path.lineTo(historicalX, historicalY); } path.lineTo(eventX, eventY); break; default: return false; } invalidate( (int) (dirtyRect.left - HALF_STROKE_WIDTH), (int) (dirtyRect.top - HALF_STROKE_WIDTH), (int) (dirtyRect.right + HALF_STROKE_WIDTH), (int) (dirtyRect.bottom + HALF_STROKE_WIDTH)); lastTouchX = eventX; lastTouchY = eventY; return true; }
private int detectSwipe(MotionEvent move) { final int historySize = move.getHistorySize(); final int pointerCount = move.getPointerCount(); for (int p = 0; p < pointerCount; p++) { final int pointerId = move.getPointerId(p); final int i = findIndex(pointerId); if (i != UNTRACKED_POINTER) { for (int h = 0; h < historySize; h++) { final long time = move.getHistoricalEventTime(h); final float x = move.getHistoricalX(p, h); final float y = move.getHistoricalY(p, h); final int swipe = detectSwipe(i, time, x, y); if (swipe != SWIPE_NONE) { return swipe; } } final int swipe = detectSwipe(i, move.getEventTime(), move.getX(p), move.getY(p)); if (swipe != SWIPE_NONE) { return swipe; } } } return SWIPE_NONE; }
@Test public void onTouchMoveAction_dragRightInLeftEnd_overscrollRight() throws Exception { // Arrange MotionEvent event = createShortRightMoveEvent(); when(mViewAdapter.isInAbsoluteStart()).thenReturn(true); when(mViewAdapter.isInAbsoluteEnd()).thenReturn(false); HorizontalOverScrollBounceEffectDecorator uut = getUUT(); // Act boolean ret = uut.onTouch(mView, event); // Assert float expectedTransX = (event.getX() - event.getHistoricalX(0)) / DEFAULT_TOUCH_DRAG_MOVE_RATIO_FWD; verify(mView).setTranslationX(expectedTransX); verify(mView, never()).setTranslationY(anyFloat()); assertTrue(ret); }
private void handleActionMove(MotionEvent event) { // Handle all recent motion events so we don't skip any cells even when the device // is busy... final int historySize = event.getHistorySize(); for (int i = 0; i < historySize + 1; i++) { final float x = i < historySize ? event.getHistoricalX(i) : event.getX(); final float y = i < historySize ? event.getHistoricalY(i) : event.getY(); final int patternSizePreHitDetect = mPattern.size(); Cell hitCell = detectAndAddHit(x, y); final int patternSize = mPattern.size(); if (hitCell != null && patternSize == 1) { mPatternInProgress = true; notifyPatternStarted(); } // note current x and y for rubber banding of in progress patterns final float dx = Math.abs(x - mInProgressX); final float dy = Math.abs(y - mInProgressY); if (dx + dy > mSquareWidth * 0.01f) { float oldX = mInProgressX; float oldY = mInProgressY; mInProgressX = x; mInProgressY = y; if (mPatternInProgress && patternSize > 0) { final ArrayList<Cell> pattern = mPattern; final float radius = mSquareWidth * mDiameterFactor * 0.5f; final Cell lastCell = pattern.get(patternSize - 1); float startX = getCenterXForColumn(lastCell.column); float startY = getCenterYForRow(lastCell.row); float left; float top; float right; float bottom; final Rect invalidateRect = mInvalidate; if (startX < x) { left = startX; right = x; } else { left = x; right = startX; } if (startY < y) { top = startY; bottom = y; } else { top = y; bottom = startY; } // Invalidate between the pattern's last cell and the current location invalidateRect.set( (int) (left - radius), (int) (top - radius), (int) (right + radius), (int) (bottom + radius)); if (startX < oldX) { left = startX; right = oldX; } else { left = oldX; right = startX; } if (startY < oldY) { top = startY; bottom = oldY; } else { top = oldY; bottom = startY; } // Invalidate between the pattern's last cell and the previous location invalidateRect.union( (int) (left - radius), (int) (top - radius), (int) (right + radius), (int) (bottom + radius)); // Invalidate between the pattern's new cell and the pattern's previous cell if (hitCell != null) { startX = getCenterXForColumn(hitCell.column); startY = getCenterYForRow(hitCell.row); if (patternSize >= 2) { // (re-using hitcell for old cell) hitCell = pattern.get(patternSize - 1 - (patternSize - patternSizePreHitDetect)); oldX = getCenterXForColumn(hitCell.column); oldY = getCenterYForRow(hitCell.row); if (startX < oldX) { left = startX; right = oldX; } else { left = oldX; right = startX; } if (startY < oldY) { top = startY; bottom = oldY; } else { top = oldY; bottom = startY; } } else { left = right = startX; top = bottom = startY; } final float widthOffset = mSquareWidth / 2f; final float heightOffset = mSquareHeight / 2f; invalidateRect.set( (int) (left - widthOffset), (int) (top - heightOffset), (int) (right + widthOffset), (int) (bottom + heightOffset)); } invalidate(invalidateRect); } else { invalidate(); } } } }
public boolean onTestMove(MotionEvent event) { float xInit = event.getHistoricalX(0); float yInit = event.getHistoricalY(0); float xNow = event.getX(); float yNow = event.getY(); Rect viewRect = new Rect(); if (!isMove) { for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); int left = child.getLeft(); int right = child.getRight(); int top = child.getTop(); int bottom = child.getBottom(); viewRect.set(left, top, right, bottom); if (viewRect.contains((int) xInit, (int) yInit)) { if (yNow > yInit) { Log.d("relache", "pass� in "); if (mOnItemMoveListener != null) { mOnItemMoveListener.onTouch(child, event); this.childSelected = child; } if (mOnItemClicked != null) { mOnItemClicked.onItemClick( HorizontalListView.this, child, mLeftViewIndex + 1 + i, mAdapter.getItemId(mLeftViewIndex + 1 + i)); } isMove = true; return true; } } } } else { mOnItemMoveListener.onTouch(childSelected, event); if (event.getAction() == MotionEvent.ACTION_UP) { int left = this.getLeft(); int right = this.getRight(); int top = this.getTop(); int bottom = this.getBottom(); Rect rect = new Rect(left, top, right, bottom); if (!rect.contains((int) xNow, (int) yNow)) { if (mOnItemOutListener != null) { mOnItemOutListener.onTouch(this.childSelected, event); } } isMove = false; return false; } return true; } return false; }
private void handleMove(MotionEvent event) { int activeTarget = -1; final int historySize = event.getHistorySize(); ArrayList<TargetDrawable> targets = mTargetDrawables; int ntargets = targets.size(); float x = 0.0f; float y = 0.0f; int actionIndex = event.findPointerIndex(mPointerId); if (actionIndex == -1) { return; // no data for this pointer } for (int k = 0; k < historySize + 1; k++) { float eventX = k < historySize ? event.getHistoricalX(actionIndex, k) : event.getX(actionIndex); float eventY = k < historySize ? event.getHistoricalY(actionIndex, k) : event.getY(actionIndex); // tx and ty are relative to wave center float tx = eventX - mWaveCenterX; float ty = eventY - mWaveCenterY; float touchRadius = (float) Math.sqrt(dist2(tx, ty)); final float scale = touchRadius > mOuterRadius ? mOuterRadius / touchRadius : 1.0f; float limitX = tx * scale; float limitY = ty * scale; double angleRad = Math.atan2(-ty, tx); if (!mDragging) { trySwitchToFirstTouchState(eventX, eventY); } if (mDragging) { // For multiple targets, snap to the one that matches final float snapRadius = mRingScaleFactor * mOuterRadius - mSnapMargin; final float snapDistance2 = snapRadius * snapRadius; // Find first target in range for (int i = 0; i < ntargets; i++) { TargetDrawable target = targets.get(i); double targetMinRad = (i - 0.5) * 2 * Math.PI / ntargets; double targetMaxRad = (i + 0.5) * 2 * Math.PI / ntargets; if (target.isEnabled()) { boolean angleMatches = (angleRad > targetMinRad && angleRad <= targetMaxRad) || (angleRad + 2 * Math.PI > targetMinRad && angleRad + 2 * Math.PI <= targetMaxRad); if (angleMatches && (dist2(tx, ty) > snapDistance2)) { activeTarget = i; } } } } x = limitX; y = limitY; } if (!mDragging) { return; } if (activeTarget != -1) { switchToState(STATE_SNAP, x, y); updateGlowPosition(x, y); } else { switchToState(STATE_TRACKING, x, y); updateGlowPosition(x, y); } if (mActiveTarget != activeTarget) { // Defocus the old target if (mActiveTarget != -1) { TargetDrawable target = targets.get(mActiveTarget); target.setState(TargetDrawable.STATE_INACTIVE); } // Focus the new target if (activeTarget != -1) { TargetDrawable target = targets.get(activeTarget); target.setState(TargetDrawable.STATE_FOCUSED); final AccessibilityManager accessibilityManager = (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); if (accessibilityManager.isEnabled()) { String targetContentDescription = getTargetDescription(activeTarget); announceForAccessibility(targetContentDescription); } } } mActiveTarget = activeTarget; }
@Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: downX = event.getX(); downY = event.getY(); if (mPropagateClicks) propagatePressed(true); break; case MotionEvent.ACTION_MOVE: try { if (mPropagateClicks) { float xDeltaTotal = event.getX() - downX; float yDeltaTotal = event.getY() - downY; if (Math.abs(xDeltaTotal) >= CLICK_SENSITIVITY || Math.abs(yDeltaTotal) >= CLICK_SENSITIVITY) { propagatePressed(false); } } float xDelta = event.getX() - downX; float yDelta = event.getY() - downY; if (event.getHistorySize() > 0) { xDelta = event.getX() - event.getHistoricalX(0); yDelta = event.getY() - event.getHistoricalY(0); } if (Math.abs(xDelta) > Math.abs(yDelta)) { if (xDelta > 0 && getCurrentItem() == 0 && mPositionOffset == 0) { return false; } else if (xDelta < 0 && mPositionOffset == 0) { if (getAdapter() != null) { int current = getCurrentItem(); int count = getAdapter().getCount(); if (current >= (count - 1)) { return false; } } } NestedViewPager.this.getParent().requestDisallowInterceptTouchEvent(true); } } catch (Exception e) { // nothing } break; case MotionEvent.ACTION_UP: if (mPropagateClicks) { propagatePressed(false); float xDelta = event.getX() - downX; float yDelta = event.getY() - downY; if (Math.abs(xDelta) < CLICK_SENSITIVITY && Math.abs(yDelta) < CLICK_SENSITIVITY) { propagateClicked(); } } break; } return super.onTouchEvent(event); }