Merge "Add STATE_CLEAR and STATE_TOUCH_INTERACTING to TouchExplorer."

This commit is contained in:
Ameer Armaly
2019-08-29 21:31:38 +00:00
committed by Android (Google) Code Review
3 changed files with 265 additions and 170 deletions

View File

@@ -66,12 +66,6 @@ public class TouchExplorer extends BaseEventStreamTransformation
// Tag for logging received events.
private static final String LOG_TAG = "TouchExplorer";
// States this explorer can be in.
private static final int STATE_TOUCH_EXPLORING = 0x00000001;
private static final int STATE_DRAGGING = 0x00000002;
private static final int STATE_DELEGATING = 0x00000004;
private static final int STATE_GESTURE_DETECTING = 0x00000005;
// The maximum of the cosine between the vectors of two moving
// pointers so they can be considered moving in the same direction.
private static final float MAX_DRAGGING_ANGLE_COS = 0.525321989f; // cos(pi/4)
@@ -248,7 +242,13 @@ public class TouchExplorer extends BaseEventStreamTransformation
return;
}
if (mState.isTouchExploring()) {
// TODO: extract the below functions into separate handlers for each state.
// Right now the number of functions and number of states make the code messy.
if (mState.isClear()) {
handleMotionEventStateClear(event, rawEvent, policyFlags);
} else if (mState.isTouchInteracting()) {
handleMotionEventStateTouchInteracting(event, rawEvent, policyFlags);
} else if (mState.isTouchExploring()) {
handleMotionEventStateTouchExploring(event, rawEvent, policyFlags);
} else if (mState.isDragging()) {
handleMotionEventStateDragging(event, policyFlags);
@@ -286,8 +286,8 @@ public class TouchExplorer extends BaseEventStreamTransformation
@Override
public void onDoubleTapAndHold(MotionEvent event, int policyFlags) {
// Ignore the event if we aren't touch exploring.
if (!mState.isTouchExploring()) {
// Ignore the event if we aren't touch interacting.
if (!mState.isTouchInteracting()) {
return;
}
@@ -304,8 +304,7 @@ public class TouchExplorer extends BaseEventStreamTransformation
@Override
public boolean onDoubleTap(MotionEvent event, int policyFlags) {
// Ignore the event if we aren't touch exploring.
if (!mState.isTouchExploring()) {
if (!mState.isTouchInteracting()) {
return false;
}
@@ -379,6 +378,94 @@ public class TouchExplorer extends BaseEventStreamTransformation
return false;
}
/**
* Handles a motion event in the clear state i.e. no fingers are touching the screen.
*/
private void handleMotionEventStateClear(
MotionEvent event, MotionEvent rawEvent, int policyFlags) {
switch (event.getActionMasked()) {
// The only way to leave the clear state is for a pointer to go down.
case MotionEvent.ACTION_DOWN:
handleActionDown(event, policyFlags);
break;
default:
// Some other nonsensical event.
break;
}
}
/**
* Handles ACTION_DOWN while in the clear or touch interacting states. This event represents the
* first finger touching the screen.
*/
private void handleActionDown(MotionEvent event, int policyFlags) {
mAms.onTouchInteractionStart();
// If we still have not notified the user for the last
// touch, we figure out what to do. If were waiting
// we resent the delayed callback and wait again.
mSendHoverEnterAndMoveDelayed.cancel();
mSendHoverExitDelayed.cancel();
// If a touch exploration gesture is in progress send events for its end.
if (mState.isTouchExploring()) {
sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
}
// Avoid duplicated TYPE_TOUCH_INTERACTION_START event when 2nd tap of double
// tap.
if (!mGestureDetector.firstTapDetected() && mState.isClear()) {
mSendTouchExplorationEndDelayed.forceSendAndRemove();
mSendTouchInteractionEndDelayed.forceSendAndRemove();
sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_START);
} else {
// Let gesture to handle to avoid duplicated TYPE_TOUCH_INTERACTION_END event.
mSendTouchInteractionEndDelayed.cancel();
}
if (!mGestureDetector.firstTapDetected() && !mState.isTouchExploring()) {
if (!mSendHoverEnterAndMoveDelayed.isPending()) {
// Queue a delayed transition to STATE_TOUCH_EXPLORING.
// If we do not detect that this is a gesture, delegation or drag the transition
// will fire by default.
// The idea is to avoid getting stuck in STATE_TOUCH_INTERACTING
final int pointerId = mReceivedPointerTracker.getPrimaryPointerId();
final int pointerIdBits = (1 << pointerId);
mSendHoverEnterAndMoveDelayed.post(event, pointerIdBits, policyFlags);
} else {
// Cache the event until we discern exploration from gesturing.
mSendHoverEnterAndMoveDelayed.addEvent(event);
}
}
}
/**
* Handles a motion event in touch interacting state.
*
* @param event The event to be handled.
* @param rawEvent The raw (unmodified) motion event.
* @param policyFlags The policy flags associated with the event.
*/
private void handleMotionEventStateTouchInteracting(
MotionEvent event, MotionEvent rawEvent, int policyFlags) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
// Continue the previous interaction.
mSendTouchInteractionEndDelayed.cancel();
handleActionDown(event, policyFlags);
break;
case MotionEvent.ACTION_POINTER_DOWN:
handleActionPointerDown();
break;
case MotionEvent.ACTION_MOVE:
handleActionMoveStateTouchInteracting(event, rawEvent, policyFlags);
break;
case MotionEvent.ACTION_UP:
handleActionUp(event, policyFlags);
break;
}
}
/**
* Handles a motion event in touch exploring state.
*
@@ -390,60 +477,19 @@ public class TouchExplorer extends BaseEventStreamTransformation
MotionEvent event, MotionEvent rawEvent, int policyFlags) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
handleActionDownStateTouchExploring(event, policyFlags);
// We should have already received ACTION_DOWN. Ignore.
break;
case MotionEvent.ACTION_POINTER_DOWN:
handleActionPointerDownStateTouchExploring();
handleActionPointerDown();
break;
case MotionEvent.ACTION_MOVE:
handleActionMoveStateTouchExploring(event, rawEvent, policyFlags);
break;
case MotionEvent.ACTION_UP:
handleActionUpStateTouchExploring(event, policyFlags);
handleActionUp(event, policyFlags);
break;
default:
break;
}
}
/**
* Handles ACTION_DOWN while in the default touch exploring state. This event represents the
* first finger touching the screen.
*/
private void handleActionDownStateTouchExploring(MotionEvent event, int policyFlags) {
mAms.onTouchInteractionStart();
// If we still have not notified the user for the last
// touch, we figure out what to do. If were waiting
// we resent the delayed callback and wait again.
mSendHoverEnterAndMoveDelayed.cancel();
mSendHoverExitDelayed.cancel();
// If a touch exploration gesture is in progress send events for its end.
if (mState.isTouchExplorationInProgress()) {
sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
}
// Avoid duplicated TYPE_TOUCH_INTERACTION_START event when 2nd tap of double
// tap.
if (!mGestureDetector.firstTapDetected()) {
mSendTouchExplorationEndDelayed.forceSendAndRemove();
mSendTouchInteractionEndDelayed.forceSendAndRemove();
sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_START);
} else {
// Let gesture to handle to avoid duplicated TYPE_TOUCH_INTERACTION_END event.
mSendTouchInteractionEndDelayed.cancel();
}
if (!mGestureDetector.firstTapDetected() && !mState.isTouchExplorationInProgress()) {
if (!mSendHoverEnterAndMoveDelayed.isPending()) {
// Deliver hover enter with a delay to have a chance
// to detect what the user is trying to do.
final int pointerId = mReceivedPointerTracker.getPrimaryPointerId();
final int pointerIdBits = (1 << pointerId);
mSendHoverEnterAndMoveDelayed.post(event, true, pointerIdBits, policyFlags);
} else {
// Cache the event until we discern exploration from gesturing.
mSendHoverEnterAndMoveDelayed.addEvent(event);
}
}
}
@@ -451,7 +497,7 @@ public class TouchExplorer extends BaseEventStreamTransformation
* Handles ACTION_POINTER_DOWN when in the touch exploring state. This event represents an
* additional finger touching the screen.
*/
private void handleActionPointerDownStateTouchExploring() {
private void handleActionPointerDown() {
// Another finger down means that if we have not started to deliver
// hover events, we will not have to. The code for ACTION_MOVE will
// decide what we will actually do next.
@@ -459,10 +505,10 @@ public class TouchExplorer extends BaseEventStreamTransformation
mSendHoverExitDelayed.cancel();
}
/**
* Handles ACTION_MOVE while in the initial touch exploring state. This is where transitions to
* Handles ACTION_MOVE while in the touch interacting state. This is where transitions to
* delegating and dragging states are handled.
*/
private void handleActionMoveStateTouchExploring(
private void handleActionMoveStateTouchInteracting(
MotionEvent event, MotionEvent rawEvent, int policyFlags) {
final int pointerId = mReceivedPointerTracker.getPrimaryPointerId();
final int pointerIndex = event.findPointerIndex(pointerId);
@@ -474,41 +520,14 @@ public class TouchExplorer extends BaseEventStreamTransformation
if (mSendHoverEnterAndMoveDelayed.isPending()) {
// Cache the event until we discern exploration from gesturing.
mSendHoverEnterAndMoveDelayed.addEvent(event);
} else if (mState.isTouchExplorationInProgress()) {
sendTouchExplorationGestureStartAndHoverEnterIfNeeded(policyFlags);
sendMotionEvent(
event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits, policyFlags);
}
break;
case 2:
// Make sure we don't have any pending transitions to touch exploration
mSendHoverEnterAndMoveDelayed.cancel();
mSendHoverExitDelayed.cancel();
// More than one pointer so the user is not touch exploring
// and now we have to decide whether to delegate or drag.
if (mSendHoverEnterAndMoveDelayed.isPending()) {
// We have not started sending events so cancel
// scheduled sending events.
mSendHoverEnterAndMoveDelayed.cancel();
mSendHoverExitDelayed.cancel();
} else if (mState.isTouchExplorationInProgress()) {
// If the user is touch exploring the second pointer may be
// performing a double tap to activate an item without need
// for the user to lift his exploring finger.
// It is *important* to use the distance traveled by the pointers
// on the screen which may or may not be magnified.
final float deltaX =
mReceivedPointerTracker.getReceivedPointerDownX(pointerId)
- rawEvent.getX(pointerIndex);
final float deltaY =
mReceivedPointerTracker.getReceivedPointerDownY(pointerId)
- rawEvent.getY(pointerIndex);
final double moveDelta = Math.hypot(deltaX, deltaY);
if (moveDelta < mDoubleTapSlop) {
break;
}
// We are sending events so send exit and gesture
// end since we transition to another state.
sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
}
// Remove move history before send injected non-move events
event = MotionEvent.obtainNoHistory(event);
if (isDraggingGesture(event)) {
@@ -525,19 +544,6 @@ public class TouchExplorer extends BaseEventStreamTransformation
}
break;
default:
// More than one pointer so the user is not touch exploring
// and now we have to decide whether to delegate or drag.
if (mSendHoverEnterAndMoveDelayed.isPending()) {
// We have not started sending events so cancel
// scheduled sending events.
mSendHoverEnterAndMoveDelayed.cancel();
mSendHoverExitDelayed.cancel();
} else {
// We are sending events so send exit and gesture
// end since we transition to another state.
sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
}
// More than two pointers are delegated to the view hierarchy.
mState.startDelegating();
event = MotionEvent.obtainNoHistory(event);
@@ -547,14 +553,13 @@ public class TouchExplorer extends BaseEventStreamTransformation
}
/**
* Handles ACTION_UP while in the initial touch exploring state. This event represents all
* fingers being lifted from the screen.
* Handles ACTION_UP while in the touch interacting state. This event represents all fingers
* being lifted from the screen.
*/
private void handleActionUpStateTouchExploring(MotionEvent event, int policyFlags) {
private void handleActionUp(MotionEvent event, int policyFlags) {
mAms.onTouchInteractionEnd();
final int pointerId = event.getPointerId(event.getActionIndex());
final int pointerIdBits = (1 << pointerId);
if (mSendHoverEnterAndMoveDelayed.isPending()) {
// If we have not delivered the enter schedule an exit.
mSendHoverExitDelayed.post(event, pointerIdBits, policyFlags);
@@ -562,12 +567,68 @@ public class TouchExplorer extends BaseEventStreamTransformation
// The user is touch exploring so we send events for end.
sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
}
if (!mSendTouchInteractionEndDelayed.isPending()) {
mSendTouchInteractionEndDelayed.post();
}
}
/**
* Handles move events while touch exploring. this is also where we drag or delegate based on
* the number of fingers moving on the screen.
*/
private void handleActionMoveStateTouchExploring(
MotionEvent event, MotionEvent rawEvent, int policyFlags) {
final int pointerId = mReceivedPointerTracker.getPrimaryPointerId();
final int pointerIdBits = (1 << pointerId);
final int pointerIndex = event.findPointerIndex(pointerId);
switch (event.getPointerCount()) {
case 1:
// Touch exploration.
sendTouchExplorationGestureStartAndHoverEnterIfNeeded(policyFlags);
sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits, policyFlags);
break;
case 2:
if (mSendHoverEnterAndMoveDelayed.isPending()) {
// We have not started sending events so cancel
// scheduled sending events.
mSendHoverEnterAndMoveDelayed.cancel();
mSendHoverExitDelayed.cancel();
}
// If the user is touch exploring the second pointer may be
// performing a double tap to activate an item without need
// for the user to lift his exploring finger.
// It is *important* to use the distance traveled by the pointers
// on the screen which may or may not be magnified.
final float deltaX =
mReceivedPointerTracker.getReceivedPointerDownX(pointerId)
- rawEvent.getX(pointerIndex);
final float deltaY =
mReceivedPointerTracker.getReceivedPointerDownY(pointerId)
- rawEvent.getY(pointerIndex);
final double moveDelta = Math.hypot(deltaX, deltaY);
if (moveDelta > mDoubleTapSlop) {
// The user is trying to either delegate or drag.
handleActionMoveStateTouchInteracting(event, rawEvent, policyFlags);
} else {
// Otherwise the double tap will be handled by the gesture detector.
sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
}
break;
default:
// Three or more fingers is something other than touch exploration.
if (mSendHoverEnterAndMoveDelayed.isPending()) {
// We have not started sending events so cancel
// scheduled sending events.
mSendHoverEnterAndMoveDelayed.cancel();
mSendHoverExitDelayed.cancel();
} else {
sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
}
handleActionMoveStateTouchInteracting(event, rawEvent, policyFlags);
break;
}
}
/**
* Handles a motion event in dragging state.
*
@@ -670,7 +731,6 @@ public class TouchExplorer extends BaseEventStreamTransformation
// Send an event to the end of the drag gesture.
sendMotionEvent(event, MotionEvent.ACTION_UP, pointerIdBits, policyFlags);
}
mState.startTouchExploring();
} break;
}
}
@@ -697,7 +757,6 @@ public class TouchExplorer extends BaseEventStreamTransformation
mAms.onTouchInteractionEnd();
sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
mState.startTouchExploring();
} break;
default: {
// Deliver the event.
@@ -717,7 +776,6 @@ public class TouchExplorer extends BaseEventStreamTransformation
}
mExitGestureDetectionModeDelayed.cancel();
mState.startTouchExploring();
}
/**
@@ -731,8 +789,13 @@ public class TouchExplorer extends BaseEventStreamTransformation
AccessibilityEvent event = AccessibilityEvent.obtain(type);
event.setWindowId(mAms.getActiveWindowId());
accessibilityManager.sendAccessibilityEvent(event);
mState.onInjectedAccessibilityEvent(type);
if (DEBUG) {
Slog.d(
LOG_TAG,
"Sending accessibility event" + AccessibilityEvent.eventTypeToString(type));
}
}
mState.onInjectedAccessibilityEvent(type);
}
/**
@@ -915,6 +978,10 @@ public class TouchExplorer extends BaseEventStreamTransformation
MAX_DRAGGING_ANGLE_COS);
}
public TouchState getState() {
return mState;
}
/**
* Class for delayed exiting from gesture detecting mode.
*/
@@ -947,8 +1014,7 @@ public class TouchExplorer extends BaseEventStreamTransformation
private int mPointerIdBits;
private int mPolicyFlags;
public void post(MotionEvent event, boolean touchExplorationInProgress,
int pointerIdBits, int policyFlags) {
public void post(MotionEvent event, int pointerIdBits, int policyFlags) {
cancel();
addEvent(event);
mPointerIdBits = pointerIdBits;

View File

@@ -41,20 +41,33 @@ public class TouchState {
public static final int ALL_POINTER_ID_BITS = 0xFFFFFFFF;
// States that the touch explorer can be in.
public static final int STATE_TOUCH_EXPLORING = 0x00000001;
public static final int STATE_DRAGGING = 0x00000002;
public static final int STATE_DELEGATING = 0x00000003;
public static final int STATE_GESTURE_DETECTING = 0x00000004;
// In the clear state the user is not touching the screen.
public static final int STATE_CLEAR = 0;
// The user is touching the screen and we are trying to figure out their intent.
// This state gets its name from the TYPE_TOUCH_INTERACTION start and end accessibility events.
public static final int STATE_TOUCH_INTERACTING = 1;
// The user is explicitly exploring the screen.
public static final int STATE_TOUCH_EXPLORING = 2;
// the user is dragging with two fingers.
public static final int STATE_DRAGGING = 3;
// The user is performing some other two finger gesture which we pass through to the view
// hierarchy as a one-finger gesture e.g. two-finger scrolling.
public static final int STATE_DELEGATING = 4;
// The user is performing something that might be a gesture.
public static final int STATE_GESTURE_DETECTING = 5;
@IntDef({STATE_TOUCH_EXPLORING, STATE_DRAGGING, STATE_DELEGATING, STATE_GESTURE_DETECTING})
@IntDef({
STATE_CLEAR,
STATE_TOUCH_INTERACTING,
STATE_TOUCH_EXPLORING,
STATE_DRAGGING,
STATE_DELEGATING,
STATE_GESTURE_DETECTING
})
public @interface State {}
// The current state of the touch explorer.
private int mState = STATE_TOUCH_EXPLORING;
// Whether touch exploration is in progress.
// TODO: Add separate states to represent intend detection and actual touch exploration so that
// only one variable describes the state.
private boolean mTouchExplorationInProgress;
private int mState = STATE_CLEAR;
// Helper class to track received pointers.
// Todo: collapse or hide this class so multiple classes don't modify it.
private final ReceivedPointerTracker mReceivedPointerTracker;
@@ -69,8 +82,7 @@ public class TouchState {
/** Clears the internal shared state. */
public void clear() {
mState = STATE_TOUCH_EXPLORING;
mTouchExplorationInProgress = false;
setState(STATE_CLEAR);
// Reset the pointer trackers.
mReceivedPointerTracker.clear();
mInjectedPointerTracker.clear();
@@ -94,18 +106,33 @@ public class TouchState {
mReceivedPointerTracker.onMotionEvent(rawEvent);
}
/**
* Updates the state in response to an accessibility event being sent from TouchExplorer.
*
* @param type The event type.
*/
public void onInjectedAccessibilityEvent(int type) {
// The below state transitions go here because the related events are often sent on a
// delay.
// This allows state to accurately reflect the state in the moment.
// TODO: replaced the delayed event senders with delayed state transitions
// so that state transitions trigger events rather than events triggering state
// transitions.
switch (type) {
case AccessibilityEvent.TYPE_TOUCH_INTERACTION_START:
startTouchInteracting();
break;
case AccessibilityEvent.TYPE_TOUCH_INTERACTION_END:
clear();
break;
case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START:
mTouchExplorationInProgress = true;
startTouchExploring();
break;
case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END:
mTouchExplorationInProgress = false;
startTouchInteracting();
break;
case AccessibilityEvent.TYPE_GESTURE_DETECTION_START:
startGestureDetecting();
break;
case AccessibilityEvent.TYPE_GESTURE_DETECTION_END:
startTouchInteracting();
break;
default:
break;
}
}
@@ -117,6 +144,7 @@ public class TouchState {
/** Transitions to a new state. */
public void setState(@State int state) {
if (mState == state) return;
if (DEBUG) {
Slog.i(LOG_TAG, getStateSymbolicName(mState) + "->" + getStateSymbolicName(state));
}
@@ -159,26 +187,32 @@ public class TouchState {
setState(STATE_DRAGGING);
}
public boolean isTouchExplorationInProgress() {
return mTouchExplorationInProgress;
public boolean isTouchInteracting() {
return mState == STATE_TOUCH_INTERACTING;
}
public void setTouchExplorationInProgress(boolean touchExplorationInProgress) {
mTouchExplorationInProgress = touchExplorationInProgress;
/**
* Transitions to the touch interacting state, where we attempt to figure out what the user is
* doing.
*/
public void startTouchInteracting() {
setState(STATE_TOUCH_INTERACTING);
}
public boolean isClear() {
return mState == STATE_CLEAR;
}
/** Returns a string representation of the current state. */
public String toString() {
return "TouchState { "
+ "mState: "
+ getStateSymbolicName(mState)
+ ", mTouchExplorationInProgress"
+ mTouchExplorationInProgress
+ " }";
return "TouchState { " + "mState: " + getStateSymbolicName(mState) + " }";
}
/** Returns a string representation of the specified state. */
public static String getStateSymbolicName(int state) {
switch (state) {
case STATE_CLEAR:
return "STATE_CLEAR";
case STATE_TOUCH_INTERACTING:
return "STATE_TOUCH_INTERACTING";
case STATE_TOUCH_EXPLORING:
return "STATE_TOUCH_EXPLORING";
case STATE_DRAGGING:

View File

@@ -16,15 +16,18 @@
package com.android.server.accessibility.gestures;
import static com.android.server.accessibility.gestures.TouchState.STATE_CLEAR;
import static com.android.server.accessibility.gestures.TouchState.STATE_DELEGATING;
import static com.android.server.accessibility.gestures.TouchState.STATE_DRAGGING;
import static com.android.server.accessibility.gestures.TouchState.STATE_TOUCH_EXPLORING;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import android.content.Context;
import android.graphics.PointF;
import android.os.SystemClock;
import android.testing.DexmakerShareClassLoaderRule;
import android.util.DebugUtils;
import android.view.InputDevice;
import android.view.MotionEvent;
@@ -46,10 +49,6 @@ import java.util.List;
@RunWith(AndroidJUnit4.class)
public class TouchExplorerTest {
public static final int STATE_TOUCH_EXPLORING = 0x00000001;
public static final int STATE_DRAGGING = 0x00000002;
public static final int STATE_DELEGATING = 0x00000004;
private static final int FLAG_1FINGER = 0x8000;
private static final int FLAG_2FINGERS = 0x0100;
private static final int FLAG_3FINGERS = 0x0200;
@@ -112,7 +111,7 @@ public class TouchExplorerTest {
@Test
public void testTwoFingersMove_shouldDelegatingAndInjectActionDownPointerDown() {
goFromStateIdleTo(STATE_MOVING_2FINGERS);
goFromStateClearTo(STATE_MOVING_2FINGERS);
assertState(STATE_DELEGATING);
assertCapturedEvents(
@@ -123,7 +122,7 @@ public class TouchExplorerTest {
@Test
public void testTwoFingersDrag_shouldDraggingAndActionDown() {
goFromStateIdleTo(STATE_DRAGGING_2FINGERS);
goFromStateClearTo(STATE_DRAGGING_2FINGERS);
assertState(STATE_DRAGGING);
assertCapturedEvents(MotionEvent.ACTION_DOWN);
@@ -133,7 +132,7 @@ public class TouchExplorerTest {
@Test
public void testTwoFingersNotDrag_shouldDelegatingAndActionUpDownPointerDown() {
// only from dragging state, and withMoveHistory no dragging
goFromStateIdleTo(STATE_PINCH_2FINGERS);
goFromStateClearTo(STATE_PINCH_2FINGERS);
assertState(STATE_DELEGATING);
assertCapturedEvents(
@@ -146,7 +145,7 @@ public class TouchExplorerTest {
@Test
public void testThreeFingersMove_shouldDelegatingAnd3ActionPointerDown() {
goFromStateIdleTo(STATE_MOVING_3FINGERS);
goFromStateClearTo(STATE_MOVING_3FINGERS);
assertState(STATE_DELEGATING);
assertCapturedEvents(
@@ -165,52 +164,47 @@ public class TouchExplorerTest {
return new PointF(x, y);
}
private static String stateToString(int state) {
return DebugUtils.valueToString(TouchExplorerTest.class, "STATE_", state);
}
private void goFromStateIdleTo(int state) {
private void goFromStateClearTo(int state) {
try {
switch (state) {
case STATE_TOUCH_EXPLORING: {
case STATE_CLEAR: {
mTouchExplorer.onDestroy();
}
break;
case STATE_TOUCH_EXPLORING_1FINGER: {
goFromStateIdleTo(STATE_TOUCH_EXPLORING);
send(downEvent());
}
break;
case STATE_TOUCH_EXPLORING_2FINGER: {
goFromStateIdleTo(STATE_TOUCH_EXPLORING_1FINGER);
goFromStateClearTo(STATE_TOUCH_EXPLORING_1FINGER);
send(pointerDownEvent());
}
break;
case STATE_TOUCH_EXPLORING_3FINGER: {
goFromStateIdleTo(STATE_TOUCH_EXPLORING_2FINGER);
goFromStateClearTo(STATE_TOUCH_EXPLORING_2FINGER);
send(thirdPointerDownEvent());
}
break;
case STATE_MOVING_2FINGERS: {
goFromStateIdleTo(STATE_TOUCH_EXPLORING_2FINGER);
goFromStateClearTo(STATE_TOUCH_EXPLORING_2FINGER);
moveEachPointers(mLastEvent, p(10, 0), p(5, 10));
send(mLastEvent);
}
break;
case STATE_DRAGGING_2FINGERS: {
goFromStateIdleTo(STATE_TOUCH_EXPLORING_2FINGER);
goFromStateClearTo(STATE_TOUCH_EXPLORING_2FINGER);
moveEachPointers(mLastEvent, p(10, 0), p(10, 0));
send(mLastEvent);
}
break;
case STATE_PINCH_2FINGERS: {
goFromStateIdleTo(STATE_DRAGGING_2FINGERS);
goFromStateClearTo(STATE_DRAGGING_2FINGERS);
moveEachPointers(mLastEvent, p(10, 0), p(-10, 1));
send(mLastEvent);
}
break;
case STATE_MOVING_3FINGERS: {
goFromStateIdleTo(STATE_TOUCH_EXPLORING_3FINGER);
goFromStateClearTo(STATE_TOUCH_EXPLORING_3FINGER);
moveEachPointers(mLastEvent, p(1, 0), p(1, 0), p(1, 0));
send(mLastEvent);
}
@@ -219,7 +213,8 @@ public class TouchExplorerTest {
throw new IllegalArgumentException("Illegal state: " + state);
}
} catch (Throwable t) {
throw new RuntimeException("Failed to go to state " + stateToString(state), t);
throw new RuntimeException("Failed to go to state "
+ TouchState.getStateSymbolicName(state), t);
}
}
@@ -234,9 +229,9 @@ public class TouchExplorerTest {
}
private void assertState(int expect) {
final String expectState = "STATE_" + stateToString(expect);
assertTrue(String.format("Expect state: %s, but: %s", expectState, mTouchExplorer),
mTouchExplorer.toString().contains(expectState));
assertEquals(
TouchState.getStateSymbolicName(expect),
TouchState.getStateSymbolicName(mTouchExplorer.getState().getState()));
}
private void assertCapturedEvents(int... actionsInOrder) {