Home | History | Annotate | Download | only in chromoting
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 package org.chromium.chromoting;
      6 
      7 import android.content.Context;
      8 import android.os.SystemClock;
      9 import android.test.InstrumentationTestCase;
     10 import android.test.suitebuilder.annotation.SmallTest;
     11 import android.view.InputDevice;
     12 import android.view.MotionEvent;
     13 import android.view.ViewConfiguration;
     14 
     15 import org.chromium.base.test.util.Feature;
     16 
     17 /** Tests for {@link SwipePinchDetector}. */
     18 public class SwipePinchDetectorTest extends InstrumentationTestCase {
     19     private SwipePinchDetector mDetector;
     20     private float mTouchSlop;
     21     private MotionEvent.PointerProperties[] mPointers;
     22 
     23     // Stores the current finger positions, for convenience in writing tests. These values are
     24     // initialized during setUp().
     25     private MotionEvent.PointerCoords[] mCurrentPositions;
     26 
     27     @Override
     28     public void setUp() {
     29         Context context = getInstrumentation().getTargetContext();
     30         mDetector = new SwipePinchDetector(context);
     31         mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
     32         MotionEvent.PointerProperties pointer0 = new MotionEvent.PointerProperties();
     33         pointer0.id = 0;
     34         MotionEvent.PointerProperties pointer1 = new MotionEvent.PointerProperties();
     35         pointer1.id = 1;
     36         mPointers = new MotionEvent.PointerProperties[] {pointer0, pointer1};
     37 
     38         MotionEvent.PointerCoords position0 = new MotionEvent.PointerCoords();
     39         MotionEvent.PointerCoords position1 = new MotionEvent.PointerCoords();
     40         mCurrentPositions = new MotionEvent.PointerCoords[] {position0, position1};
     41 
     42         // The starting points are arbitrary, but non-zero to ensure that the tests detect relative,
     43         // not absolute, motion.
     44         mCurrentPositions[0].x = 100;
     45         mCurrentPositions[0].y = 200;
     46         mCurrentPositions[1].x = 300;
     47         mCurrentPositions[1].y = 400;
     48     }
     49 
     50     /**
     51      * Simulates a 2-finger event. The action parameter should be MotionEvent.ACTION_POINTER_DOWN,
     52      * MotionEvent.ACTION_MOVE or MotionEvent.ACTION_POINTER_UP.
     53      */
     54     private void injectEvent(int action) {
     55         final long eventTime = SystemClock.uptimeMillis();
     56         MotionEvent event = MotionEvent.obtain(eventTime, eventTime, action, 2, mPointers,
     57                 mCurrentPositions, 0, 0, 1, 1, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
     58         mDetector.onTouchEvent(event);
     59     }
     60 
     61     /** Verifies that a simple swipe gesture is recognized as a swipe. */
     62     @SmallTest
     63     @Feature({"Chromoting"})
     64     public void testSwipeRecognition() throws Exception {
     65         injectEvent(MotionEvent.ACTION_POINTER_DOWN);
     66         assertFalse(mDetector.isSwiping());
     67         assertFalse(mDetector.isPinching());
     68 
     69         // Any distance greater than the touch-slop threshold should work.
     70         mCurrentPositions[0].y += mTouchSlop * 2;
     71         mCurrentPositions[1].y += mTouchSlop * 2;
     72         injectEvent(MotionEvent.ACTION_MOVE);
     73         assertTrue(mDetector.isSwiping());
     74         assertFalse(mDetector.isPinching());
     75     }
     76 
     77     /** Verifies that a simple pinch gesture is recognized. */
     78     @SmallTest
     79     @Feature({"Chromoting"})
     80     public void testPinchRecognition() throws Exception {
     81         injectEvent(MotionEvent.ACTION_POINTER_DOWN);
     82         assertFalse(mDetector.isSwiping());
     83         assertFalse(mDetector.isPinching());
     84 
     85         // Any distance greater than the touch-slop threshold should work.
     86         mCurrentPositions[0].x -= mTouchSlop * 2;
     87         mCurrentPositions[1].x += mTouchSlop * 2;
     88         injectEvent(MotionEvent.ACTION_MOVE);
     89         assertFalse(mDetector.isSwiping());
     90         assertTrue(mDetector.isPinching());
     91     }
     92 
     93     /** Verifies that motion less than touch-slop does not trigger anything. */
     94     @SmallTest
     95     @Feature({"Chromoting"})
     96     public void testNoMotion() throws Exception {
     97         injectEvent(MotionEvent.ACTION_POINTER_DOWN);
     98         mCurrentPositions[0].x += mTouchSlop / 2;
     99         mCurrentPositions[0].y += mTouchSlop / 2;
    100         mCurrentPositions[1].x -= mTouchSlop / 2;
    101         mCurrentPositions[1].y -= mTouchSlop / 2;
    102         injectEvent(MotionEvent.ACTION_MOVE);
    103         assertFalse(mDetector.isSwiping());
    104         assertFalse(mDetector.isPinching());
    105     }
    106 
    107     /** Verifies that a pinch with one finger stationary is detected. */
    108     @SmallTest
    109     @Feature({"Chromoting"})
    110     public void testOneFingerStationary() throws Exception {
    111         injectEvent(MotionEvent.ACTION_POINTER_DOWN);
    112 
    113         // The triggering threshold in this case (one finger stationary) is mTouchSlop * 2;
    114         mCurrentPositions[1].x += mTouchSlop * 3;
    115         injectEvent(MotionEvent.ACTION_MOVE);
    116         assertFalse(mDetector.isSwiping());
    117         assertTrue(mDetector.isPinching());
    118 
    119         // Do the same test for the other finger.
    120         injectEvent(MotionEvent.ACTION_POINTER_DOWN);
    121         mCurrentPositions[0].x += mTouchSlop * 3;
    122         injectEvent(MotionEvent.ACTION_MOVE);
    123         assertFalse(mDetector.isSwiping());
    124         assertTrue(mDetector.isPinching());
    125     }
    126 
    127     /**
    128      * Verifies that a pinch is recognized, when the fingers cross the motion threshold at
    129      * different times.
    130      */
    131     @SmallTest
    132     @Feature({"Chromoting"})
    133     public void testUnevenPinch() throws Exception {
    134         injectEvent(MotionEvent.ACTION_POINTER_DOWN);
    135         for (int i = 0; i < 50; i++) {
    136             mCurrentPositions[0].x -= 2;
    137             mCurrentPositions[1].x += 3;
    138             injectEvent(MotionEvent.ACTION_MOVE);
    139         }
    140 
    141         assertFalse(mDetector.isSwiping());
    142         assertTrue(mDetector.isPinching());
    143     }
    144 
    145     /** Same test as testUnevenPinch() except the slow/fast fingers are reversed. */
    146     @SmallTest
    147     @Feature({"Chromoting"})
    148     public void testUnevenPinch2() throws Exception {
    149         injectEvent(MotionEvent.ACTION_POINTER_DOWN);
    150         for (int i = 0; i < 50; i++) {
    151             mCurrentPositions[0].x -= 3;
    152             mCurrentPositions[1].x += 2;
    153             injectEvent(MotionEvent.ACTION_MOVE);
    154         }
    155 
    156         assertFalse(mDetector.isSwiping());
    157         assertTrue(mDetector.isPinching());
    158     }
    159 
    160     /** Verifies that a swipe is recognized, even if the fingers move at different rates. */
    161     @SmallTest
    162     @Feature({"Chromoting"})
    163     public void testUnevenSwipe() throws Exception {
    164         injectEvent(MotionEvent.ACTION_POINTER_DOWN);
    165         for (int i = 0; i < 50; i++) {
    166             // The fingers need to move similarly enough so that one finger moves a distance of
    167             // 2 * mTouchSlop after the other finger moves a distance of mTouchSlop.
    168             // Otherwise the gesture would be mis-detected as a one-finger-stationary pinch.
    169             mCurrentPositions[0].y += 2;
    170             mCurrentPositions[1].y += 3;
    171             injectEvent(MotionEvent.ACTION_MOVE);
    172         }
    173 
    174         assertTrue(mDetector.isSwiping());
    175         assertFalse(mDetector.isPinching());
    176     }
    177 
    178     /** Same test as testUnevenSwipe() except the slow/fast fingers are reversed. */
    179     @SmallTest
    180     @Feature({"Chromoting"})
    181     public void testUnevenSwipe2() throws Exception {
    182         injectEvent(MotionEvent.ACTION_POINTER_DOWN);
    183         for (int i = 0; i < 50; i++) {
    184             // The fingers need to move similarly enough so that one finger moves a distance of
    185             // 2 * mTouchSlop after the other finger moves a distance of mTouchSlop.
    186             // Otherwise the gesture would be mis-detected as a one-finger-stationary pinch.
    187             mCurrentPositions[0].y += 3;
    188             mCurrentPositions[1].y += 2;
    189             injectEvent(MotionEvent.ACTION_MOVE);
    190         }
    191 
    192         assertTrue(mDetector.isSwiping());
    193         assertFalse(mDetector.isPinching());
    194     }
    195 
    196     /** Verifies that the detector is reset when a gesture terminates or a new gesture begins. */
    197     @SmallTest
    198     @Feature({"Chromoting"})
    199     public void testDetectorReset() throws Exception {
    200         injectEvent(MotionEvent.ACTION_POINTER_DOWN);
    201         mCurrentPositions[0].x += mTouchSlop * 3;
    202         injectEvent(MotionEvent.ACTION_MOVE);
    203         assertTrue(mDetector.isPinching());
    204 
    205         // ACTION_POINTER_UP should terminate the gesture.
    206         injectEvent(MotionEvent.ACTION_POINTER_UP);
    207         assertFalse(mDetector.isPinching());
    208 
    209         // Repeat the same test, but use ACTION_POINTER_DOWN to start a new gesture, which should
    210         // terminate the current one.
    211         injectEvent(MotionEvent.ACTION_POINTER_DOWN);
    212         mCurrentPositions[0].x += mTouchSlop * 3;
    213         injectEvent(MotionEvent.ACTION_MOVE);
    214         assertTrue(mDetector.isPinching());
    215         injectEvent(MotionEvent.ACTION_POINTER_DOWN);
    216         assertFalse(mDetector.isPinching());
    217     }
    218 }
    219