blob: 85a1b1eb6aacaa93717ead65d1886da4eb7dad0d [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chromoting;
import android.content.Context;
import android.os.SystemClock;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.chromium.base.test.BaseJUnit4ClassRunner;
import org.chromium.base.test.util.Feature;
/** Tests for {@link SwipePinchDetector}. */
@RunWith(BaseJUnit4ClassRunner.class)
public class SwipePinchDetectorTest {
private SwipePinchDetector mDetector;
private float mTouchSlop;
private MotionEvent.PointerProperties[] mPointers;
// Stores the current finger positions, for convenience in writing tests. These values are
// initialized during setUp().
private MotionEvent.PointerCoords[] mCurrentPositions;
@Before
public void setUp() {
Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
mDetector = new SwipePinchDetector(context);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
MotionEvent.PointerProperties pointer0 = new MotionEvent.PointerProperties();
pointer0.id = 0;
MotionEvent.PointerProperties pointer1 = new MotionEvent.PointerProperties();
pointer1.id = 1;
mPointers = new MotionEvent.PointerProperties[] {pointer0, pointer1};
MotionEvent.PointerCoords position0 = new MotionEvent.PointerCoords();
MotionEvent.PointerCoords position1 = new MotionEvent.PointerCoords();
mCurrentPositions = new MotionEvent.PointerCoords[] {position0, position1};
// The starting points are arbitrary, but non-zero to ensure that the tests detect relative,
// not absolute, motion.
mCurrentPositions[0].x = 100;
mCurrentPositions[0].y = 200;
mCurrentPositions[1].x = 300;
mCurrentPositions[1].y = 400;
}
/**
* Simulates a 2-finger event. The action parameter should be MotionEvent.ACTION_POINTER_DOWN,
* MotionEvent.ACTION_MOVE or MotionEvent.ACTION_POINTER_UP.
*/
private void injectEvent(int action) {
final long eventTime = SystemClock.uptimeMillis();
MotionEvent event = MotionEvent.obtain(eventTime, eventTime, action, 2, mPointers,
mCurrentPositions, 0, 0, 1, 1, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
mDetector.onTouchEvent(event);
}
/** Verifies that a simple swipe gesture is recognized as a swipe. */
@Test
@SmallTest
@Feature({"Chromoting"})
public void testSwipeRecognition() throws Exception {
injectEvent(MotionEvent.ACTION_POINTER_DOWN);
Assert.assertFalse(mDetector.isSwiping());
Assert.assertFalse(mDetector.isPinching());
// Any distance greater than the touch-slop threshold should work.
mCurrentPositions[0].y += mTouchSlop * 2;
mCurrentPositions[1].y += mTouchSlop * 2;
injectEvent(MotionEvent.ACTION_MOVE);
Assert.assertTrue(mDetector.isSwiping());
Assert.assertFalse(mDetector.isPinching());
}
/** Verifies that a simple pinch gesture is recognized. */
@Test
@SmallTest
@Feature({"Chromoting"})
public void testPinchRecognition() throws Exception {
injectEvent(MotionEvent.ACTION_POINTER_DOWN);
Assert.assertFalse(mDetector.isSwiping());
Assert.assertFalse(mDetector.isPinching());
// Any distance greater than the touch-slop threshold should work.
mCurrentPositions[0].x -= mTouchSlop * 2;
mCurrentPositions[1].x += mTouchSlop * 2;
injectEvent(MotionEvent.ACTION_MOVE);
Assert.assertFalse(mDetector.isSwiping());
Assert.assertTrue(mDetector.isPinching());
}
/** Verifies that motion less than touch-slop does not trigger anything. */
@Test
@SmallTest
@Feature({"Chromoting"})
public void testNoMotion() throws Exception {
injectEvent(MotionEvent.ACTION_POINTER_DOWN);
mCurrentPositions[0].x += mTouchSlop / 2;
mCurrentPositions[0].y += mTouchSlop / 2;
mCurrentPositions[1].x -= mTouchSlop / 2;
mCurrentPositions[1].y -= mTouchSlop / 2;
injectEvent(MotionEvent.ACTION_MOVE);
Assert.assertFalse(mDetector.isSwiping());
Assert.assertFalse(mDetector.isPinching());
}
/** Verifies that a pinch with one finger stationary is detected. */
@Test
@SmallTest
@Feature({"Chromoting"})
public void testOneFingerStationary() throws Exception {
injectEvent(MotionEvent.ACTION_POINTER_DOWN);
// The triggering threshold in this case (one finger stationary) is mTouchSlop * 2;
mCurrentPositions[1].x += mTouchSlop * 3;
injectEvent(MotionEvent.ACTION_MOVE);
Assert.assertFalse(mDetector.isSwiping());
Assert.assertTrue(mDetector.isPinching());
// Do the same test for the other finger.
injectEvent(MotionEvent.ACTION_POINTER_DOWN);
mCurrentPositions[0].x += mTouchSlop * 3;
injectEvent(MotionEvent.ACTION_MOVE);
Assert.assertFalse(mDetector.isSwiping());
Assert.assertTrue(mDetector.isPinching());
}
/**
* Verifies that a pinch is recognized, when the fingers cross the motion threshold at
* different times.
*/
@Test
@SmallTest
@Feature({"Chromoting"})
public void testUnevenPinch() throws Exception {
injectEvent(MotionEvent.ACTION_POINTER_DOWN);
for (int i = 0; i < 50; i++) {
mCurrentPositions[0].x -= 2;
mCurrentPositions[1].x += 3;
injectEvent(MotionEvent.ACTION_MOVE);
}
Assert.assertFalse(mDetector.isSwiping());
Assert.assertTrue(mDetector.isPinching());
}
/** Same test as testUnevenPinch() except the slow/fast fingers are reversed. */
@Test
@SmallTest
@Feature({"Chromoting"})
public void testUnevenPinch2() throws Exception {
injectEvent(MotionEvent.ACTION_POINTER_DOWN);
for (int i = 0; i < 50; i++) {
mCurrentPositions[0].x -= 3;
mCurrentPositions[1].x += 2;
injectEvent(MotionEvent.ACTION_MOVE);
}
Assert.assertFalse(mDetector.isSwiping());
Assert.assertTrue(mDetector.isPinching());
}
/** Verifies that a swipe is recognized, even if the fingers move at different rates. */
@Test
@SmallTest
@Feature({"Chromoting"})
public void testUnevenSwipe() throws Exception {
injectEvent(MotionEvent.ACTION_POINTER_DOWN);
for (int i = 0; i < 50; i++) {
// The fingers need to move similarly enough so that one finger moves a distance of
// 2 * mTouchSlop after the other finger moves a distance of mTouchSlop.
// Otherwise the gesture would be mis-detected as a one-finger-stationary pinch.
mCurrentPositions[0].y += 2;
mCurrentPositions[1].y += 3;
injectEvent(MotionEvent.ACTION_MOVE);
}
Assert.assertTrue(mDetector.isSwiping());
Assert.assertFalse(mDetector.isPinching());
}
/** Same test as testUnevenSwipe() except the slow/fast fingers are reversed. */
@Test
@SmallTest
@Feature({"Chromoting"})
public void testUnevenSwipe2() throws Exception {
injectEvent(MotionEvent.ACTION_POINTER_DOWN);
for (int i = 0; i < 50; i++) {
// The fingers need to move similarly enough so that one finger moves a distance of
// 2 * mTouchSlop after the other finger moves a distance of mTouchSlop.
// Otherwise the gesture would be mis-detected as a one-finger-stationary pinch.
mCurrentPositions[0].y += 3;
mCurrentPositions[1].y += 2;
injectEvent(MotionEvent.ACTION_MOVE);
}
Assert.assertTrue(mDetector.isSwiping());
Assert.assertFalse(mDetector.isPinching());
}
/** Verifies that the detector is reset when a gesture terminates or a new gesture begins. */
@Test
@SmallTest
@Feature({"Chromoting"})
public void testDetectorReset() throws Exception {
injectEvent(MotionEvent.ACTION_POINTER_DOWN);
mCurrentPositions[0].x += mTouchSlop * 3;
injectEvent(MotionEvent.ACTION_MOVE);
Assert.assertTrue(mDetector.isPinching());
// ACTION_POINTER_UP should terminate the gesture.
injectEvent(MotionEvent.ACTION_POINTER_UP);
Assert.assertFalse(mDetector.isPinching());
// Repeat the same test, but use ACTION_POINTER_DOWN to start a new gesture, which should
// terminate the current one.
injectEvent(MotionEvent.ACTION_POINTER_DOWN);
mCurrentPositions[0].x += mTouchSlop * 3;
injectEvent(MotionEvent.ACTION_MOVE);
Assert.assertTrue(mDetector.isPinching());
injectEvent(MotionEvent.ACTION_POINTER_DOWN);
Assert.assertFalse(mDetector.isPinching());
}
}