1919import android .app .Service ;
2020import android .content .Context ;
2121import android .content .Intent ;
22- import android .content .res .Configuration ;
2322import android .os .IBinder ;
2423import android .os .Looper ;
2524import android .os .Message ;
2625import android .os .RemoteException ;
27- import android .util .LocaleUtil ;
2826import android .util .Log ;
29- import android .view .View ;
3027import android .view .accessibility .AccessibilityEvent ;
3128import android .view .accessibility .AccessibilityInteractionClient ;
3229import android .view .accessibility .AccessibilityNodeInfo ;
3330
3431import com .android .internal .os .HandlerCaller ;
3532
36- import java .util .Locale ;
37-
3833/**
3934 * An accessibility service runs in the background and receives callbacks by the system
4035 * when {@link AccessibilityEvent}s are fired. Such events denote some state transition
@@ -298,6 +293,16 @@ public abstract class AccessibilityService extends Service {
298293 */
299294 public static final int GESTURE_SWIPE_DOWN_AND_RIGHT = 18 ;
300295
296+ /**
297+ * The user has performed a two finger tap gesture on the touch screen.
298+ */
299+ public static final int GESTURE_TWO_FINGER_TAP = 19 ;
300+
301+ /**
302+ * The user has performed a two finger long press gesture on the touch screen.
303+ */
304+ public static final int GESTURE_TWO_FINGER_LONG_PRESS = 20 ;
305+
301306 /**
302307 * The {@link Intent} that must be declared as handled by the service.
303308 */
@@ -342,24 +347,20 @@ public abstract class AccessibilityService extends Service {
342347 */
343348 public static final int GLOBAL_ACTION_NOTIFICATIONS = 4 ;
344349
345- private static final int UNDEFINED = -1 ;
346-
347350 private static final String LOG_TAG = "AccessibilityService" ;
348351
349352 interface Callbacks {
350353 public void onAccessibilityEvent (AccessibilityEvent event );
351354 public void onInterrupt ();
352355 public void onServiceConnected ();
353356 public void onSetConnectionId (int connectionId );
354- public void onGesture (int gestureId );
357+ public boolean onGesture (int gestureId );
355358 }
356359
357360 private int mConnectionId ;
358361
359362 private AccessibilityServiceInfo mInfo ;
360363
361- private int mLayoutDirection ;
362-
363364 /**
364365 * Callback for {@link android.view.accessibility.AccessibilityEvent}s.
365366 *
@@ -386,95 +387,43 @@ protected void onServiceConnected() {
386387
387388 /**
388389 * Called by the system when the user performs a specific gesture on the
389- * touch screen.
390+ * touch screen. If the gesture is not handled in this callback the system
391+ * may provide default handing. Therefore, one should return true from this
392+ * function if overriding of default behavior is desired.
393+ *
394+ * <strong>Note:</strong> To receive gestures an accessibility service
395+ * must declare that it can handle such by specifying the
396+ * <code><{@link android.R.styleable#AccessibilityService_canHandleGestures
397+ * canHandleGestures}></code> attribute.
390398 *
391399 * @param gestureId The unique id of the performed gesture.
392400 *
401+ * @return Whether the gesture was handled.
402+ *
393403 * @see #GESTURE_SWIPE_UP
394- * @see #GESTURE_SWIPE_DOWN
395- * @see #GESTURE_SWIPE_LEFT
396- * @see #GESTURE_SWIPE_RIGHT
404+ * @see #GESTURE_SWIPE_UP_AND_LEFT
397405 * @see #GESTURE_SWIPE_UP_AND_DOWN
406+ * @see #GESTURE_SWIPE_UP_AND_RIGHT
407+ * @see #GESTURE_SWIPE_DOWN
408+ * @see #GESTURE_SWIPE_DOWN_AND_LEFT
398409 * @see #GESTURE_SWIPE_DOWN_AND_UP
410+ * @see #GESTURE_SWIPE_DOWN_AND_RIGHT
411+ * @see #GESTURE_SWIPE_LEFT
412+ * @see #GESTURE_SWIPE_LEFT_AND_UP
399413 * @see #GESTURE_SWIPE_LEFT_AND_RIGHT
414+ * @see #GESTURE_SWIPE_LEFT_AND_DOWN
415+ * @see #GESTURE_SWIPE_RIGHT
416+ * @see #GESTURE_SWIPE_RIGHT_AND_UP
400417 * @see #GESTURE_SWIPE_RIGHT_AND_LEFT
418+ * @see #GESTURE_SWIPE_RIGHT_AND_DOWN
401419 * @see #GESTURE_CLOCKWISE_CIRCLE
402420 * @see #GESTURE_COUNTER_CLOCKWISE_CIRCLE
421+ * @see #GESTURE_TWO_FINGER_TAP
422+ * @see #GESTURE_TWO_FINGER_LONG_PRESS
403423 */
404- protected void onGesture (int gestureId ) {
424+ protected boolean onGesture (int gestureId ) {
405425 // TODO: Describe the default gesture processing in the javaDoc once it is finalized.
406-
407- // Global actions.
408- switch (gestureId ) {
409- case GESTURE_SWIPE_DOWN_AND_LEFT : {
410- performGlobalAction (GLOBAL_ACTION_BACK );
411- } return ;
412- case GESTURE_SWIPE_DOWN_AND_RIGHT : {
413- performGlobalAction (GLOBAL_ACTION_HOME );
414- } return ;
415- case GESTURE_SWIPE_UP_AND_LEFT : {
416- performGlobalAction (GLOBAL_ACTION_RECENTS );
417- } return ;
418- case GESTURE_SWIPE_UP_AND_RIGHT : {
419- performGlobalAction (GLOBAL_ACTION_NOTIFICATIONS );
420- } return ;
421- }
422-
423- // Cache the id to avoid locking
424- final int connectionId = mConnectionId ;
425- if (connectionId == UNDEFINED ) {
426- throw new IllegalStateException ("AccessibilityService not connected."
427- + " Did you receive a call of onServiceConnected()?" );
428- }
429- AccessibilityNodeInfo root = getRootInActiveWindow ();
430- if (root == null ) {
431- return ;
432- }
433-
434- AccessibilityNodeInfo current = root .findFocus (AccessibilityNodeInfo .FOCUS_ACCESSIBILITY );
435- if (current == null ) {
436- current = root ;
437- }
438-
439- // Local actions.
440- AccessibilityNodeInfo next = null ;
441- switch (gestureId ) {
442- case GESTURE_SWIPE_UP : {
443- next = current .focusSearch (View .ACCESSIBILITY_FOCUS_OUT );
444- } break ;
445- case GESTURE_SWIPE_DOWN : {
446- next = current .focusSearch (View .ACCESSIBILITY_FOCUS_IN );
447- } break ;
448- case GESTURE_SWIPE_LEFT : {
449- if (mLayoutDirection == View .LAYOUT_DIRECTION_LTR ) {
450- next = current .focusSearch (View .ACCESSIBILITY_FOCUS_BACKWARD );
451- } else { // LAYOUT_DIRECTION_RTL
452- next = current .focusSearch (View .ACCESSIBILITY_FOCUS_FORWARD );
453- }
454- } break ;
455- case GESTURE_SWIPE_RIGHT : {
456- if (mLayoutDirection == View .LAYOUT_DIRECTION_LTR ) {
457- next = current .focusSearch (View .ACCESSIBILITY_FOCUS_FORWARD );
458- } else { // LAYOUT_DIRECTION_RTL
459- next = current .focusSearch (View .ACCESSIBILITY_FOCUS_BACKWARD );
460- }
461- } break ;
462- case GESTURE_SWIPE_UP_AND_DOWN : {
463- next = current .focusSearch (View .ACCESSIBILITY_FOCUS_UP );
464- } break ;
465- case GESTURE_SWIPE_DOWN_AND_UP : {
466- next = current .focusSearch (View .ACCESSIBILITY_FOCUS_DOWN );
467- } break ;
468- case GESTURE_SWIPE_LEFT_AND_RIGHT : {
469- next = current .focusSearch (View .ACCESSIBILITY_FOCUS_LEFT );
470- } break ;
471- case GESTURE_SWIPE_RIGHT_AND_LEFT : {
472- next = current .focusSearch (View .ACCESSIBILITY_FOCUS_RIGHT );
473- } break ;
474- }
475- if (next != null && !next .equals (current )) {
476- next .performAction (AccessibilityNodeInfo .ACTION_ACCESSIBILITY_FOCUS );
477- }
426+ return false ;
478427 }
479428
480429 /**
@@ -484,10 +433,7 @@ protected void onGesture(int gestureId) {
484433 * @return The root node if this service can retrieve window content.
485434 */
486435 public AccessibilityNodeInfo getRootInActiveWindow () {
487- return AccessibilityInteractionClient .getInstance ()
488- .findAccessibilityNodeInfoByAccessibilityId (mConnectionId ,
489- AccessibilityNodeInfo .ACTIVE_WINDOW_ID , AccessibilityNodeInfo .ROOT_NODE_ID ,
490- AccessibilityNodeInfo .FLAG_PREFETCH_DESCENDANTS );
436+ return AccessibilityInteractionClient .getInstance ().getRootInActiveWindow (mConnectionId );
491437 }
492438
493439 /**
@@ -509,7 +455,7 @@ public final boolean performGlobalAction(int action) {
509455 AccessibilityInteractionClient .getInstance ().getConnection (mConnectionId );
510456 if (connection != null ) {
511457 try {
512- return connection .perfromGlobalAction (action );
458+ return connection .performGlobalAction (action );
513459 } catch (RemoteException re ) {
514460 Log .w (LOG_TAG , "Error while calling performGlobalAction" , re );
515461 }
@@ -572,18 +518,6 @@ private void sendServiceInfo() {
572518 }
573519 }
574520
575- @ Override
576- public void onCreate () {
577- Locale locale = getResources ().getConfiguration ().locale ;
578- mLayoutDirection = LocaleUtil .getLayoutDirectionFromLocale (locale );
579- }
580-
581- @ Override
582- public void onConfigurationChanged (Configuration configuration ) {
583- super .onConfigurationChanged (configuration );
584- mLayoutDirection = LocaleUtil .getLayoutDirectionFromLocale (configuration .locale );
585- }
586-
587521 /**
588522 * Implement to return the implementation of the internal accessibility
589523 * service interface.
@@ -612,8 +546,8 @@ public void onSetConnectionId( int connectionId) {
612546 }
613547
614548 @ Override
615- public void onGesture (int gestureId ) {
616- AccessibilityService .this .onGesture (gestureId );
549+ public boolean onGesture (int gestureId ) {
550+ return AccessibilityService .this .onGesture (gestureId );
617551 }
618552 });
619553 }
@@ -658,8 +592,10 @@ public void onAccessibilityEvent(AccessibilityEvent event) {
658592 mCaller .sendMessage (message );
659593 }
660594
661- public void onGesture (int gestureId ) {
662- Message message = mCaller .obtainMessageI (DO_ON_GESTURE , gestureId );
595+ public void onGesture (int gestureId , IAccessibilityServiceClientCallback callback ,
596+ int interactionId ) {
597+ Message message = mCaller .obtainMessageIIO (DO_ON_GESTURE , gestureId , interactionId ,
598+ callback );
663599 mCaller .sendMessage (message );
664600 }
665601
@@ -692,7 +628,15 @@ public void executeMessage(Message message) {
692628 return ;
693629 case DO_ON_GESTURE :
694630 final int gestureId = message .arg1 ;
695- mCallback .onGesture (gestureId );
631+ final int interactionId = message .arg2 ;
632+ IAccessibilityServiceClientCallback callback =
633+ (IAccessibilityServiceClientCallback ) message .obj ;
634+ final boolean handled = mCallback .onGesture (gestureId );
635+ try {
636+ callback .setGestureResult (gestureId , handled , interactionId );
637+ } catch (RemoteException re ) {
638+ Log .e (LOG_TAG , "Error calling back with the gesture resut." , re );
639+ }
696640 return ;
697641 default :
698642 Log .w (LOG_TAG , "Unknown message type " + message .what );
0 commit comments