diff options
| author | Svetoslav Ganov <svetoslavganov@google.com> | 2012-04-16 18:17:17 -0700 |
|---|---|---|
| committer | Svetoslav Ganov <svetoslavganov@google.com> | 2012-04-18 13:43:55 -0700 |
| commit | 005b83b0c62d3d0538f0d566b08bd457015ec661 (patch) | |
| tree | d83728a70e5a25f14289fafd0654b2e35c2c07e6 /core/java | |
| parent | b3830f6737bb17185e2e1c95f4dcde9ce82ac7e4 (diff) | |
| download | frameworks_base-005b83b0c62d3d0538f0d566b08bd457015ec661.zip frameworks_base-005b83b0c62d3d0538f0d566b08bd457015ec661.tar.gz frameworks_base-005b83b0c62d3d0538f0d566b08bd457015ec661.tar.bz2 | |
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
Diffstat (limited to 'core/java')
7 files changed, 168 insertions, 39 deletions
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index 3da35d3..eed8aa6 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -259,13 +259,51 @@ public abstract class AccessibilityService extends Service { public static final int GESTURE_COUNTER_CLOCKWISE_CIRCLE = 10; /** + * The user has performed a left and up gesture on the touch screen. + */ + public static final int GESTURE_SWIPE_LEFT_AND_UP = 11; + + /** + * The user has performed a left and down gesture on the touch screen. + */ + public static final int GESTURE_SWIPE_LEFT_AND_DOWN = 12; + + /** + * The user has performed a right and up gesture on the touch screen. + */ + public static final int GESTURE_SWIPE_RIGHT_AND_UP = 13; + + /** + * The user has performed a right and down gesture on the touch screen. + */ + public static final int GESTURE_SWIPE_RIGHT_AND_DOWN = 14; + + /** + * The user has performed an up and left gesture on the touch screen. + */ + public static final int GESTURE_SWIPE_UP_AND_LEFT = 15; + + /** + * The user has performed an up and right gesture on the touch screen. + */ + public static final int GESTURE_SWIPE_UP_AND_RIGHT = 16; + + /** + * The user has performed an down and left gesture on the touch screen. + */ + public static final int GESTURE_SWIPE_DOWN_AND_LEFT = 17; + + /** + * The user has performed an down and right gesture on the touch screen. + */ + public static final int GESTURE_SWIPE_DOWN_AND_RIGHT = 18; + + /** * The {@link Intent} that must be declared as handled by the service. */ public static final String SERVICE_INTERFACE = "android.accessibilityservice.AccessibilityService"; - private static final int UNDEFINED = -1; - /** * Name under which an AccessibilityService component publishes information * about itself. This meta-data must reference an XML resource containing an @@ -284,6 +322,28 @@ public abstract class AccessibilityService extends Service { */ public static final String SERVICE_META_DATA = "android.accessibilityservice"; + /** + * Action to go back. + */ + public static final int GLOBAL_ACTION_BACK = 1; + + /** + * Action to go home. + */ + public static final int GLOBAL_ACTION_HOME = 2; + + /** + * Action to open the recents. + */ + public static final int GLOBAL_ACTION_RECENTS = 3; + + /** + * Action to open the notifications. + */ + public static final int GLOBAL_ACTION_NOTIFICATIONS = 4; + + private static final int UNDEFINED = -1; + private static final String LOG_TAG = "AccessibilityService"; interface Callbacks { @@ -344,6 +404,22 @@ public abstract class AccessibilityService extends Service { protected void onGesture(int gestureId) { // TODO: Describe the default gesture processing in the javaDoc once it is finalized. + // Global actions. + switch (gestureId) { + case GESTURE_SWIPE_DOWN_AND_LEFT: { + performGlobalAction(GLOBAL_ACTION_BACK); + } return; + case GESTURE_SWIPE_DOWN_AND_RIGHT: { + performGlobalAction(GLOBAL_ACTION_HOME); + } return; + case GESTURE_SWIPE_UP_AND_LEFT: { + performGlobalAction(GLOBAL_ACTION_RECENTS); + } return; + case GESTURE_SWIPE_UP_AND_RIGHT: { + performGlobalAction(GLOBAL_ACTION_NOTIFICATIONS); + } return; + } + // Cache the id to avoid locking final int connectionId = mConnectionId; if (connectionId == UNDEFINED) { @@ -357,10 +433,12 @@ public abstract class AccessibilityService extends Service { if (root == null) { return; } - AccessibilityNodeInfo current = root.findFocus(View.FOCUS_ACCESSIBILITY); + AccessibilityNodeInfo current = root.findFocus(AccessibilityNodeInfo.FOCUS_ACCESSIBILITY); if (current == null) { current = root; } + + // Local actions. AccessibilityNodeInfo next = null; switch (gestureId) { case GESTURE_SWIPE_UP: { @@ -402,6 +480,33 @@ public abstract class AccessibilityService extends Service { } /** + * Performs a global action. Such an action can be performed + * at any moment regardless of the current application or user + * location in that application. For example going back, going + * home, opening recents, etc. + * + * @param action The action to perform. + * @return Whether the action was successfully performed. + * + * @see #GLOBAL_ACTION_BACK + * @see #GLOBAL_ACTION_HOME + * @see #GLOBAL_ACTION_NOTIFICATIONS + * @see #GLOBAL_ACTION_RECENTS + */ + public final boolean performGlobalAction(int action) { + IAccessibilityServiceConnection connection = + AccessibilityInteractionClient.getInstance().getConnection(mConnectionId); + if (connection != null) { + try { + return connection.perfromGlobalAction(action); + } catch (RemoteException re) { + Log.w(LOG_TAG, "Error while calling performGlobalAction", re); + } + } + return false; + } + + /** * Gets the an {@link AccessibilityServiceInfo} describing this * {@link AccessibilityService}. This method is useful if one wants * to change some of the dynamically configurable properties at diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl index 30da9db..1bd5387 100644 --- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl +++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl @@ -160,4 +160,12 @@ interface IAccessibilityServiceConnection { * @return The associated accessibility service info. */ AccessibilityServiceInfo getServiceInfo(); + + /** + * Performs a global action, such as going home, going back, etc. + * + * @param action The action to perform. + * @return Whether the action was performed. + */ + boolean perfromGlobalAction(int action); } diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java index 6c1a6bf..54c62ee 100644 --- a/core/java/android/view/AccessibilityInteractionController.java +++ b/core/java/android/view/AccessibilityInteractionController.java @@ -52,13 +52,16 @@ final class AccessibilityInteractionController { private ArrayList<AccessibilityNodeInfo> mTempAccessibilityNodeInfoList = new ArrayList<AccessibilityNodeInfo>(); - private final Handler mHandler = new PrivateHandler(); + private final Handler mHandler; private final ViewRootImpl mViewRootImpl; private final AccessibilityNodePrefetcher mPrefetcher; public AccessibilityInteractionController(ViewRootImpl viewRootImpl) { + // mView is never null - the caller has already checked. + Looper looper = viewRootImpl.mView.mContext.getMainLooper(); + mHandler = new PrivateHandler(looper); mViewRootImpl = viewRootImpl; mPrefetcher = new AccessibilityNodePrefetcher(); } @@ -846,8 +849,8 @@ final class AccessibilityInteractionController { private final static int MSG_FIND_FOCUS = 5; private final static int MSG_FOCUS_SEARCH = 6; - public PrivateHandler() { - super(Looper.getMainLooper()); + public PrivateHandler(Looper looper) { + super(looper); } @Override diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 6c1f02d..500b966 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -6352,16 +6352,14 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal public boolean performAccessibilityAction(int action) { switch (action) { case AccessibilityNodeInfo.ACTION_CLICK: { - final long now = SystemClock.uptimeMillis(); - // Send down. - MotionEvent event = MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, - getWidth() / 2, getHeight() / 2, 0); - onTouchEvent(event); - // Send up. - event.setAction(MotionEvent.ACTION_UP); - onTouchEvent(event); - // Clean up. - event.recycle(); + if (isClickable()) { + performClick(); + } + } break; + case AccessibilityNodeInfo.ACTION_LONG_CLICK: { + if (isLongClickable()) { + performLongClick(); + } } break; case AccessibilityNodeInfo.ACTION_FOCUS: { if (!hasFocus()) { diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 7e90e2b..30ea766 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -5723,11 +5723,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager throw new IllegalStateException("Instance already recycled."); } clear(); - if (sPoolSize < MAX_POOL_SIZE) { - mNext = sPool; - mIsPooled = true; - sPool = this; - sPoolSize++; + synchronized (sPoolLock) { + if (sPoolSize < MAX_POOL_SIZE) { + mNext = sPool; + mIsPooled = true; + sPool = this; + sPoolSize++; + } } } @@ -5820,11 +5822,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager throw new IllegalStateException("Instance already recycled."); } clear(); - if (sPoolSize < MAX_POOL_SIZE) { - mNext = sPool; - mIsPooled = true; - sPool = this; - sPoolSize++; + synchronized (sPoolLock) { + if (sPoolSize < MAX_POOL_SIZE) { + mNext = sPool; + mIsPooled = true; + sPool = this; + sPoolSize++; + } } } @@ -5874,9 +5878,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager if (widthDiference != 0) { return -widthDiference; } - // Return nondeterministically one of them since we do - // not want to ignore any views. - return 1; + // Just break the tie somehow. The accessibliity ids are unique + // and stable, hence this is deterministic tie breaking. + return mView.getAccessibilityViewId() - another.mView.getAccessibilityViewId(); } private void init(ViewGroup root, View view) { diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index b4554d5..a1e33ac 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -2665,6 +2665,7 @@ public final class ViewRootImpl implements ViewParent, private final static int MSG_PROCESS_INPUT_EVENTS = 19; private final static int MSG_DISPATCH_SCREEN_STATE = 20; private final static int MSG_INVALIDATE_DISPLAY_LIST = 21; + private final static int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 22; final class ViewRootHandler extends Handler { @Override @@ -2712,6 +2713,8 @@ public final class ViewRootImpl implements ViewParent, return "MSG_DISPATCH_SCREEN_STATE"; case MSG_INVALIDATE_DISPLAY_LIST: return "MSG_INVALIDATE_DISPLAY_LIST"; + case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: + return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST"; } return super.getMessageName(message); } @@ -2921,6 +2924,9 @@ public final class ViewRootImpl implements ViewParent, case MSG_INVALIDATE_DISPLAY_LIST: { invalidateDisplayLists(); } break; + case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: { + setAccessibilityFocusedHost(null); + } break; } } } @@ -5063,7 +5069,7 @@ public final class ViewRootImpl implements ViewParent, } } else { ensureNoConnection(); - setAccessibilityFocusedHost(null); + mHandler.obtainMessage(MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST).sendToTarget(); } } diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index 1071c65..c5f2062 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -84,7 +84,7 @@ public class AccessibilityNodeInfo implements Parcelable { /** * Action that gives input focus to the node. */ - public static final int ACTION_FOCUS = 0x00000001; + public static final int ACTION_FOCUS = 0x00000001; /** * Action that clears input focus of the node. @@ -102,19 +102,24 @@ public class AccessibilityNodeInfo implements Parcelable { public static final int ACTION_CLEAR_SELECTION = 0x00000008; /** - * Action that gives accessibility focus to the node. + * Action that clicks on the node info. */ - public static final int ACTION_ACCESSIBILITY_FOCUS = 0x00000010; + public static final int ACTION_CLICK = 0x00000010; /** - * Action that clears accessibility focus of the node. + * Action that clicks on the node. + */ + public static final int ACTION_LONG_CLICK = 0x00000020; + + /** + * Action that gives accessibility focus to the node. */ - public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 0x00000020; + public static final int ACTION_ACCESSIBILITY_FOCUS = 0x00000040; /** - * Action that clicks on the node info./AccessibilityNodeInfoCache.java + * Action that clears accessibility focus of the node. */ - public static final int ACTION_CLICK = 0x00000040; + public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 0x00000080; /** * The input focus. @@ -278,9 +283,9 @@ public class AccessibilityNodeInfo implements Parcelable { (root != null) ? root.getAccessibilityViewId() : UNDEFINED; mSourceNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId); } - + /** - * Find the view that has the input focus. The search starts from + * Find the view that has the specified focus type. The search starts from * the view represented by this node info. * * @param focus The focus to find. One of {@link #FOCUS_INPUT} or |
