diff options
| -rw-r--r-- | services/java/com/android/server/accessibility/TouchExplorer.java | 298 |
1 files changed, 123 insertions, 175 deletions
diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java index 4ad291680b44..496210c2a3e8 100644 --- a/services/java/com/android/server/accessibility/TouchExplorer.java +++ b/services/java/com/android/server/accessibility/TouchExplorer.java @@ -21,11 +21,8 @@ import static android.view.accessibility.AccessibilityEvent.TYPE_TOUCH_EXPLORATI import android.content.Context; import android.os.Handler; -import android.os.SystemClock; import android.util.Slog; import android.view.MotionEvent; -import android.view.MotionEvent.PointerCoords; -import android.view.MotionEvent.PointerProperties; import android.view.ViewConfiguration; import android.view.WindowManagerPolicy; import android.view.accessibility.AccessibilityEvent; @@ -75,11 +72,6 @@ public class TouchExplorer implements Explorer { // Invalid pointer ID. private static final int INVALID_POINTER_ID = -1; - // The coefficient by which to multiply - // ViewConfiguration.#getScaledTouchExplorationTapSlop() - // to compute #mDraggingDistance. - private static final int COEFFICIENT_DRAGGING_DISTANCE = 2; - // The time slop in milliseconds for activating an item after it has // been touch explored. Tapping on an item within this slop will perform // a click and tapping and holding down a long press. @@ -95,23 +87,14 @@ public class TouchExplorer implements Explorer { private static final float MIN_ANGLE_COS = 0.866025404f; // cos(pi/6) // The delay for sending a hover enter event. - private static final long DELAY_SEND_HOVER_MOVE = 200; + private static final long DELAY_SEND_HOVER_ENTER = 200; + + // Constant referring to the ids bits of all pointers. + private static final int ALL_POINTER_ID_BITS = 0xFFFFFFFF; // Temporary array for storing pointer IDs. private final int[] mTempPointerIds = new int[MAX_POINTER_COUNT]; - // Temporary array for storing PointerProperties - private final PointerProperties[] mTempPointerProperties = - PointerProperties.createArray(MAX_POINTER_COUNT); - - // Temporary array for storing PointerCoords - private final PointerCoords[] mTempPointerCoords = - PointerCoords.createArray(MAX_POINTER_COUNT); - - // The maximal distance between two pointers so they are - // considered to be performing a drag operation. - private final float mDraggingDistance; - // The distance from the last touch explored location tapping within // which would perform a click and tapping and holding a long press. private final int mTouchExplorationTapSlop; @@ -159,7 +142,6 @@ public class TouchExplorer implements Explorer { mInputFilter = inputFilter; mTouchExplorationTapSlop = ViewConfiguration.get(context).getScaledTouchExplorationTapSlop(); - mDraggingDistance = mTouchExplorationTapSlop * COEFFICIENT_DRAGGING_DISTANCE; mPointerTracker = new PointerTracker(context); mHandler = new Handler(context.getMainLooper()); mSendHoverDelayed = new SendHoverDelayed(); @@ -220,18 +202,21 @@ public class TouchExplorer implements Explorer { + "touch exploring state!"); } case 1: { - // Send hover if pending. - mSendHoverDelayed.forceSendAndRemove(); + mSendHoverDelayed.remove(); // Send a hover for every finger down so the user gets feedback. final int pointerId = pointerTracker.getPrimaryActivePointerId(); final int pointerIdBits = (1 << pointerId); final int lastAction = pointerTracker.getLastInjectedHoverAction(); - // If a hover enter for another pointer is delivered we send move. - final int action = (lastAction == MotionEvent.ACTION_HOVER_ENTER) - ? MotionEvent.ACTION_HOVER_MOVE - : MotionEvent.ACTION_HOVER_ENTER; - mSendHoverDelayed.post(event, action, pointerIdBits, policyFlags, - DELAY_SEND_HOVER_MOVE); + + // Deliver hover enter with a delay to have a change to detect + // whether the user actually starts a scrolling gesture. + if (lastAction == MotionEvent.ACTION_HOVER_EXIT) { + mSendHoverDelayed.post(event, MotionEvent.ACTION_HOVER_ENTER, + pointerIdBits, policyFlags, DELAY_SEND_HOVER_ENTER); + } else { + sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits, + policyFlags); + } if (mLastTouchExploreEvent == null) { break; @@ -318,12 +303,11 @@ public class TouchExplorer implements Explorer { } } break; case 2: { - mSendHoverDelayed.forceSendAndRemove(); + mSendHoverDelayed.remove(); mPerformLongPressDelayed.remove(); // We want to no longer hover over the location so subsequent // touch at the same spot will generate a hover enter. - sendMotionEvent(event, MotionEvent.ACTION_HOVER_EXIT, pointerIdBits, - policyFlags); + ensureHoverExitSent(event, pointerIdBits, policyFlags); if (isDraggingGesture(event)) { // Two pointers moving in the same direction within @@ -340,6 +324,7 @@ public class TouchExplorer implements Explorer { } else { // Two pointers moving arbitrary are delegated to the view hierarchy. mCurrentState = STATE_DELEGATING; + mSendHoverDelayed.remove(); if (mTouchExploreGestureInProgress) { sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_END); mTouchExploreGestureInProgress = false; @@ -349,12 +334,11 @@ public class TouchExplorer implements Explorer { } } break; default: { - mSendHoverDelayed.forceSendAndRemove(); + mSendHoverDelayed.remove(); mPerformLongPressDelayed.remove(); // We want to no longer hover over the location so subsequent // touch at the same spot will generate a hover enter. - sendMotionEvent(event, MotionEvent.ACTION_HOVER_EXIT, pointerIdBits, - policyFlags); + ensureHoverExitSent(event, pointerIdBits, policyFlags); // More than two pointers are delegated to the view hierarchy. mCurrentState = STATE_DELEGATING; @@ -379,8 +363,9 @@ public class TouchExplorer implements Explorer { break; } - mSendHoverDelayed.forceSendAndRemove(); mPerformLongPressDelayed.remove(); + mSendHoverDelayed.forceSendAndRemove(); + ensureHoverExitSent(event, pointerIdBits, policyFlags); // If touch exploring announce the end of the gesture. // Also do not click on the last explored location. @@ -388,11 +373,6 @@ public class TouchExplorer implements Explorer { mTouchExploreGestureInProgress = false; mLastTouchExploreEvent = MotionEvent.obtain(event); sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_END); - final int lastAction = mPointerTracker.getLastInjectedHoverAction(); - if (lastAction != MotionEvent.ACTION_HOVER_EXIT) { - sendMotionEvent(event, MotionEvent.ACTION_HOVER_EXIT, - pointerIdBits, policyFlags); - } break; } @@ -404,11 +384,6 @@ public class TouchExplorer implements Explorer { final long exploreTime = mLastTouchExploreEvent.getEventTime(); final long deltaTime = eventTime - exploreTime; if (deltaTime > ACTIVATION_TIME_SLOP) { - final int lastAction = mPointerTracker.getLastInjectedHoverAction(); - if (lastAction != MotionEvent.ACTION_HOVER_EXIT) { - sendMotionEvent(event, MotionEvent.ACTION_HOVER_EXIT, - pointerIdBits, policyFlags); - } mLastTouchExploreEvent = MotionEvent.obtain(event); break; } @@ -421,11 +396,6 @@ public class TouchExplorer implements Explorer { - event.getY(pointerIndex); final float deltaMove = (float) Math.hypot(deltaX, deltaY); if (deltaMove > mTouchExplorationTapSlop) { - final int lastAction = mPointerTracker.getLastInjectedHoverAction(); - if (lastAction != MotionEvent.ACTION_HOVER_EXIT) { - sendMotionEvent(event, MotionEvent.ACTION_HOVER_EXIT, - pointerIdBits, policyFlags); - } mLastTouchExploreEvent = MotionEvent.obtain(event); break; } @@ -434,12 +404,6 @@ public class TouchExplorer implements Explorer { sendActionDownAndUp(mLastTouchExploreEvent, policyFlags); mLastTouchExploreEvent = null; } else { - mSendHoverDelayed.forceSendAndRemove(); - final int lastAction = mPointerTracker.getLastInjectedHoverAction(); - if (lastAction != MotionEvent.ACTION_HOVER_EXIT) { - sendMotionEvent(event, MotionEvent.ACTION_HOVER_EXIT, - pointerIdBits, policyFlags); - } mLastTouchExploreEvent = MotionEvent.obtain(event); } } break; @@ -448,13 +412,9 @@ public class TouchExplorer implements Explorer { case MotionEvent.ACTION_CANCEL: { mSendHoverDelayed.remove(); mPerformLongPressDelayed.remove(); - final int lastAction = pointerTracker.getLastInjectedHoverAction(); - if (lastAction != MotionEvent.ACTION_HOVER_EXIT) { - final int pointerId = pointerTracker.getPrimaryActivePointerId(); - final int pointerIdBits = (1 << pointerId); - sendMotionEvent(event, MotionEvent.ACTION_HOVER_EXIT, pointerIdBits, - policyFlags); - } + final int pointerId = pointerTracker.getPrimaryActivePointerId(); + final int pointerIdBits = (1 << pointerId); + ensureHoverExitSent(event, pointerIdBits, policyFlags); clear(); } break; } @@ -540,7 +500,8 @@ public class TouchExplorer implements Explorer { // a given distance and if such exist send them to the view hierarchy final int notInjectedCount = mPointerTracker.getNotInjectedActivePointerCount(); if (notInjectedCount > 0) { - sendDownForAllActiveNotInjectedPointers(event, policyFlags); + MotionEvent prototype = MotionEvent.obtain(event); + sendDownForAllActiveNotInjectedPointers(prototype, policyFlags); } } break; case MotionEvent.ACTION_POINTER_UP: { @@ -565,42 +526,47 @@ public class TouchExplorer implements Explorer { * @param policyFlags The policy flags associated with the event. */ private void sendDownForAllActiveNotInjectedPointers(MotionEvent prototype, int policyFlags) { - final PointerProperties[] pointerProperties = mTempPointerProperties; - final PointerCoords[] pointerCoords = mTempPointerCoords; final PointerTracker pointerTracker = mPointerTracker; - int pointerDataIndex = 0; + int pointerIdBits = 0; + final int pointerCount = prototype.getPointerCount(); - final int pinterCount = prototype.getPointerCount(); - for (int i = 0; i < pinterCount; i++) { + // Find which pointers are already injected. + for (int i = 0; i < pointerCount; i++) { final int pointerId = prototype.getPointerId(i); + if (pointerTracker.isInjectedPointerDown(pointerId)) { + pointerIdBits |= (1 << pointerId); + } + } + // Inject the active and not injected pointers. + for (int i = 0; i < pointerCount; i++) { + final int pointerId = prototype.getPointerId(i); // Skip inactive pointers. if (!pointerTracker.isActivePointer(pointerId)) { continue; } - // Skip already delivered pointers. + // Do not send event for already delivered pointers. if (pointerTracker.isInjectedPointerDown(pointerId)) { continue; } + pointerIdBits |= (1 << pointerId); + final int action = computeInjectionAction(MotionEvent.ACTION_DOWN, i); + sendMotionEvent(prototype, action, pointerIdBits, policyFlags); + } + } - // Populate and inject an event for the current pointer. - prototype.getPointerProperties(i, pointerProperties[pointerDataIndex]); - prototype.getPointerCoords(i, pointerCoords[pointerDataIndex]); - - final long downTime = pointerTracker.getLastInjectedDownEventTime(); - final int action = computeInjectionAction(MotionEvent.ACTION_DOWN, pointerDataIndex); - final int pointerCount = pointerDataIndex + 1; - final long eventTime = SystemClock.uptimeMillis(); - - MotionEvent event = MotionEvent.obtain(downTime, eventTime, - action, pointerCount, pointerProperties, pointerCoords, - prototype.getMetaState(), prototype.getButtonState(), - prototype.getXPrecision(), prototype.getYPrecision(), prototype.getDeviceId(), - prototype.getEdgeFlags(), prototype.getSource(), prototype.getFlags()); - sendMotionEvent(event, policyFlags); - event.recycle(); - - pointerDataIndex++; + /** + * Ensures that hover exit has been sent. + * + * @param prototype The prototype from which to create the injected events. + * @param pointerIdBits The bits of the pointers to send. + * @param policyFlags The policy flags associated with the event. + */ + private void ensureHoverExitSent(MotionEvent prototype, int pointerIdBits, int policyFlags) { + final int lastAction = mPointerTracker.getLastInjectedHoverAction(); + if (lastAction != MotionEvent.ACTION_HOVER_EXIT) { + sendMotionEvent(prototype, MotionEvent.ACTION_HOVER_EXIT, pointerIdBits, + policyFlags); } } @@ -613,38 +579,17 @@ public class TouchExplorer implements Explorer { */ private void sendUpForInjectedDownPointers(MotionEvent prototype, int policyFlags) { final PointerTracker pointerTracker = mPointerTracker; - final PointerProperties[] pointerProperties = mTempPointerProperties; - final PointerCoords[] pointerCoords = mTempPointerCoords; - int pointerDataIndex = 0; - - final int pointerCount = prototype.getPointerCount(); + int pointerIdBits = 0; + final int pointerCount = prototype.getPointerCount(); for (int i = 0; i < pointerCount; i++) { final int pointerId = prototype.getPointerId(i); - // Skip non injected down pointers. if (!pointerTracker.isInjectedPointerDown(pointerId)) { continue; } - - // Populate and inject event. - prototype.getPointerProperties(i, pointerProperties[pointerDataIndex]); - prototype.getPointerCoords(i, pointerCoords[pointerDataIndex]); - - final long downTime = pointerTracker.getLastInjectedDownEventTime(); - final int action = computeInjectionAction(MotionEvent.ACTION_UP, pointerDataIndex); - final int newPointerCount = pointerDataIndex + 1; - final long eventTime = SystemClock.uptimeMillis(); - - MotionEvent event = MotionEvent.obtain(downTime, eventTime, action, - newPointerCount, pointerProperties, pointerCoords, - prototype.getMetaState(), prototype.getButtonState(), - prototype.getXPrecision(), prototype.getYPrecision(), prototype.getDeviceId(), - prototype.getEdgeFlags(), prototype.getSource(), prototype.getFlags()); - - sendMotionEvent(event, policyFlags); - event.recycle(); - - pointerDataIndex++; + pointerIdBits |= (1 << pointerId); + final int action = computeInjectionAction(MotionEvent.ACTION_UP, i); + sendMotionEvent(prototype, action, pointerIdBits, policyFlags); } } @@ -659,7 +604,7 @@ public class TouchExplorer implements Explorer { // All pointers active therefore we just inject the event as is. if (prototype.getPointerCount() == pointerTracker.getActivePointerCount()) { - sendMotionEvent(prototype, policyFlags); + sendMotionEvent(prototype, prototype.getAction(), ALL_POINTER_ID_BITS, policyFlags); return; } @@ -670,20 +615,27 @@ public class TouchExplorer implements Explorer { return; } + // If the action pointer going up/down is not active we have nothing to do. + // However, for moves we keep going to report moves of active pointers. + final int actionMasked = prototype.getActionMasked(); + final int actionPointerId = prototype.getPointerId(prototype.getActionIndex()); + if (actionMasked != MotionEvent.ACTION_MOVE) { + if (!pointerTracker.isActiveOrWasLastActiveUpPointer(actionPointerId)) { + return; + } + } + + // If the pointer is active or the pointer that just went up + // was active we keep the pointer data in the event. int pointerIdBits = 0; final int pointerCount = prototype.getPointerCount(); for (int pointerIndex = 0; pointerIndex < pointerCount; pointerIndex++) { final int pointerId = prototype.getPointerId(pointerIndex); - // If the pointer is inactive or the pointer that just went up - // was inactive we strip the pointer data from the event. if (pointerTracker.isActiveOrWasLastActiveUpPointer(pointerId)) { pointerIdBits |= (1 << pointerId); } } - - MotionEvent event = prototype.split(pointerIdBits); - sendMotionEvent(event, policyFlags); - event.recycle(); + sendMotionEvent(prototype, prototype.getAction(), pointerIdBits, policyFlags); } /** @@ -693,26 +645,11 @@ public class TouchExplorer implements Explorer { * @param policyFlags The policy flags associated with the event. */ private void sendActionDownAndUp(MotionEvent prototype, int policyFlags) { - final PointerProperties[] pointerProperties = mTempPointerProperties; - final PointerCoords[] pointerCoords = mTempPointerCoords; - final int pointerIndex = prototype.getActionIndex(); - - // Send down. - prototype.getPointerProperties(pointerIndex, pointerProperties[0]); - prototype.getPointerCoords(pointerIndex, pointerCoords[0]); - - final long downTime = SystemClock.uptimeMillis(); - MotionEvent event = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_DOWN, - 1, pointerProperties, pointerCoords, - prototype.getMetaState(), prototype.getButtonState(), - prototype.getXPrecision(), prototype.getYPrecision(), prototype.getDeviceId(), - prototype.getEdgeFlags(), prototype.getSource(), prototype.getFlags()); - sendMotionEvent(event, policyFlags); - - // Send up. - event.setAction(MotionEvent.ACTION_UP); - sendMotionEvent(event, policyFlags); - event.recycle(); + // Tap with the pointer that last went up - we may have inactive pointers. + final int pointerId = mPointerTracker.getLastReceivedUpPointerId(); + final int pointerIdBits = (1 << pointerId); + sendMotionEvent(prototype, MotionEvent.ACTION_DOWN, pointerIdBits, policyFlags); + sendMotionEvent(prototype, MotionEvent.ACTION_UP, pointerIdBits, policyFlags); } /** @@ -725,11 +662,33 @@ public class TouchExplorer implements Explorer { */ private void sendMotionEvent(MotionEvent prototype, int action, int pointerIdBits, int policyFlags) { - MotionEvent event = prototype.split(pointerIdBits); - event.setDownTime(mPointerTracker.getLastInjectedDownEventTime()); - event.setAction(action); - sendMotionEvent(event, policyFlags); - event.recycle(); + prototype.setAction(action); + + MotionEvent event = null; + if (pointerIdBits == ALL_POINTER_ID_BITS) { + event = prototype; + } else { + event = prototype.split(pointerIdBits); + } + if (action == MotionEvent.ACTION_DOWN) { + event.setDownTime(event.getEventTime()); + } else { + event.setDownTime(mPointerTracker.getLastInjectedDownEventTime()); + } + + if (DEBUG) { + Slog.d(LOG_TAG_INJECTED, "Injecting event: " + event + ", policyFlags=0x" + + Integer.toHexString(policyFlags)); + } + + // Make sure that the user will see the event. + policyFlags |= WindowManagerPolicy.FLAG_PASS_TO_USER; + mPointerTracker.onInjectedMotionEvent(event); + mInputFilter.sendInputEvent(event, policyFlags); + + if (event != prototype) { + event.recycle(); + } } /** @@ -787,19 +746,16 @@ public class TouchExplorer implements Explorer { final float secondPtrX = event.getX(secondPtrIndex); final float secondPtrY = event.getY(secondPtrIndex); - // Check if the pointers are close enough. - final float deltaX = firstPtrX - secondPtrX; - final float deltaY = firstPtrY - secondPtrY; - final float deltaMove = (float) Math.hypot(deltaX, deltaY); - if (deltaMove > mDraggingDistance) { - return false; - } - // Check if the pointers are moving in the same direction. final float firstDeltaX = firstPtrX - pointerTracker.getReceivedPointerDownX(firstPtrIndex); final float firstDeltaY = firstPtrY - pointerTracker.getReceivedPointerDownY(firstPtrIndex); + + if (firstDeltaX == 0 && firstDeltaY == 0) { + return true; + } + final float firstMagnitude = (float) Math.sqrt(firstDeltaX * firstDeltaX + firstDeltaY * firstDeltaY); final float firstXNormalized = @@ -811,6 +767,11 @@ public class TouchExplorer implements Explorer { secondPtrX - pointerTracker.getReceivedPointerDownX(secondPtrIndex); final float secondDeltaY = secondPtrY - pointerTracker.getReceivedPointerDownY(secondPtrIndex); + + if (secondDeltaX == 0 && secondDeltaY == 0) { + return true; + } + final float secondMagnitude = (float) Math.sqrt(secondDeltaX * secondDeltaX + secondDeltaY * secondDeltaY); final float secondXNormalized = @@ -839,23 +800,6 @@ public class TouchExplorer implements Explorer { } /** - * Sends a motion event to the input filter for injection. - * - * @param event The event to send. - * @param policyFlags The policy flags associated with the event. - */ - private void sendMotionEvent(MotionEvent event, int policyFlags) { - if (DEBUG) { - Slog.d(LOG_TAG_INJECTED, "Injecting event: " + event + ", policyFlags=0x" - + Integer.toHexString(policyFlags)); - } - // Make sure that the user will see the event. - policyFlags |= WindowManagerPolicy.FLAG_PASS_TO_USER; - mPointerTracker.onInjectedMotionEvent(event); - mInputFilter.sendInputEvent(event, policyFlags); - } - - /** * Clears the internal state of this explorer. */ public void clear() { @@ -1013,6 +957,7 @@ public class TouchExplorer implements Explorer { switch (action) { case MotionEvent.ACTION_DOWN: { handleInjectedPointerDown(event.getActionIndex(), event); + mLastInjectedDownEventTime = event.getDownTime(); } break; case MotionEvent.ACTION_POINTER_DOWN: { handleInjectedPointerDown(event.getActionIndex(), event); @@ -1270,7 +1215,6 @@ public class TouchExplorer implements Explorer { final int pointerId = event.getPointerId(pointerIndex); final int pointerFlag = (1 << pointerId); mInjectedPointersDown |= pointerFlag; - mLastInjectedDownEventTime = event.getEventTime(); } /** @@ -1406,7 +1350,11 @@ public class TouchExplorer implements Explorer { public void run() { mCurrentState = STATE_DELEGATING; // Make sure the scheduled hover exit is delivered. - mSendHoverDelayed.forceSendAndRemove(); + mSendHoverDelayed.remove(); + final int pointerId = mPointerTracker.getPrimaryActivePointerId(); + final int pointerIdBits = (1 << pointerId); + ensureHoverExitSent(mEvent, pointerIdBits, mPolicyFlags); + sendDownForAllActiveNotInjectedPointers(mEvent, mPolicyFlags); mTouchExploreGestureInProgress = false; mLastTouchExploreEvent = null; |