am c37dc69c: am d367b70c: Merge "Accessibility HOVER_ENTER / EXIT without enclosing EXPLORATION_GESTURE_START / END" into jb-mr1-dev

* commit 'c37dc69ca272ef86a9bc3593ad6a65010294f7ae':
  Accessibility HOVER_ENTER / EXIT without enclosing EXPLORATION_GESTURE_START / END
This commit is contained in:
Svetoslav Ganov
2012-10-04 12:34:32 -07:00
committed by Android Git Automerger

View File

@@ -102,10 +102,6 @@ class TouchExplorer implements EventStreamTransformation {
// The timeout after which we are no longer trying to detect a gesture. // The timeout after which we are no longer trying to detect a gesture.
private static final int EXIT_GESTURE_DETECTION_TIMEOUT = 2000; private static final int EXIT_GESTURE_DETECTION_TIMEOUT = 2000;
// The timeout to send interaction end events in case we did not
// receive the expected hover exit event due to a misbehaving app.
private static final int SEND_INTERACTION_END_EVENTS_TIMEOUT = 200;
// Temporary array for storing pointer IDs. // Temporary array for storing pointer IDs.
private final int[] mTempPointerIds = new int[MAX_POINTER_COUNT]; private final int[] mTempPointerIds = new int[MAX_POINTER_COUNT];
@@ -139,8 +135,11 @@ class TouchExplorer implements EventStreamTransformation {
// Command for delayed sending of a hover exit event. // Command for delayed sending of a hover exit event.
private final SendHoverDelayed mSendHoverExitDelayed; private final SendHoverDelayed mSendHoverExitDelayed;
// Command for delayed sending of interaction ending events. // Command for delayed sending of touch exploration end events.
private final SendInteractionEndEventsDelayed mSendInteractionEndEventsDelayed; private final SendAccessibilityEventDelayed mSendTouchExplorationEndDelayed;
// Command for delayed sending of touch interaction end events.
private final SendAccessibilityEventDelayed mSendTouchInteractionEndDelayed;
// Command for delayed sending of a long press. // Command for delayed sending of a long press.
private final PerformLongPressDelayed mPerformLongPressDelayed; private final PerformLongPressDelayed mPerformLongPressDelayed;
@@ -209,11 +208,8 @@ class TouchExplorer implements EventStreamTransformation {
// The id of the last touch explored window. // The id of the last touch explored window.
private int mLastTouchedWindowId; private int mLastTouchedWindowId;
// Whether touch exploration gesture has ended. // Whether touch exploration is in progress.
private boolean mTouchExplorationGestureEnded; private boolean mTouchExplorationInProgress;
// Whether touch interaction has ended.
private boolean mTouchInteractionEnded;
/** /**
* Creates a new instance. * Creates a new instance.
@@ -240,7 +236,12 @@ class TouchExplorer implements EventStreamTransformation {
mGestureLibrary.load(); mGestureLibrary.load();
mSendHoverEnterDelayed = new SendHoverDelayed(MotionEvent.ACTION_HOVER_ENTER, true); mSendHoverEnterDelayed = new SendHoverDelayed(MotionEvent.ACTION_HOVER_ENTER, true);
mSendHoverExitDelayed = new SendHoverDelayed(MotionEvent.ACTION_HOVER_EXIT, false); mSendHoverExitDelayed = new SendHoverDelayed(MotionEvent.ACTION_HOVER_EXIT, false);
mSendInteractionEndEventsDelayed = new SendInteractionEndEventsDelayed(); mSendTouchExplorationEndDelayed = new SendAccessibilityEventDelayed(
AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END,
mDetermineUserIntentTimeout);
mSendTouchInteractionEndDelayed = new SendAccessibilityEventDelayed(
AccessibilityEvent.TYPE_TOUCH_INTERACTION_END,
mDetermineUserIntentTimeout);
mDoubleTapDetector = new DoubleTapDetector(); mDoubleTapDetector = new DoubleTapDetector();
final float density = context.getResources().getDisplayMetrics().density; final float density = context.getResources().getDisplayMetrics().density;
mScaledMinPointerDistanceToUseMiddleLocation = mScaledMinPointerDistanceToUseMiddleLocation =
@@ -265,7 +266,7 @@ class TouchExplorer implements EventStreamTransformation {
switch (mCurrentState) { switch (mCurrentState) {
case STATE_TOUCH_EXPLORING: { case STATE_TOUCH_EXPLORING: {
// If a touch exploration gesture is in progress send events for its end. // If a touch exploration gesture is in progress send events for its end.
sendExitEventsIfNeeded(policyFlags); sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
} break; } break;
case STATE_DRAGGING: { case STATE_DRAGGING: {
mDraggingPointerId = INVALID_POINTER_ID; mDraggingPointerId = INVALID_POINTER_ID;
@@ -286,7 +287,8 @@ class TouchExplorer implements EventStreamTransformation {
mSendHoverExitDelayed.remove(); mSendHoverExitDelayed.remove();
mPerformLongPressDelayed.remove(); mPerformLongPressDelayed.remove();
mExitGestureDetectionModeDelayed.remove(); mExitGestureDetectionModeDelayed.remove();
mSendInteractionEndEventsDelayed.remove(); mSendTouchExplorationEndDelayed.remove();
mSendTouchInteractionEndDelayed.remove();
// Reset the pointer trackers. // Reset the pointer trackers.
mReceivedPointerTracker.clear(); mReceivedPointerTracker.clear();
mInjectedPointerTracker.clear(); mInjectedPointerTracker.clear();
@@ -301,6 +303,7 @@ class TouchExplorer implements EventStreamTransformation {
if (mNext != null) { if (mNext != null) {
mNext.clear(); mNext.clear();
} }
mTouchExplorationInProgress = false;
} }
@Override @Override
@@ -341,19 +344,17 @@ class TouchExplorer implements EventStreamTransformation {
// The event for gesture end should be strictly after the // The event for gesture end should be strictly after the
// last hover exit event. // last hover exit event.
if (mTouchExplorationGestureEnded if (mSendTouchExplorationEndDelayed.isPending()
&& eventType == AccessibilityEvent.TYPE_VIEW_HOVER_EXIT) { && eventType == AccessibilityEvent.TYPE_VIEW_HOVER_EXIT) {
mSendInteractionEndEventsDelayed.remove(); mSendTouchExplorationEndDelayed.remove();
mTouchExplorationGestureEnded = false;
sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END); sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END);
} }
// The event for touch interaction end should be strictly after the // The event for touch interaction end should be strictly after the
// last hover exit and the touch exploration gesture end events. // last hover exit and the touch exploration gesture end events.
if (mTouchInteractionEnded if (mSendTouchInteractionEndDelayed.isPending()
&& eventType == AccessibilityEvent.TYPE_VIEW_HOVER_EXIT) { && eventType == AccessibilityEvent.TYPE_VIEW_HOVER_EXIT) {
mSendInteractionEndEventsDelayed.remove(); mSendTouchInteractionEndDelayed.remove();
mTouchInteractionEnded = false;
sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END); sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
} }
@@ -396,15 +397,6 @@ class TouchExplorer implements EventStreamTransformation {
switch (event.getActionMasked()) { switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_DOWN:
// The delayed enter not delivered implies that we have delivered
// TYPE_TOUCH_INTERACTION_START and not TYPE_TOUCH_INTERACTION_END,
// therefore we need to deliver the interaction end event here.
if (mSendHoverEnterDelayed.isPending()) {
sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
}
// Announce the start of a new touch interaction.
sendAccessibilityEvent(
AccessibilityEvent.TYPE_TOUCH_INTERACTION_START);
// Pre-feed the motion events to the gesture detector since we // Pre-feed the motion events to the gesture detector since we
// have a distance slop before getting into gesture detection // have a distance slop before getting into gesture detection
// mode and not using the points within this slop significantly // mode and not using the points within this slop significantly
@@ -426,8 +418,20 @@ class TouchExplorer implements EventStreamTransformation {
mSendHoverExitDelayed.remove(); mSendHoverExitDelayed.remove();
} }
if (mSendInteractionEndEventsDelayed.isPending()) { if (mSendTouchExplorationEndDelayed.isPending()) {
mSendInteractionEndEventsDelayed.forceSendAndRemove(); mSendTouchExplorationEndDelayed.forceSendAndRemove();
}
if (mSendTouchInteractionEndDelayed.isPending()) {
mSendTouchInteractionEndDelayed.forceSendAndRemove();
}
// Every pointer that goes down is active until it moves or
// another one goes down. Hence, having more than one pointer
// down we have already send the interaction start event.
if (event.getPointerCount() == 1) {
sendAccessibilityEvent(
AccessibilityEvent.TYPE_TOUCH_INTERACTION_START);
} }
mPerformLongPressDelayed.remove(); mPerformLongPressDelayed.remove();
@@ -443,11 +447,13 @@ class TouchExplorer implements EventStreamTransformation {
mPerformLongPressDelayed.post(event, policyFlags); mPerformLongPressDelayed.post(event, policyFlags);
break; break;
} }
// Deliver hover enter with a delay to have a chance if (!mTouchExplorationInProgress) {
// to detect what the user is trying to do. // Deliver hover enter with a delay to have a chance
final int pointerId = receivedTracker.getPrimaryActivePointerId(); // to detect what the user is trying to do.
final int pointerIdBits = (1 << pointerId); final int pointerId = receivedTracker.getPrimaryActivePointerId();
mSendHoverEnterDelayed.post(event, true, pointerIdBits, policyFlags); final int pointerIdBits = (1 << pointerId);
mSendHoverEnterDelayed.post(event, true, pointerIdBits, policyFlags);
}
} break; } break;
default: { default: {
/* do nothing - let the code for ACTION_MOVE decide what to do */ /* do nothing - let the code for ACTION_MOVE decide what to do */
@@ -512,12 +518,27 @@ class TouchExplorer implements EventStreamTransformation {
break; break;
} }
} else { } else {
// Cancel the long press if pending and the user
// moved more than the slop.
if (mPerformLongPressDelayed.isPending()) {
final float deltaX =
receivedTracker.getReceivedPointerDownX(pointerId)
- rawEvent.getX(pointerIndex);
final float deltaY =
receivedTracker.getReceivedPointerDownY(pointerId)
- rawEvent.getY(pointerIndex);
final double moveDelta = Math.hypot(deltaX, deltaY);
// The user has moved enough for us to decide.
if (moveDelta > mTouchSlop) {
mPerformLongPressDelayed.remove();
}
}
// The user is wither double tapping or performing long // The user is wither double tapping or performing long
// press so do not send move events yet. // press so do not send move events yet.
if (mDoubleTapDetector.firstTapDetected()) { if (mDoubleTapDetector.firstTapDetected()) {
break; break;
} }
sendEnterEventsIfNeeded(policyFlags); sendTouchExplorationGestureStartAndHoverEnterIfNeeded(policyFlags);
sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits, sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits,
policyFlags); policyFlags);
} }
@@ -548,7 +569,7 @@ class TouchExplorer implements EventStreamTransformation {
} }
// We are sending events so send exit and gesture // We are sending events so send exit and gesture
// end since we transition to another state. // end since we transition to another state.
sendExitEventsIfNeeded(policyFlags); sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
} }
// We know that a new state transition is to happen and the // We know that a new state transition is to happen and the
@@ -583,7 +604,7 @@ class TouchExplorer implements EventStreamTransformation {
mPerformLongPressDelayed.remove(); mPerformLongPressDelayed.remove();
// We are sending events so send exit and gesture // We are sending events so send exit and gesture
// end since we transition to another state. // end since we transition to another state.
sendExitEventsIfNeeded(policyFlags); sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
} }
// More than two pointers are delegated to the view hierarchy. // More than two pointers are delegated to the view hierarchy.
@@ -612,11 +633,14 @@ class TouchExplorer implements EventStreamTransformation {
// If we have not delivered the enter schedule exit. // If we have not delivered the enter schedule exit.
if (mSendHoverEnterDelayed.isPending()) { if (mSendHoverEnterDelayed.isPending()) {
mSendHoverEnterDelayed.mTouchExplorationInProgress = false;
mSendHoverExitDelayed.post(event, false, pointerIdBits, policyFlags); mSendHoverExitDelayed.post(event, false, pointerIdBits, policyFlags);
} else { } else {
// The user is touch exploring so we send events for end. // The user is touch exploring so we send events for end.
sendExitEventsIfNeeded(policyFlags); sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
}
if (!mSendTouchInteractionEndDelayed.isPending()) {
mSendTouchInteractionEndDelayed.post();
} }
} break; } break;
} }
@@ -846,6 +870,14 @@ class TouchExplorer implements EventStreamTransformation {
if (accessibilityManager.isEnabled()) { if (accessibilityManager.isEnabled()) {
AccessibilityEvent event = AccessibilityEvent.obtain(type); AccessibilityEvent event = AccessibilityEvent.obtain(type);
accessibilityManager.sendAccessibilityEvent(event); accessibilityManager.sendAccessibilityEvent(event);
switch (type) {
case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START: {
mTouchExplorationInProgress = true;
} break;
case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END: {
mTouchExplorationInProgress = false;
} break;
}
} }
} }
@@ -893,14 +925,12 @@ class TouchExplorer implements EventStreamTransformation {
* *
* @param policyFlags The policy flags associated with the event. * @param policyFlags The policy flags associated with the event.
*/ */
private void sendExitEventsIfNeeded(int policyFlags) { private void sendHoverExitAndTouchExplorationGestureEndIfNeeded(int policyFlags) {
MotionEvent event = mInjectedPointerTracker.getLastInjectedHoverEvent(); MotionEvent event = mInjectedPointerTracker.getLastInjectedHoverEvent();
if (event != null && event.getActionMasked() != MotionEvent.ACTION_HOVER_EXIT) { if (event != null && event.getActionMasked() != MotionEvent.ACTION_HOVER_EXIT) {
final int pointerIdBits = event.getPointerIdBits(); final int pointerIdBits = event.getPointerIdBits();
mTouchExplorationGestureEnded = true; if (!mSendTouchExplorationEndDelayed.isPending()) {
mTouchInteractionEnded = true; mSendTouchExplorationEndDelayed.post();
if (!mSendInteractionEndEventsDelayed.isPending()) {
mSendInteractionEndEventsDelayed.post();
} }
sendMotionEvent(event, MotionEvent.ACTION_HOVER_EXIT, pointerIdBits, policyFlags); sendMotionEvent(event, MotionEvent.ACTION_HOVER_EXIT, pointerIdBits, policyFlags);
} }
@@ -912,10 +942,11 @@ class TouchExplorer implements EventStreamTransformation {
* *
* @param policyFlags The policy flags associated with the event. * @param policyFlags The policy flags associated with the event.
*/ */
private void sendEnterEventsIfNeeded(int policyFlags) { private void sendTouchExplorationGestureStartAndHoverEnterIfNeeded(int policyFlags) {
MotionEvent event = mInjectedPointerTracker.getLastInjectedHoverEvent(); MotionEvent event = mInjectedPointerTracker.getLastInjectedHoverEvent();
if (event != null && event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT) { if (event != null && event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT) {
final int pointerIdBits = event.getPointerIdBits(); final int pointerIdBits = event.getPointerIdBits();
sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
sendMotionEvent(event, MotionEvent.ACTION_HOVER_ENTER, pointerIdBits, policyFlags); sendMotionEvent(event, MotionEvent.ACTION_HOVER_ENTER, pointerIdBits, policyFlags);
} }
} }
@@ -1181,8 +1212,12 @@ class TouchExplorer implements EventStreamTransformation {
mSendHoverExitDelayed.remove(); mSendHoverExitDelayed.remove();
mPerformLongPressDelayed.remove(); mPerformLongPressDelayed.remove();
// The touch interaction has ended since we will send a click. if (mSendTouchExplorationEndDelayed.isPending()) {
sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END); mSendTouchExplorationEndDelayed.forceSendAndRemove();
}
if (mSendTouchInteractionEndDelayed.isPending()) {
mSendTouchInteractionEndDelayed.forceSendAndRemove();
}
int clickLocationX; int clickLocationX;
int clickLocationY; int clickLocationY;
@@ -1416,7 +1451,7 @@ class TouchExplorer implements EventStreamTransformation {
mLongPressingPointerDeltaX = (int) mEvent.getX(pointerIndex) - clickLocationX; mLongPressingPointerDeltaX = (int) mEvent.getX(pointerIndex) - clickLocationX;
mLongPressingPointerDeltaY = (int) mEvent.getY(pointerIndex) - clickLocationY; mLongPressingPointerDeltaY = (int) mEvent.getY(pointerIndex) - clickLocationY;
sendExitEventsIfNeeded(mPolicyFlags); sendHoverExitAndTouchExplorationGestureEndIfNeeded(mPolicyFlags);
mCurrentState = STATE_DELEGATING; mCurrentState = STATE_DELEGATING;
sendDownForAllActiveNotInjectedPointers(mEvent, mPolicyFlags); sendDownForAllActiveNotInjectedPointers(mEvent, mPolicyFlags);
@@ -1445,7 +1480,6 @@ class TouchExplorer implements EventStreamTransformation {
private MotionEvent mPrototype; private MotionEvent mPrototype;
private int mPointerIdBits; private int mPointerIdBits;
private int mPolicyFlags; private int mPolicyFlags;
private boolean mTouchExplorationInProgress;
public SendHoverDelayed(int hoverAction, boolean gestureStarted) { public SendHoverDelayed(int hoverAction, boolean gestureStarted) {
mHoverAction = hoverAction; mHoverAction = hoverAction;
@@ -1456,7 +1490,6 @@ class TouchExplorer implements EventStreamTransformation {
int pointerIdBits, int policyFlags) { int pointerIdBits, int policyFlags) {
remove(); remove();
mPrototype = MotionEvent.obtain(prototype); mPrototype = MotionEvent.obtain(prototype);
mTouchExplorationInProgress = touchExplorationInProgress;
mPointerIdBits = pointerIdBits; mPointerIdBits = pointerIdBits;
mPolicyFlags = policyFlags; mPolicyFlags = policyFlags;
mHandler.postDelayed(this, mDetermineUserIntentTimeout); mHandler.postDelayed(this, mDetermineUserIntentTimeout);
@@ -1493,7 +1526,6 @@ class TouchExplorer implements EventStreamTransformation {
mPrototype = null; mPrototype = null;
mPointerIdBits = -1; mPointerIdBits = -1;
mPolicyFlags = 0; mPolicyFlags = 0;
mTouchExplorationInProgress = false;
} }
public void forceSendAndRemove() { public void forceSendAndRemove() {
@@ -1510,22 +1542,15 @@ class TouchExplorer implements EventStreamTransformation {
Slog.d(LOG_TAG_SEND_HOVER_DELAYED, mGestureStarted ? Slog.d(LOG_TAG_SEND_HOVER_DELAYED, mGestureStarted ?
"touchExplorationGestureStarted" : "touchExplorationGestureEnded"); "touchExplorationGestureStarted" : "touchExplorationGestureEnded");
} }
if (mTouchExplorationInProgress) { if (mGestureStarted) {
if (mGestureStarted) { sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
} else {
mTouchExplorationGestureEnded = true;
mTouchInteractionEnded = true;
if (!mSendInteractionEndEventsDelayed.isPending()) {
mSendInteractionEndEventsDelayed.post();
}
}
} else { } else {
if (!mGestureStarted) { if (!mSendTouchExplorationEndDelayed.isPending()) {
mTouchInteractionEnded = true; mSendTouchExplorationEndDelayed.post();
if (!mSendInteractionEndEventsDelayed.isPending()) { }
mSendInteractionEndEventsDelayed.post(); if (mSendTouchInteractionEndDelayed.isPending()) {
} mSendTouchInteractionEndDelayed.remove();
mSendTouchInteractionEndDelayed.post();
} }
} }
sendMotionEvent(mPrototype, mHoverAction, mPointerIdBits, mPolicyFlags); sendMotionEvent(mPrototype, mHoverAction, mPointerIdBits, mPolicyFlags);
@@ -1533,14 +1558,21 @@ class TouchExplorer implements EventStreamTransformation {
} }
} }
private class SendInteractionEndEventsDelayed implements Runnable { private class SendAccessibilityEventDelayed implements Runnable {
private final int mEventType;
private final int mDelay;
public SendAccessibilityEventDelayed(int eventType, int delay) {
mEventType = eventType;
mDelay = delay;
}
public void remove() { public void remove() {
mHandler.removeCallbacks(this); mHandler.removeCallbacks(this);
} }
public void post() { public void post() {
mHandler.postDelayed(this, SEND_INTERACTION_END_EVENTS_TIMEOUT); mHandler.postDelayed(this, mDelay);
} }
public boolean isPending() { public boolean isPending() {
@@ -1556,14 +1588,7 @@ class TouchExplorer implements EventStreamTransformation {
@Override @Override
public void run() { public void run() {
if (mTouchExplorationGestureEnded) { sendAccessibilityEvent(mEventType);
mTouchExplorationGestureEnded = false;
sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END);
}
if (mTouchInteractionEnded) {
mTouchInteractionEnded = false;
sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
}
} }
} }