1 // Copyright 2014 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.test.InstrumentationTestCase; 8 import android.test.suitebuilder.annotation.SmallTest; 9 import android.view.MotionEvent; 10 import android.view.ViewConfiguration; 11 12 import org.chromium.base.ThreadUtils; 13 import org.chromium.base.test.util.Feature; 14 15 /** Tests for {@link TapGestureDetector}. */ 16 public class TapGestureDetectorTest extends InstrumentationTestCase { 17 private static class MockListener implements TapGestureDetector.OnTapListener { 18 int mTapCount = -1; 19 int mLongPressCount = -1; 20 21 @Override 22 public boolean onTap(int pointerCount) { 23 assertEquals(-1, mTapCount); 24 mTapCount = pointerCount; 25 return true; 26 } 27 28 @Override 29 public void onLongPress(int pointerCount) { 30 assertEquals(-1, mLongPressCount); 31 mLongPressCount = pointerCount; 32 } 33 34 /** Resets the mock listener to its initial state. */ 35 public void reset() { 36 mTapCount = -1; 37 mLongPressCount = -1; 38 } 39 40 public void assertTapDetected(int expectedCount) { 41 assertEquals(expectedCount, mTapCount); 42 assertEquals(-1, mLongPressCount); 43 } 44 45 public void assertLongPressDetected(int expectedCount) { 46 assertEquals(expectedCount, mLongPressCount); 47 assertEquals(-1, mTapCount); 48 } 49 50 public void assertNothingDetected() { 51 assertEquals(-1, mTapCount); 52 assertEquals(-1, mLongPressCount); 53 } 54 } 55 56 private TapGestureDetector mDetector; 57 private MockListener mListener; 58 private TouchEventGenerator mEventGenerator; 59 60 /** Injects movement of a single finger (keeping other fingers in place). */ 61 private void injectMoveEvent(int id, float x, float y) { 62 MotionEvent event = mEventGenerator.obtainMoveEvent(id, x, y); 63 mDetector.onTouchEvent(event); 64 event.recycle(); 65 } 66 67 /** Injects a finger-down event (keeping other fingers in place). */ 68 private void injectDownEvent(int id, float x, float y) { 69 MotionEvent event = mEventGenerator.obtainDownEvent(id, x, y); 70 mDetector.onTouchEvent(event); 71 event.recycle(); 72 } 73 74 /** Injects a finger-up event (keeping other fingers in place). */ 75 private void injectUpEvent(int id) { 76 MotionEvent event = mEventGenerator.obtainUpEvent(id); 77 mDetector.onTouchEvent(event); 78 event.recycle(); 79 } 80 81 @Override 82 public void setUp() { 83 mListener = new MockListener(); 84 mDetector = new TapGestureDetector(getInstrumentation().getTargetContext(), mListener); 85 mEventGenerator = new TouchEventGenerator(); 86 } 87 88 /** Verifies that a simple down/up is detected as a tap. */ 89 @SmallTest 90 @Feature({"Chromoting"}) 91 public void testOneFingerDownUp() throws Exception { 92 injectDownEvent(0, 0, 0); 93 injectUpEvent(0); 94 mListener.assertTapDetected(1); 95 } 96 97 /** Verifies that a simple multi-finger down/up is detected as a tap. */ 98 @SmallTest 99 @Feature({"Chromoting"}) 100 public void testMultipleFingerDownUp() throws Exception { 101 injectDownEvent(0, 0, 0); 102 injectDownEvent(1, 100, 100); 103 injectDownEvent(2, 200, 200); 104 injectUpEvent(0); 105 injectUpEvent(1); 106 injectUpEvent(2); 107 mListener.assertTapDetected(3); 108 } 109 110 /** Verifies that a multi-finger tap is detected when lifting the fingers in reverse order. */ 111 @SmallTest 112 @Feature({"Chromoting"}) 113 public void testMultipleFingerDownUpReversed() throws Exception { 114 injectDownEvent(0, 0, 0); 115 injectDownEvent(1, 100, 100); 116 injectDownEvent(2, 200, 200); 117 injectUpEvent(2); 118 injectUpEvent(1); 119 injectUpEvent(0); 120 mListener.assertTapDetected(3); 121 } 122 123 /** Verifies that small movement of multiple fingers is still detected as a tap. */ 124 @SmallTest 125 @Feature({"Chromoting"}) 126 public void testMultipleFingerSmallMovements() throws Exception { 127 injectDownEvent(0, 0, 0); 128 injectDownEvent(1, 100, 100); 129 injectDownEvent(2, 200, 200); 130 injectMoveEvent(0, 1, 1); 131 injectMoveEvent(1, 101, 101); 132 injectMoveEvent(2, 202, 202); 133 injectUpEvent(0); 134 injectUpEvent(1); 135 injectUpEvent(2); 136 mListener.assertTapDetected(3); 137 } 138 139 /** Verifies that large motion of a finger prevents a tap being detected. */ 140 @SmallTest 141 @Feature({"Chromoting"}) 142 public void testLargeMotion() throws Exception { 143 injectDownEvent(0, 0, 0); 144 injectDownEvent(1, 100, 100); 145 injectDownEvent(2, 200, 200); 146 injectMoveEvent(1, 300, 300); 147 injectUpEvent(0); 148 injectUpEvent(1); 149 injectUpEvent(2); 150 mListener.assertNothingDetected(); 151 } 152 153 /** Verifies that a long-press is detected. */ 154 @SmallTest 155 @Feature({"Chromoting"}) 156 public void testLongPress() throws Exception { 157 ThreadUtils.runOnUiThreadBlocking(new Runnable() { 158 public void run() { 159 // Ensure the gesture-detector is created on the UI thread, so that it uses the 160 // Handler for the UI thread for LongPress notifications. 161 mDetector = new TapGestureDetector( 162 getInstrumentation().getTargetContext(), mListener); 163 164 injectDownEvent(0, 0, 0); 165 } 166 }); 167 168 Thread.sleep(2 * ViewConfiguration.getLongPressTimeout()); 169 170 ThreadUtils.runOnUiThreadBlocking(new Runnable() { 171 public void run() { 172 injectUpEvent(0); 173 } 174 }); 175 176 mListener.assertLongPressDetected(1); 177 } 178 } 179