ScrubGestureDetector implements View.OnTouchListener { @Override public boolean onTouch(View v, MotionEvent event) { if (!enabled) return false; final float x = event.getX(); final float y = event.getY(); switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: downX = x; downY = y; handler.postDelayed(longPressRunnable, LONG_PRESS_TIMEOUT_MS); return true; case MotionEvent.ACTION_MOVE: float timeDelta = event.getEventTime() - event.getDownTime(); if (timeDelta >= LONG_PRESS_TIMEOUT_MS) { handler.removeCallbacks(longPressRunnable); scrubListener.onScrubbed(x, y); } else { float deltaX = x - downX; float deltaY = y - downY; if (deltaX >= touchSlop || deltaY >= touchSlop) { handler.removeCallbacks(longPressRunnable); return false; } } return true; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: handler.removeCallbacks(longPressRunnable); scrubListener.onScrubEnded(); return true; default: return false; } } ScrubGestureDetector(
            @NonNull ScrubListener scrubListener,
            @NonNull Handler handler,
            float touchSlop); void setEnabled(boolean enabled); @Override boolean onTouch(View v, MotionEvent event);  }
@Test public void test_moveScrub_success() { final long downTime = 0; final long moveTime = ScrubGestureDetector.LONG_PRESS_TIMEOUT_MS; final float scrubX = TOUCH_SLOP + 1, scrubY = TOUCH_SLOP + 1; final MotionEvent down = getMotionEvent(MotionEvent.ACTION_DOWN, 0, 0, 0, 0); final MotionEvent move = getMotionEvent(MotionEvent.ACTION_MOVE, scrubX, scrubY, moveTime, downTime); final MotionEvent up = getMotionEvent(MotionEvent.ACTION_UP, 0, 0, moveTime, downTime); assertTrue(scrubGestureDetector.onTouch(null, down)); assertTrue(scrubGestureDetector.onTouch(null, move)); assertTrue(scrubGestureDetector.onTouch(null, up)); verify(scrubListener).onScrubbed(scrubX, scrubY); verify(scrubListener).onScrubEnded(); verifyNoMoreInteractions(scrubListener); }
@Test public void test_moveScrub_waiting() { final long downTime = 0; final long moveTime = ScrubGestureDetector.LONG_PRESS_TIMEOUT_MS - 1; final float scrubX = TOUCH_SLOP - 1, scrubY = TOUCH_SLOP - 1; final MotionEvent down = getMotionEvent(MotionEvent.ACTION_DOWN, 0, 0, 0, 0); final MotionEvent move = getMotionEvent(MotionEvent.ACTION_MOVE, scrubX, scrubY, moveTime, downTime); assertTrue(scrubGestureDetector.onTouch(null, down)); assertTrue(scrubGestureDetector.onTouch(null, move)); verifyNoMoreInteractions(scrubListener); }
@Test public void test_moveScrub_failure() { final long downTime = 0; final long moveTime = ScrubGestureDetector.LONG_PRESS_TIMEOUT_MS - 1; final float scrubX = 9, scrubY = 9; final MotionEvent down = getMotionEvent(MotionEvent.ACTION_DOWN, 0, 0, 0, 0); final MotionEvent move = getMotionEvent(MotionEvent.ACTION_MOVE, scrubX, scrubY, moveTime, downTime); assertTrue(scrubGestureDetector.onTouch(null, down)); assertFalse(scrubGestureDetector.onTouch(null, move)); verifyNoMoreInteractions(scrubListener); }
@Test public void test_timeScrub_success() { when(handler.postDelayed(any(Runnable.class), anyLong())).then(new Answer<Boolean>() { @Override public Boolean answer(InvocationOnMock invocation) throws Throwable { Runnable r = (Runnable) invocation.getArguments()[0]; r.run(); return true; } }); float scrubX = 10, scrubY = 10; MotionEvent down = getMotionEvent(MotionEvent.ACTION_DOWN, scrubX, scrubY, 0, 0); assertTrue(scrubGestureDetector.onTouch(null, down)); verify(scrubListener).onScrubbed(scrubX, scrubY); verifyNoMoreInteractions(scrubListener); }