summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorHyunyoung Song <hyunyoungs@google.com>2017-07-06 12:35:55 -0700
committerHyunyoung Song <hyunyoungs@google.com>2017-07-06 14:32:35 -0700
commitf40e94955cba0ca351f587358b9e07496d132a1b (patch)
treeada5929c818f0fb9db689af4154bd144d7c39ab6 /tests
parent19b3165c890ecb897a2c3f519db78aba1b5d64df (diff)
downloadandroid_packages_apps_Trebuchet-f40e94955cba0ca351f587358b9e07496d132a1b.tar.gz
android_packages_apps_Trebuchet-f40e94955cba0ca351f587358b9e07496d132a1b.tar.bz2
android_packages_apps_Trebuchet-f40e94955cba0ca351f587358b9e07496d132a1b.zip
Add tests to SwipeDetector (formerly VerticalPullDetector).
Change-Id: I09ab4f22d7204ad806825ab0d6374c2b9616bf39
Diffstat (limited to 'tests')
-rw-r--r--tests/src/com/android/launcher3/testcomponent/TouchEventGenerator.java275
-rw-r--r--tests/src/com/android/launcher3/touch/SwipeDetectorTest.java96
2 files changed, 371 insertions, 0 deletions
diff --git a/tests/src/com/android/launcher3/testcomponent/TouchEventGenerator.java b/tests/src/com/android/launcher3/testcomponent/TouchEventGenerator.java
new file mode 100644
index 000000000..80d6341e7
--- /dev/null
+++ b/tests/src/com/android/launcher3/testcomponent/TouchEventGenerator.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.testcomponent;
+
+import android.graphics.Point;
+import android.util.Pair;
+import android.view.InputDevice;
+import android.view.MotionEvent;
+import android.view.MotionEvent.PointerCoords;
+import android.view.MotionEvent.PointerProperties;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Utility class to generate MotionEvent event sequences for testing touch gesture detectors.
+ */
+public class TouchEventGenerator {
+
+ /**
+ * Amount of time between two generated events.
+ */
+ private static final long TIME_INCREMENT_MS = 20L;
+
+ /**
+ * Id of the fake device generating the events.
+ */
+ private static final int DEVICE_ID = 2104;
+
+ /**
+ * The fingers currently present on the emulated touch screen.
+ */
+ private Map<Integer, Point> mFingers;
+
+ /**
+ * Initial event time for the current sequence.
+ */
+ private long mInitialTime;
+
+ /**
+ * Time of the last generated event.
+ */
+ private long mLastEventTime;
+
+ /**
+ * Time of the next event.
+ */
+ private long mTime;
+
+ /**
+ * Receives the generated events.
+ */
+ public interface Listener {
+
+ /**
+ * Called when an event was generated.
+ */
+ void onTouchEvent(MotionEvent event);
+ }
+ private final Listener mListener;
+
+ public TouchEventGenerator(Listener listener) {
+ mListener = listener;
+ mFingers = new HashMap<Integer, Point>();
+ }
+
+ /**
+ * Adds a finger on the touchscreen.
+ */
+ public TouchEventGenerator put(int id, int x, int y, long ms) {
+ checkFingerExistence(id, false);
+ boolean isInitialDown = mFingers.isEmpty();
+ mFingers.put(id, new Point(x, y));
+ int action;
+ if (isInitialDown) {
+ action = MotionEvent.ACTION_DOWN;
+ } else {
+ action = MotionEvent.ACTION_POINTER_DOWN;
+ // Set the id of the changed pointer.
+ action |= id << MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+ }
+ generateEvent(action, ms);
+ return this;
+ }
+
+ /**
+ * Adds a finger on the touchscreen after advancing default time interval.
+ */
+ public TouchEventGenerator put(int id, int x, int y) {
+ return put(id, x, y, TIME_INCREMENT_MS);
+ }
+
+ /**
+ * Adjusts the position of a finger for an upcoming move event.
+ *
+ * @see #move(long ms)
+ */
+ public TouchEventGenerator position(int id, int x, int y) {
+ checkFingerExistence(id, true);
+ mFingers.get(id).set(x, y);
+ return this;
+ }
+
+ /**
+ * Commits the finger position changes of {@link #position(int, int, int)} by generating a move
+ * event.
+ *
+ * @see #position(int, int, int)
+ */
+ public TouchEventGenerator move(long ms) {
+ generateEvent(MotionEvent.ACTION_MOVE, ms);
+ return this;
+ }
+
+ /**
+ * Commits the finger position changes of {@link #position(int, int, int)} by generating a move
+ * event after advancing the default time interval.
+ *
+ * @see #position(int, int, int)
+ */
+ public TouchEventGenerator move() {
+ return move(TIME_INCREMENT_MS);
+ }
+
+ /**
+ * Moves a single finger on the touchscreen.
+ */
+ public TouchEventGenerator move(int id, int x, int y, long ms) {
+ return position(id, x, y).move(ms);
+ }
+
+ /**
+ * Moves a single finger on the touchscreen after advancing default time interval.
+ */
+ public TouchEventGenerator move(int id, int x, int y) {
+ return move(id, x, y, TIME_INCREMENT_MS);
+ }
+
+ /**
+ * Removes an existing finger from the touchscreen.
+ */
+ public TouchEventGenerator lift(int id, long ms) {
+ checkFingerExistence(id, true);
+ boolean isFinalUp = mFingers.size() == 1;
+ int action;
+ if (isFinalUp) {
+ action = MotionEvent.ACTION_UP;
+ } else {
+ action = MotionEvent.ACTION_POINTER_UP;
+ // Set the id of the changed pointer.
+ action |= id << MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+ }
+ generateEvent(action, ms);
+ mFingers.remove(id);
+ return this;
+ }
+
+ /**
+ * Removes a finger from the touchscreen.
+ */
+ public TouchEventGenerator lift(int id, int x, int y, long ms) {
+ checkFingerExistence(id, true);
+ mFingers.get(id).set(x, y);
+ return lift(id, ms);
+ }
+
+ /**
+ * Removes an existing finger from the touchscreen after advancing default time interval.
+ */
+ public TouchEventGenerator lift(int id) {
+ return lift(id, TIME_INCREMENT_MS);
+ }
+
+ /**
+ * Cancels an ongoing sequence.
+ */
+ public TouchEventGenerator cancel(long ms) {
+ generateEvent(MotionEvent.ACTION_CANCEL, ms);
+ mFingers.clear();
+ return this;
+ }
+
+ /**
+ * Cancels an ongoing sequence.
+ */
+ public TouchEventGenerator cancel() {
+ return cancel(TIME_INCREMENT_MS);
+ }
+
+ private void checkFingerExistence(int id, boolean shouldExist) {
+ if (shouldExist != mFingers.containsKey(id)) {
+ throw new IllegalArgumentException(
+ shouldExist ? "Finger does not exist" : "Finger already exists");
+ }
+ }
+
+ private void generateEvent(int action, long ms) {
+ mTime = mLastEventTime + ms;
+ Pair<PointerProperties[], PointerCoords[]> state = getFingerState();
+ MotionEvent event = MotionEvent.obtain(
+ mInitialTime,
+ mTime,
+ action,
+ state.first.length,
+ state.first,
+ state.second,
+ 0 /* metaState */,
+ 0 /* buttonState */,
+ 1.0f /* xPrecision */,
+ 1.0f /* yPrecision */,
+ DEVICE_ID,
+ 0 /* edgeFlags */,
+ InputDevice.SOURCE_TOUCHSCREEN,
+ 0 /* flags */);
+ mListener.onTouchEvent(event);
+ if (action == MotionEvent.ACTION_UP) {
+ resetTime();
+ }
+ event.recycle();
+ mLastEventTime = mTime;
+ }
+
+ /**
+ * Returns the description of the fingers' state expected by MotionEvent.
+ */
+ private Pair<PointerProperties[], PointerCoords[]> getFingerState() {
+ int nFingers = mFingers.size();
+ PointerProperties[] properties = new PointerProperties[nFingers];
+ PointerCoords[] coordinates = new PointerCoords[nFingers];
+
+ int index = 0;
+ for (Map.Entry<Integer, Point> entry : mFingers.entrySet()) {
+ int id = entry.getKey();
+ Point location = entry.getValue();
+
+ PointerProperties property = new PointerProperties();
+ property.id = id;
+ property.toolType = MotionEvent.TOOL_TYPE_FINGER;
+ properties[index] = property;
+
+ PointerCoords coordinate = new PointerCoords();
+ coordinate.x = location.x;
+ coordinate.y = location.y;
+ coordinate.pressure = 1.0f;
+ coordinates[index] = coordinate;
+
+ index++;
+ }
+
+ return new Pair<MotionEvent.PointerProperties[], MotionEvent.PointerCoords[]>(
+ properties, coordinates);
+ }
+
+ /**
+ * Resets the time references for a new sequence.
+ */
+ private void resetTime() {
+ mInitialTime = 0L;
+ mLastEventTime = -1L;
+ mTime = 0L;
+ }
+}
diff --git a/tests/src/com/android/launcher3/touch/SwipeDetectorTest.java b/tests/src/com/android/launcher3/touch/SwipeDetectorTest.java
new file mode 100644
index 000000000..8724704ed
--- /dev/null
+++ b/tests/src/com/android/launcher3/touch/SwipeDetectorTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.touch;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+
+import com.android.launcher3.testcomponent.TouchEventGenerator;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyFloat;
+import static org.mockito.Mockito.verify;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SwipeDetectorTest{
+
+ private static final String TAG = SwipeDetectorTest.class.getSimpleName();
+ public static void L(String s, Object... parts) {
+ Log.d(TAG, (parts.length == 0) ? s : String.format(s, parts));
+ }
+
+ private TouchEventGenerator mGenerator;
+ private SwipeDetector mDetector;
+ private int mTouchSlop;
+
+ @Mock
+ private SwipeDetector.Listener mMockListener;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ Context context = InstrumentationRegistry.getTargetContext();
+ mDetector = new SwipeDetector(context);
+ mGenerator = new TouchEventGenerator(new TouchEventGenerator.Listener() {
+ @Override
+ public void onTouchEvent(MotionEvent event) {
+ mDetector.onTouchEvent(event);
+ }
+ });
+ mDetector.setListener(mMockListener);
+ mDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_BOTH, false);
+ mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+ L("mTouchSlop=", mTouchSlop);
+ }
+
+ @Test
+ public void testDragStart() throws Exception {
+ mGenerator.put(0, 100, 100);
+ mGenerator.move(0, 100, 100 + mTouchSlop);
+ // TODO: actually calculate the following parameters and do exact value checks.
+ verify(mMockListener).onDragStart(anyBoolean());
+ }
+
+ @Test
+ public void testDrag() throws Exception {
+ mGenerator.put(0, 100, 100);
+ mGenerator.move(0, 100, 100 + mTouchSlop);
+ // TODO: actually calculate the following parameters and do exact value checks.
+ verify(mMockListener).onDrag(anyFloat(), anyFloat());
+ }
+
+ @Test
+ public void testDragEnd() throws Exception {
+ mGenerator.put(0, 100, 100);
+ mGenerator.move(0, 100, 100 + mTouchSlop);
+ mGenerator.move(0, 100, 100 + mTouchSlop * 2);
+ mGenerator.lift(0);
+ // TODO: actually calculate the following parameters and do exact value checks.
+ verify(mMockListener).onDragEnd(anyFloat(), anyBoolean());
+ }
+}