/*
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.drawee.gestures;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import com.facebook.testing.robolectric.v2.WithTestDefaultsRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import static android.view.MotionEvent.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
/**
* Tests for {@link GestureDetector}
*/
@RunWith(WithTestDefaultsRunner.class)
public class GestureDetectorTest {
private GestureDetector.ClickListener mClickListener;
private ViewConfiguration mViewConfiguration;
private long mScaledTouchSlop;
private long mLongPressTimeout;
private GestureDetector mGestureDetector;
@Before
public void setup() {
mClickListener = mock(GestureDetector.ClickListener.class);
mViewConfiguration = ViewConfiguration.get(Robolectric.application);
mScaledTouchSlop = mViewConfiguration.getScaledTouchSlop();
mLongPressTimeout = mViewConfiguration.getLongPressTimeout();
mGestureDetector = new GestureDetector(Robolectric.application);
mGestureDetector.setClickListener(mClickListener);
}
@Test
public void testInitialstate() {
assertEquals(mScaledTouchSlop, mGestureDetector.mSingleTapSlopPx, 0f);
assertEquals(false, mGestureDetector.mIsCapturingGesture);
assertEquals(false, mGestureDetector.mIsClickCandidate);
}
@Test
public void testSetClickListener() {
GestureDetector.ClickListener clickListener = mock(GestureDetector.ClickListener.class);
mGestureDetector.setClickListener(clickListener);
assertSame(clickListener, mGestureDetector.mClickListener);
mGestureDetector.setClickListener(null);
assertSame(null, mGestureDetector.mClickListener);
}
@Test
public void testOnClick_NoListener() {
MotionEvent event1 = obtain(1000, 1000, ACTION_DOWN, 100.f, 100.f, 0);
MotionEvent event2 = obtain(1000, 1001, ACTION_UP, 100.f, 100.f, 0);
mGestureDetector.setClickListener(mClickListener);
mGestureDetector.onTouchEvent(event1);
mGestureDetector.onTouchEvent(event2);
verify(mClickListener).onClick();
mGestureDetector.setClickListener(null);
mGestureDetector.onTouchEvent(event1);
mGestureDetector.onTouchEvent(event2);
verifyNoMoreInteractions(mClickListener);
event1.recycle();
event2.recycle();
}
@Test
public void testOnClick_Valid() {
float s = mScaledTouchSlop;
long T0 = 1000;
long T1 = T0;
MotionEvent event1 = obtain(T0, T1, ACTION_DOWN, 100.f, 100.f, 0);
mGestureDetector.onTouchEvent(event1);
assertEquals(true, mGestureDetector.mIsCapturingGesture);
assertEquals(true, mGestureDetector.mIsClickCandidate);
assertEquals(event1.getEventTime(), mGestureDetector.mActionDownTime);
assertEquals(event1.getX(), mGestureDetector.mActionDownX, 0f);
assertEquals(event1.getY(), mGestureDetector.mActionDownY, 0f);
long T2 = T0 + mLongPressTimeout * 1 / 3;
MotionEvent event2 = obtain(T0, T2, ACTION_MOVE, 100.f + s * 0.3f, 100.f - s * 0.3f, 0);
mGestureDetector.onTouchEvent(event2);
assertEquals(true, mGestureDetector.mIsCapturingGesture);
assertEquals(true, mGestureDetector.mIsClickCandidate);
assertEquals(event1.getEventTime(), mGestureDetector.mActionDownTime);
assertEquals(event1.getX(), mGestureDetector.mActionDownX, 0f);
assertEquals(event1.getY(), mGestureDetector.mActionDownY, 0f);
long T3 = T0 + mLongPressTimeout * 2 / 3;
MotionEvent event3 = obtain(T0, T3, ACTION_MOVE, 100.f + s * 0.6f, 100.f - s * 0.6f, 0);
mGestureDetector.onTouchEvent(event3);
assertEquals(true, mGestureDetector.mIsCapturingGesture);
assertEquals(true, mGestureDetector.mIsClickCandidate);
assertEquals(event1.getEventTime(), mGestureDetector.mActionDownTime);
assertEquals(event1.getX(), mGestureDetector.mActionDownX, 0f);
assertEquals(event1.getY(), mGestureDetector.mActionDownY, 0f);
long T4 = T0 + mLongPressTimeout;
MotionEvent event4 = obtain(T0, T4, ACTION_UP, 100.f + s, 100.f - s, 0);
mGestureDetector.onTouchEvent(event4);
assertEquals(false, mGestureDetector.mIsCapturingGesture);
assertEquals(false, mGestureDetector.mIsClickCandidate);
assertEquals(event1.getEventTime(), mGestureDetector.mActionDownTime);
assertEquals(event1.getX(), mGestureDetector.mActionDownX, 0f);
assertEquals(event1.getY(), mGestureDetector.mActionDownY, 0f);
verify(mClickListener).onClick();
event1.recycle();
event2.recycle();
event3.recycle();
event4.recycle();
}
@Test
public void testOnClick_ToFar() {
float s = mScaledTouchSlop;
long T0 = 1000;
long T1 = T0;
MotionEvent event1 = obtain(T0, T1, ACTION_DOWN, 100.f, 100.f, 0);
mGestureDetector.onTouchEvent(event1);
assertEquals(true, mGestureDetector.mIsCapturingGesture);
assertEquals(true, mGestureDetector.mIsClickCandidate);
assertEquals(event1.getEventTime(), mGestureDetector.mActionDownTime);
assertEquals(event1.getX(), mGestureDetector.mActionDownX, 0f);
assertEquals(event1.getY(), mGestureDetector.mActionDownY, 0f);
long T2 = T0 + mLongPressTimeout * 1 / 3;
MotionEvent event2 = obtain(T0, T2, ACTION_MOVE, 100.f + s * 0.5f, 100.f - s * 0.5f, 0);
mGestureDetector.onTouchEvent(event2);
assertEquals(true, mGestureDetector.mIsCapturingGesture);
assertEquals(true, mGestureDetector.mIsClickCandidate);
assertEquals(event1.getEventTime(), mGestureDetector.mActionDownTime);
assertEquals(event1.getX(), mGestureDetector.mActionDownX, 0f);
assertEquals(event1.getY(), mGestureDetector.mActionDownY, 0f);
// maximum allowed distance is `s` px, but here we went `s * 1.1` px away from down point
long T3 = T0 + mLongPressTimeout * 2 / 3;
MotionEvent event3 = obtain(T0, T3, ACTION_MOVE, 100.f + s * 1.1f, 100.f - s * 0.5f, 0);
mGestureDetector.onTouchEvent(event3);
assertEquals(true, mGestureDetector.mIsCapturingGesture);
assertEquals(false, mGestureDetector.mIsClickCandidate);
assertEquals(event1.getEventTime(), mGestureDetector.mActionDownTime);
assertEquals(event1.getX(), mGestureDetector.mActionDownX, 0f);
assertEquals(event1.getY(), mGestureDetector.mActionDownY, 0f);
long T4 = T0 + mLongPressTimeout;
MotionEvent event4 = obtain(T0, T4, ACTION_UP, 100.f + s, 100.f - s, 0);
mGestureDetector.onTouchEvent(event4);
assertEquals(false, mGestureDetector.mIsCapturingGesture);
assertEquals(false, mGestureDetector.mIsClickCandidate);
assertEquals(event1.getEventTime(), mGestureDetector.mActionDownTime);
assertEquals(event1.getX(), mGestureDetector.mActionDownX, 0f);
assertEquals(event1.getY(), mGestureDetector.mActionDownY, 0f);
verifyNoMoreInteractions(mClickListener);
event1.recycle();
event2.recycle();
event3.recycle();
event4.recycle();
}
@Test
public void testOnClick_ToLong() {
float s = mScaledTouchSlop;
long T0 = 1000;
long T1 = T0;
MotionEvent event1 = obtain(T0, T1, ACTION_DOWN, 100.f, 100.f, 0);
mGestureDetector.onTouchEvent(event1);
assertEquals(true, mGestureDetector.mIsCapturingGesture);
assertEquals(true, mGestureDetector.mIsClickCandidate);
assertEquals(event1.getEventTime(), mGestureDetector.mActionDownTime);
assertEquals(event1.getX(), mGestureDetector.mActionDownX, 0f);
assertEquals(event1.getY(), mGestureDetector.mActionDownY, 0f);
long T2 = T0 + mLongPressTimeout * 1 / 3;
MotionEvent event2 = obtain(T0, T2, ACTION_MOVE, 100.f + s * 0.3f, 100.f - s * 0.3f, 0);
mGestureDetector.onTouchEvent(event2);
assertEquals(true, mGestureDetector.mIsCapturingGesture);
assertEquals(true, mGestureDetector.mIsClickCandidate);
assertEquals(event1.getEventTime(), mGestureDetector.mActionDownTime);
assertEquals(event1.getX(), mGestureDetector.mActionDownX, 0f);
assertEquals(event1.getY(), mGestureDetector.mActionDownY, 0f);
long T3 = T0 + mLongPressTimeout * 2 / 3;
MotionEvent event3 = obtain(T0, T3, ACTION_MOVE, 100.f + s * 0.6f, 100.f - s * 0.6f, 0);
mGestureDetector.onTouchEvent(event3);
assertEquals(true, mGestureDetector.mIsCapturingGesture);
assertEquals(true, mGestureDetector.mIsClickCandidate);
assertEquals(event1.getEventTime(), mGestureDetector.mActionDownTime);
assertEquals(event1.getX(), mGestureDetector.mActionDownX, 0f);
assertEquals(event1.getY(), mGestureDetector.mActionDownY, 0f);
// maximum allowed duration is mLongPressTimeout ms, but here we released 1 ms after that
long T4 = T0 + mLongPressTimeout + 1;
MotionEvent event4 = obtain(T0, T4, ACTION_UP, 100.f + s, 100.f - s, 0);
mGestureDetector.onTouchEvent(event4);
assertEquals(false, mGestureDetector.mIsCapturingGesture);
assertEquals(false, mGestureDetector.mIsClickCandidate);
assertEquals(event1.getEventTime(), mGestureDetector.mActionDownTime);
assertEquals(event1.getX(), mGestureDetector.mActionDownX, 0f);
assertEquals(event1.getY(), mGestureDetector.mActionDownY, 0f);
verifyNoMoreInteractions(mClickListener);
event1.recycle();
event2.recycle();
event3.recycle();
event4.recycle();
}
}