Skip to content

Commit 005b83b

Browse files
committed
Adding some more gestures and actions for accessibility.
1. Added more gesture for accessibility. After a meeting with the access-eng team we have decided that the current set of gestures may be smaller than needed considering that we will use four gestures for home, back, recents, and notifications. 2. Adding actions for going back, home, opening the recents, and opening the notifications. 3. Added preliminary mapping from some of the new gestures to the new actions. 4. Fixed a bug in the accessibility interaction controller which was trying to create a handled on the main looper thread which may be null if the queried UI is in the system process. Now the context looper of the root view is used. 5. Fixed a bug of using an incorrect constant. 6. Added a missing locking in a couple of places. 7. Fixed view comparison for accessibilityt since it was not anisymmetric. bug:5932640 bug:5605641 Change-Id: Icc983bf4eafefa42b65920b3782ed8a25518e94f
1 parent b3830f6 commit 005b83b

File tree

10 files changed

+235
-45
lines changed

10 files changed

+235
-45
lines changed

api/current.txt

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2000,17 +2000,30 @@ package android.accessibilityservice {
20002000
method protected void onGesture(int);
20012001
method public abstract void onInterrupt();
20022002
method protected void onServiceConnected();
2003+
method public final boolean performGlobalAction(int);
20032004
method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo);
20042005
field public static final int GESTURE_CLOCKWISE_CIRCLE = 9; // 0x9
20052006
field public static final int GESTURE_COUNTER_CLOCKWISE_CIRCLE = 10; // 0xa
20062007
field public static final int GESTURE_SWIPE_DOWN = 2; // 0x2
2008+
field public static final int GESTURE_SWIPE_DOWN_AND_LEFT = 17; // 0x11
2009+
field public static final int GESTURE_SWIPE_DOWN_AND_RIGHT = 18; // 0x12
20072010
field public static final int GESTURE_SWIPE_DOWN_AND_UP = 8; // 0x8
20082011
field public static final int GESTURE_SWIPE_LEFT = 3; // 0x3
2012+
field public static final int GESTURE_SWIPE_LEFT_AND_DOWN = 12; // 0xc
20092013
field public static final int GESTURE_SWIPE_LEFT_AND_RIGHT = 5; // 0x5
2014+
field public static final int GESTURE_SWIPE_LEFT_AND_UP = 11; // 0xb
20102015
field public static final int GESTURE_SWIPE_RIGHT = 4; // 0x4
2016+
field public static final int GESTURE_SWIPE_RIGHT_AND_DOWN = 14; // 0xe
20112017
field public static final int GESTURE_SWIPE_RIGHT_AND_LEFT = 6; // 0x6
2018+
field public static final int GESTURE_SWIPE_RIGHT_AND_UP = 13; // 0xd
20122019
field public static final int GESTURE_SWIPE_UP = 1; // 0x1
20132020
field public static final int GESTURE_SWIPE_UP_AND_DOWN = 7; // 0x7
2021+
field public static final int GESTURE_SWIPE_UP_AND_LEFT = 15; // 0xf
2022+
field public static final int GESTURE_SWIPE_UP_AND_RIGHT = 16; // 0x10
2023+
field public static final int GLOBAL_ACTION_BACK = 1; // 0x1
2024+
field public static final int GLOBAL_ACTION_HOME = 2; // 0x2
2025+
field public static final int GLOBAL_ACTION_NOTIFICATIONS = 4; // 0x4
2026+
field public static final int GLOBAL_ACTION_RECENTS = 3; // 0x3
20142027
field public static final java.lang.String SERVICE_INTERFACE = "android.accessibilityservice.AccessibilityService";
20152028
field public static final java.lang.String SERVICE_META_DATA = "android.accessibilityservice";
20162029
}
@@ -24742,12 +24755,13 @@ package android.view.accessibility {
2474224755
method public void setSource(android.view.View, int);
2474324756
method public void setText(java.lang.CharSequence);
2474424757
method public void writeToParcel(android.os.Parcel, int);
24745-
field public static final int ACTION_ACCESSIBILITY_FOCUS = 16; // 0x10
24746-
field public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 32; // 0x20
24758+
field public static final int ACTION_ACCESSIBILITY_FOCUS = 64; // 0x40
24759+
field public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 128; // 0x80
2474724760
field public static final int ACTION_CLEAR_FOCUS = 2; // 0x2
2474824761
field public static final int ACTION_CLEAR_SELECTION = 8; // 0x8
24749-
field public static final int ACTION_CLICK = 64; // 0x40
24762+
field public static final int ACTION_CLICK = 16; // 0x10
2475024763
field public static final int ACTION_FOCUS = 1; // 0x1
24764+
field public static final int ACTION_LONG_CLICK = 32; // 0x20
2475124765
field public static final int ACTION_SELECT = 4; // 0x4
2475224766
field public static final android.os.Parcelable.Creator CREATOR;
2475324767
field public static final int FOCUS_ACCESSIBILITY = 2; // 0x2

core/java/android/accessibilityservice/AccessibilityService.java

Lines changed: 108 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -258,14 +258,52 @@ public abstract class AccessibilityService extends Service {
258258
*/
259259
public static final int GESTURE_COUNTER_CLOCKWISE_CIRCLE = 10;
260260

261+
/**
262+
* The user has performed a left and up gesture on the touch screen.
263+
*/
264+
public static final int GESTURE_SWIPE_LEFT_AND_UP = 11;
265+
266+
/**
267+
* The user has performed a left and down gesture on the touch screen.
268+
*/
269+
public static final int GESTURE_SWIPE_LEFT_AND_DOWN = 12;
270+
271+
/**
272+
* The user has performed a right and up gesture on the touch screen.
273+
*/
274+
public static final int GESTURE_SWIPE_RIGHT_AND_UP = 13;
275+
276+
/**
277+
* The user has performed a right and down gesture on the touch screen.
278+
*/
279+
public static final int GESTURE_SWIPE_RIGHT_AND_DOWN = 14;
280+
281+
/**
282+
* The user has performed an up and left gesture on the touch screen.
283+
*/
284+
public static final int GESTURE_SWIPE_UP_AND_LEFT = 15;
285+
286+
/**
287+
* The user has performed an up and right gesture on the touch screen.
288+
*/
289+
public static final int GESTURE_SWIPE_UP_AND_RIGHT = 16;
290+
291+
/**
292+
* The user has performed an down and left gesture on the touch screen.
293+
*/
294+
public static final int GESTURE_SWIPE_DOWN_AND_LEFT = 17;
295+
296+
/**
297+
* The user has performed an down and right gesture on the touch screen.
298+
*/
299+
public static final int GESTURE_SWIPE_DOWN_AND_RIGHT = 18;
300+
261301
/**
262302
* The {@link Intent} that must be declared as handled by the service.
263303
*/
264304
public static final String SERVICE_INTERFACE =
265305
"android.accessibilityservice.AccessibilityService";
266306

267-
private static final int UNDEFINED = -1;
268-
269307
/**
270308
* Name under which an AccessibilityService component publishes information
271309
* about itself. This meta-data must reference an XML resource containing an
@@ -284,6 +322,28 @@ public abstract class AccessibilityService extends Service {
284322
*/
285323
public static final String SERVICE_META_DATA = "android.accessibilityservice";
286324

325+
/**
326+
* Action to go back.
327+
*/
328+
public static final int GLOBAL_ACTION_BACK = 1;
329+
330+
/**
331+
* Action to go home.
332+
*/
333+
public static final int GLOBAL_ACTION_HOME = 2;
334+
335+
/**
336+
* Action to open the recents.
337+
*/
338+
public static final int GLOBAL_ACTION_RECENTS = 3;
339+
340+
/**
341+
* Action to open the notifications.
342+
*/
343+
public static final int GLOBAL_ACTION_NOTIFICATIONS = 4;
344+
345+
private static final int UNDEFINED = -1;
346+
287347
private static final String LOG_TAG = "AccessibilityService";
288348

289349
interface Callbacks {
@@ -344,6 +404,22 @@ protected void onServiceConnected() {
344404
protected void onGesture(int gestureId) {
345405
// TODO: Describe the default gesture processing in the javaDoc once it is finalized.
346406

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+
347423
// Cache the id to avoid locking
348424
final int connectionId = mConnectionId;
349425
if (connectionId == UNDEFINED) {
@@ -357,10 +433,12 @@ protected void onGesture(int gestureId) {
357433
if (root == null) {
358434
return;
359435
}
360-
AccessibilityNodeInfo current = root.findFocus(View.FOCUS_ACCESSIBILITY);
436+
AccessibilityNodeInfo current = root.findFocus(AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
361437
if (current == null) {
362438
current = root;
363439
}
440+
441+
// Local actions.
364442
AccessibilityNodeInfo next = null;
365443
switch (gestureId) {
366444
case GESTURE_SWIPE_UP: {
@@ -401,6 +479,33 @@ protected void onGesture(int gestureId) {
401479
}
402480
}
403481

482+
/**
483+
* Performs a global action. Such an action can be performed
484+
* at any moment regardless of the current application or user
485+
* location in that application. For example going back, going
486+
* home, opening recents, etc.
487+
*
488+
* @param action The action to perform.
489+
* @return Whether the action was successfully performed.
490+
*
491+
* @see #GLOBAL_ACTION_BACK
492+
* @see #GLOBAL_ACTION_HOME
493+
* @see #GLOBAL_ACTION_NOTIFICATIONS
494+
* @see #GLOBAL_ACTION_RECENTS
495+
*/
496+
public final boolean performGlobalAction(int action) {
497+
IAccessibilityServiceConnection connection =
498+
AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
499+
if (connection != null) {
500+
try {
501+
return connection.perfromGlobalAction(action);
502+
} catch (RemoteException re) {
503+
Log.w(LOG_TAG, "Error while calling performGlobalAction", re);
504+
}
505+
}
506+
return false;
507+
}
508+
404509
/**
405510
* Gets the an {@link AccessibilityServiceInfo} describing this
406511
* {@link AccessibilityService}. This method is useful if one wants

core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,4 +160,12 @@ interface IAccessibilityServiceConnection {
160160
* @return The associated accessibility service info.
161161
*/
162162
AccessibilityServiceInfo getServiceInfo();
163+
164+
/**
165+
* Performs a global action, such as going home, going back, etc.
166+
*
167+
* @param action The action to perform.
168+
* @return Whether the action was performed.
169+
*/
170+
boolean perfromGlobalAction(int action);
163171
}

core/java/android/view/AccessibilityInteractionController.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,16 @@ final class AccessibilityInteractionController {
5252
private ArrayList<AccessibilityNodeInfo> mTempAccessibilityNodeInfoList =
5353
new ArrayList<AccessibilityNodeInfo>();
5454

55-
private final Handler mHandler = new PrivateHandler();
55+
private final Handler mHandler;
5656

5757
private final ViewRootImpl mViewRootImpl;
5858

5959
private final AccessibilityNodePrefetcher mPrefetcher;
6060

6161
public AccessibilityInteractionController(ViewRootImpl viewRootImpl) {
62+
// mView is never null - the caller has already checked.
63+
Looper looper = viewRootImpl.mView.mContext.getMainLooper();
64+
mHandler = new PrivateHandler(looper);
6265
mViewRootImpl = viewRootImpl;
6366
mPrefetcher = new AccessibilityNodePrefetcher();
6467
}
@@ -846,8 +849,8 @@ private class PrivateHandler extends Handler {
846849
private final static int MSG_FIND_FOCUS = 5;
847850
private final static int MSG_FOCUS_SEARCH = 6;
848851

849-
public PrivateHandler() {
850-
super(Looper.getMainLooper());
852+
public PrivateHandler(Looper looper) {
853+
super(looper);
851854
}
852855

853856
@Override

core/java/android/view/View.java

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6352,16 +6352,14 @@ public void resetAccessibilityStateChanged() {
63526352
public boolean performAccessibilityAction(int action) {
63536353
switch (action) {
63546354
case AccessibilityNodeInfo.ACTION_CLICK: {
6355-
final long now = SystemClock.uptimeMillis();
6356-
// Send down.
6357-
MotionEvent event = MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN,
6358-
getWidth() / 2, getHeight() / 2, 0);
6359-
onTouchEvent(event);
6360-
// Send up.
6361-
event.setAction(MotionEvent.ACTION_UP);
6362-
onTouchEvent(event);
6363-
// Clean up.
6364-
event.recycle();
6355+
if (isClickable()) {
6356+
performClick();
6357+
}
6358+
} break;
6359+
case AccessibilityNodeInfo.ACTION_LONG_CLICK: {
6360+
if (isLongClickable()) {
6361+
performLongClick();
6362+
}
63656363
} break;
63666364
case AccessibilityNodeInfo.ACTION_FOCUS: {
63676365
if (!hasFocus()) {

core/java/android/view/ViewGroup.java

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5723,11 +5723,13 @@ public void recycle() {
57235723
throw new IllegalStateException("Instance already recycled.");
57245724
}
57255725
clear();
5726-
if (sPoolSize < MAX_POOL_SIZE) {
5727-
mNext = sPool;
5728-
mIsPooled = true;
5729-
sPool = this;
5730-
sPoolSize++;
5726+
synchronized (sPoolLock) {
5727+
if (sPoolSize < MAX_POOL_SIZE) {
5728+
mNext = sPool;
5729+
mIsPooled = true;
5730+
sPool = this;
5731+
sPoolSize++;
5732+
}
57315733
}
57325734
}
57335735

@@ -5820,11 +5822,13 @@ public void recycle() {
58205822
throw new IllegalStateException("Instance already recycled.");
58215823
}
58225824
clear();
5823-
if (sPoolSize < MAX_POOL_SIZE) {
5824-
mNext = sPool;
5825-
mIsPooled = true;
5826-
sPool = this;
5827-
sPoolSize++;
5825+
synchronized (sPoolLock) {
5826+
if (sPoolSize < MAX_POOL_SIZE) {
5827+
mNext = sPool;
5828+
mIsPooled = true;
5829+
sPool = this;
5830+
sPoolSize++;
5831+
}
58285832
}
58295833
}
58305834

@@ -5874,9 +5878,9 @@ public int compareTo(ViewLocationHolder another) {
58745878
if (widthDiference != 0) {
58755879
return -widthDiference;
58765880
}
5877-
// Return nondeterministically one of them since we do
5878-
// not want to ignore any views.
5879-
return 1;
5881+
// Just break the tie somehow. The accessibliity ids are unique
5882+
// and stable, hence this is deterministic tie breaking.
5883+
return mView.getAccessibilityViewId() - another.mView.getAccessibilityViewId();
58805884
}
58815885

58825886
private void init(ViewGroup root, View view) {

core/java/android/view/ViewRootImpl.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2665,6 +2665,7 @@ private static void forceLayout(View view) {
26652665
private final static int MSG_PROCESS_INPUT_EVENTS = 19;
26662666
private final static int MSG_DISPATCH_SCREEN_STATE = 20;
26672667
private final static int MSG_INVALIDATE_DISPLAY_LIST = 21;
2668+
private final static int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 22;
26682669

26692670
final class ViewRootHandler extends Handler {
26702671
@Override
@@ -2712,6 +2713,8 @@ public String getMessageName(Message message) {
27122713
return "MSG_DISPATCH_SCREEN_STATE";
27132714
case MSG_INVALIDATE_DISPLAY_LIST:
27142715
return "MSG_INVALIDATE_DISPLAY_LIST";
2716+
case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST:
2717+
return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST";
27152718
}
27162719
return super.getMessageName(message);
27172720
}
@@ -2921,6 +2924,9 @@ public void handleMessage(Message msg) {
29212924
case MSG_INVALIDATE_DISPLAY_LIST: {
29222925
invalidateDisplayLists();
29232926
} break;
2927+
case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: {
2928+
setAccessibilityFocusedHost(null);
2929+
} break;
29242930
}
29252931
}
29262932
}
@@ -5063,7 +5069,7 @@ public void onAccessibilityStateChanged(boolean enabled) {
50635069
}
50645070
} else {
50655071
ensureNoConnection();
5066-
setAccessibilityFocusedHost(null);
5072+
mHandler.obtainMessage(MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST).sendToTarget();
50675073
}
50685074
}
50695075

0 commit comments

Comments
 (0)