Skip to content

Commit fefd20e

Browse files
committed
Adding an opt-in mechanism for gesture detection in AccessibilityService.
1. An accessibility service has to explicitly opt in to be notified for gestures by the system. There is only one accessibility service that handles gestures and in case it does not handle a gesture the system performs default handling. This default handling ensures that we have gesture navigation even if no accessibility service would like to participate/customize the interaction model. bug:5932640 Change-Id: Id8194293bd94097b455e9388b68134a45dc3b8fa
1 parent 749e796 commit fefd20e

File tree

13 files changed

+402
-133
lines changed

13 files changed

+402
-133
lines changed

Android.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ LOCAL_SRC_FILES := $(filter-out \
6161
LOCAL_SRC_FILES += \
6262
core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl \
6363
core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl \
64+
core/java/android/accessibilityservice/IAccessibilityServiceClientCallback.aidl \
6465
core/java/android/accounts/IAccountManager.aidl \
6566
core/java/android/accounts/IAccountManagerResponse.aidl \
6667
core/java/android/accounts/IAccountAuthenticator.aidl \

api/current.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,7 @@ package android {
294294
field public static final int cacheColorHint = 16843009; // 0x1010101
295295
field public static final int calendarViewShown = 16843596; // 0x101034c
296296
field public static final int calendarViewStyle = 16843613; // 0x101035d
297+
field public static final int canHandleGestures = 16843699; // 0x10103b3
297298
field public static final int canRetrieveWindowContent = 16843653; // 0x1010385
298299
field public static final int candidatesTextStyleSpans = 16843312; // 0x1010230
299300
field public static final deprecated int capitalize = 16843113; // 0x1010169
@@ -1997,7 +1998,7 @@ package android.accessibilityservice {
19971998
method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
19981999
method public abstract void onAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
19992000
method public final android.os.IBinder onBind(android.content.Intent);
2000-
method protected void onGesture(int);
2001+
method protected boolean onGesture(int);
20012002
method public abstract void onInterrupt();
20022003
method protected void onServiceConnected();
20032004
method public final boolean performGlobalAction(int);
@@ -2020,6 +2021,8 @@ package android.accessibilityservice {
20202021
field public static final int GESTURE_SWIPE_UP_AND_DOWN = 7; // 0x7
20212022
field public static final int GESTURE_SWIPE_UP_AND_LEFT = 15; // 0xf
20222023
field public static final int GESTURE_SWIPE_UP_AND_RIGHT = 16; // 0x10
2024+
field public static final int GESTURE_TWO_FINGER_LONG_PRESS = 20; // 0x14
2025+
field public static final int GESTURE_TWO_FINGER_TAP = 19; // 0x13
20232026
field public static final int GLOBAL_ACTION_BACK = 1; // 0x1
20242027
field public static final int GLOBAL_ACTION_HOME = 2; // 0x2
20252028
field public static final int GLOBAL_ACTION_NOTIFICATIONS = 4; // 0x4
@@ -2033,6 +2036,7 @@ package android.accessibilityservice {
20332036
method public int describeContents();
20342037
method public static java.lang.String feedbackTypeToString(int);
20352038
method public static java.lang.String flagToString(int);
2039+
method public boolean getCanHandleGestures();
20362040
method public boolean getCanRetrieveWindowContent();
20372041
method public deprecated java.lang.String getDescription();
20382042
method public java.lang.String getId();

core/java/android/accessibilityservice/AccessibilityService.java

Lines changed: 53 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,17 @@
1919
import android.app.Service;
2020
import android.content.Context;
2121
import android.content.Intent;
22-
import android.content.res.Configuration;
2322
import android.os.IBinder;
2423
import android.os.Looper;
2524
import android.os.Message;
2625
import android.os.RemoteException;
27-
import android.util.LocaleUtil;
2826
import android.util.Log;
29-
import android.view.View;
3027
import android.view.accessibility.AccessibilityEvent;
3128
import android.view.accessibility.AccessibilityInteractionClient;
3229
import android.view.accessibility.AccessibilityNodeInfo;
3330

3431
import 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>&lt;{@link android.R.styleable#AccessibilityService_canHandleGestures
397+
* canHandleGestures}&gt;</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);

core/java/android/accessibilityservice/AccessibilityServiceInfo.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,11 @@ public class AccessibilityServiceInfo implements Parcelable {
223223
*/
224224
private boolean mCanRetrieveWindowContent;
225225

226+
/**
227+
* Flag whether this accessibility service can handle gestures.
228+
*/
229+
private boolean mCanHandleGestures;
230+
226231
/**
227232
* Resource id of the description of the accessibility service.
228233
*/
@@ -303,6 +308,8 @@ public AccessibilityServiceInfo(ResolveInfo resolveInfo, Context context)
303308
mCanRetrieveWindowContent = asAttributes.getBoolean(
304309
com.android.internal.R.styleable.AccessibilityService_canRetrieveWindowContent,
305310
false);
311+
mCanHandleGestures = asAttributes.getBoolean(
312+
com.android.internal.R.styleable.AccessibilityService_canHandleGestures, false);
306313
TypedValue peekedValue = asAttributes.peekValue(
307314
com.android.internal.R.styleable.AccessibilityService_description);
308315
if (peekedValue != null) {
@@ -378,12 +385,24 @@ public String getSettingsActivityName() {
378385
* <strong>Statically set from
379386
* {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
380387
* </p>
381-
* @return True window content can be retrieved.
388+
* @return True if window content can be retrieved.
382389
*/
383390
public boolean getCanRetrieveWindowContent() {
384391
return mCanRetrieveWindowContent;
385392
}
386393

394+
/**
395+
* Whether this service can handle gestures.
396+
* <p>
397+
* <strong>Statically set from
398+
* {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
399+
* </p>
400+
* @return True if the service can handle gestures.
401+
*/
402+
public boolean getCanHandleGestures() {
403+
return mCanHandleGestures;
404+
}
405+
387406
/**
388407
* Gets the non-localized description of the accessibility service.
389408
* <p>

core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package android.accessibilityservice;
1818

19+
import android.accessibilityservice.IAccessibilityServiceClientCallback;
1920
import android.accessibilityservice.IAccessibilityServiceConnection;
2021
import android.view.accessibility.AccessibilityEvent;
2122

@@ -32,5 +33,5 @@ import android.view.accessibility.AccessibilityEvent;
3233

3334
void onInterrupt();
3435

35-
void onGesture(int gestureId);
36+
void onGesture(int gesture, in IAccessibilityServiceClientCallback callback, int interactionId);
3637
}

0 commit comments

Comments
 (0)