summaryrefslogtreecommitdiffstats
path: root/services/accessibility
diff options
context:
space:
mode:
authorSvetoslav <svetoslavganov@google.com>2015-01-30 20:28:41 -0800
committerSvetoslav Ganov <svetoslavganov@google.com>2015-02-02 23:17:17 +0000
commitded133c446fa9d0d23e6bde19a66fb2ce3980491 (patch)
tree41f26af8f4fce5f667a3c167ff6ddfae503b9663 /services/accessibility
parent175ddbcf2ed71fdcd44a9b64cdc5d479df496a4d (diff)
downloadframeworks_base-ded133c446fa9d0d23e6bde19a66fb2ce3980491.zip
frameworks_base-ded133c446fa9d0d23e6bde19a66fb2ce3980491.tar.gz
frameworks_base-ded133c446fa9d0d23e6bde19a66fb2ce3980491.tar.bz2
Fix broken activation of the selected view in accessibility mode.
We were using an approximation to determine where to send a pair of down and up events to click on the view that has accessibility focus. We were doing reverse computation to figuring out which portion of the view is not covered by interactive views and get a point in this region. However, determining whether a view is interactive is not feasible in general since for example may override onTouchEvent. This results in views not being activated or which is worse wrong views being activated. This change swithes to a new approach to activate views in accessibility mode which is guaranteed to always work except the very rare case of a view that overrides dispatchTouchEvent (which developers shouldn't be doing). The new approach is to flag the down and up events pair sent by the touch explorer as targeting the accessibility focused view. Such events are dispatched such that views predecessors of the accessibility focus do not handle them guaranteeing that these events reach the accessibiliy focused view. Once the accessibiliy focused view gets such an event it clears the flag and the event is dispatched following the normal event dispatch semantics. The new approach is semantically equivalent to requesting the view to perform a click accessiblitiy action but is more generic as it is not affected by views not implementing click action support correctly. bug:18986806 bug:18889611 Change-Id: Id4b7b886c9fd34f7eb11e606636d8e3bab122869
Diffstat (limited to 'services/accessibility')
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java87
-rw-r--r--services/accessibility/java/com/android/server/accessibility/TouchExplorer.java36
2 files changed, 42 insertions, 81 deletions
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index bbf3644..93c65f3 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -170,6 +170,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
private final Rect mTempRect = new Rect();
+ private final Rect mTempRect1 = new Rect();
+
private final Point mTempPoint = new Point();
private final PackageManager mPackageManager;
@@ -2533,57 +2535,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
@Override
- public boolean computeClickPointInScreen(int accessibilityWindowId,
- long accessibilityNodeId, int interactionId,
- IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
- throws RemoteException {
- final int resolvedWindowId;
- IAccessibilityInteractionConnection connection = null;
- Region partialInteractiveRegion = mTempRegion;
- synchronized (mLock) {
- // We treat calls from a profile as if made by its parent as profiles
- // share the accessibility state of the parent. The call below
- // performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
- .resolveCallingUserIdEnforcingPermissionsLocked(
- UserHandle.USER_CURRENT);
- if (resolvedUserId != mCurrentUserId) {
- return false;
- }
- resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
- final boolean permissionGranted =
- mSecurityPolicy.canRetrieveWindowContentLocked(this);
- if (!permissionGranted) {
- return false;
- } else {
- connection = getConnectionLocked(resolvedWindowId);
- if (connection == null) {
- return false;
- }
- }
- if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked(
- resolvedWindowId, partialInteractiveRegion)) {
- partialInteractiveRegion = null;
- }
- }
- final int interrogatingPid = Binder.getCallingPid();
- final long identityToken = Binder.clearCallingIdentity();
- MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId);
- try {
- connection.computeClickPointInScreen(accessibilityNodeId, partialInteractiveRegion,
- interactionId, callback, interrogatingPid, interrogatingTid, spec);
- return true;
- } catch (RemoteException re) {
- if (DEBUG) {
- Slog.e(LOG_TAG, "Error computeClickPointInScreen().");
- }
- } finally {
- Binder.restoreCallingIdentity(identityToken);
- }
- return false;
- }
-
- @Override
public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
mSecurityPolicy.enforceCallingPermission(Manifest.permission.DUMP, FUNCTION_DUMP);
synchronized (mLock) {
@@ -3236,38 +3187,36 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
synchronized (mLock) {
- Point point = mClient.computeClickPointInScreen(mConnectionId,
- focus.getWindowId(), focus.getSourceNodeId());
+ Rect boundsInScreen = mTempRect;
+ focus.getBoundsInScreen(boundsInScreen);
- if (point == null) {
+ // Clip to the window bounds.
+ Rect windowBounds = mTempRect1;
+ getWindowBounds(focus.getWindowId(), windowBounds);
+ boundsInScreen.intersect(windowBounds);
+ if (boundsInScreen.isEmpty()) {
return false;
}
+ // Apply magnification if needed.
MagnificationSpec spec = getCompatibleMagnificationSpecLocked(focus.getWindowId());
if (spec != null && !spec.isNop()) {
- point.offset((int) -spec.offsetX, (int) -spec.offsetY);
- point.x = (int) (point.x * (1 / spec.scale));
- point.y = (int) (point.y * (1 / spec.scale));
+ boundsInScreen.offset((int) -spec.offsetX, (int) -spec.offsetY);
+ boundsInScreen.scale(1 / spec.scale);
}
- // Make sure the point is within the window.
- Rect windowBounds = mTempRect;
- getWindowBounds(focus.getWindowId(), windowBounds);
- if (!windowBounds.contains(point.x, point.y)) {
- return false;
- }
-
- // Make sure the point is within the screen.
+ // Clip to the screen bounds.
Point screenSize = mTempPoint;
mDefaultDisplay.getRealSize(screenSize);
- if (point.x < 0 || point.x > screenSize.x
- || point.y < 0 || point.y > screenSize.y) {
+ boundsInScreen.intersect(0, 0, screenSize.x, screenSize.y);
+ if (boundsInScreen.isEmpty()) {
return false;
}
- outPoint.set(point.x, point.y);
- return true;
+ outPoint.set(boundsInScreen.centerX(), boundsInScreen.centerY());
}
+
+ return true;
}
private AccessibilityNodeInfo getAccessibilityFocusNotLocked() {
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index b9ed89b..f18b5ef 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -77,6 +77,10 @@ class TouchExplorer implements EventStreamTransformation {
private static final int STATE_DELEGATING = 0x00000004;
private static final int STATE_GESTURE_DETECTING = 0x00000005;
+ private static final int CLICK_LOCATION_NONE = 0;
+ private static final int CLICK_LOCATION_ACCESSIBILITY_FOCUS = 1;
+ private static final int CLICK_LOCATION_LAST_TOUCH_EXPLORED = 2;
+
// The maximum of the cosine between the vectors of two moving
// pointers so they can be considered moving in the same direction.
private static final float MAX_DRAGGING_ANGLE_COS = 0.525321989f; // cos(pi/4)
@@ -942,12 +946,16 @@ class TouchExplorer implements EventStreamTransformation {
*
* @param prototype The prototype from which to create the injected events.
* @param policyFlags The policy flags associated with the event.
+ * @param targetAccessibilityFocus Whether the event targets the accessibility focus.
*/
- private void sendActionDownAndUp(MotionEvent prototype, int policyFlags) {
+ private void sendActionDownAndUp(MotionEvent prototype, int policyFlags,
+ boolean targetAccessibilityFocus) {
// Tap with the pointer that last explored.
final int pointerId = prototype.getPointerId(prototype.getActionIndex());
final int pointerIdBits = (1 << pointerId);
+ prototype.setTargetAccessibilityFocus(targetAccessibilityFocus);
sendMotionEvent(prototype, MotionEvent.ACTION_DOWN, pointerIdBits, policyFlags);
+ prototype.setTargetAccessibilityFocus(targetAccessibilityFocus);
sendMotionEvent(prototype, MotionEvent.ACTION_UP, pointerIdBits, policyFlags);
}
@@ -1155,7 +1163,8 @@ class TouchExplorer implements EventStreamTransformation {
final int pointerIndex = secondTapUp.findPointerIndex(pointerId);
Point clickLocation = mTempPoint;
- if (!computeClickLocation(clickLocation)) {
+ final int result = computeClickLocation(clickLocation);
+ if (result == CLICK_LOCATION_NONE) {
return;
}
@@ -1171,7 +1180,8 @@ class TouchExplorer implements EventStreamTransformation {
secondTapUp.getEventTime(), MotionEvent.ACTION_DOWN, 1, properties,
coords, 0, 0, 1.0f, 1.0f, secondTapUp.getDeviceId(), 0,
secondTapUp.getSource(), secondTapUp.getFlags());
- sendActionDownAndUp(event, policyFlags);
+ final boolean targetAccessibilityFocus = (result == CLICK_LOCATION_ACCESSIBILITY_FOCUS);
+ sendActionDownAndUp(event, policyFlags, targetAccessibilityFocus);
event.recycle();
}
@@ -1216,7 +1226,7 @@ class TouchExplorer implements EventStreamTransformation {
MAX_DRAGGING_ANGLE_COS);
}
- private boolean computeClickLocation(Point outLocation) {
+ private int computeClickLocation(Point outLocation) {
MotionEvent lastExploreEvent = mInjectedPointerTracker.getLastInjectedHoverEventForClick();
if (lastExploreEvent != null) {
final int lastExplorePointerIndex = lastExploreEvent.getActionIndex();
@@ -1224,14 +1234,17 @@ class TouchExplorer implements EventStreamTransformation {
outLocation.y = (int) lastExploreEvent.getY(lastExplorePointerIndex);
if (!mAms.accessibilityFocusOnlyInActiveWindow()
|| mLastTouchedWindowId == mAms.getActiveWindowId()) {
- mAms.getAccessibilityFocusClickPointInScreen(outLocation);
+ if (mAms.getAccessibilityFocusClickPointInScreen(outLocation)) {
+ return CLICK_LOCATION_ACCESSIBILITY_FOCUS;
+ } else {
+ return CLICK_LOCATION_LAST_TOUCH_EXPLORED;
+ }
}
- return true;
}
if (mAms.getAccessibilityFocusClickPointInScreen(outLocation)) {
- return true;
+ return CLICK_LOCATION_ACCESSIBILITY_FOCUS;
}
- return false;
+ return CLICK_LOCATION_NONE;
}
/**
@@ -1310,14 +1323,13 @@ class TouchExplorer implements EventStreamTransformation {
return;
}
- int clickLocationX;
- int clickLocationY;
-
final int pointerId = mEvent.getPointerId(mEvent.getActionIndex());
final int pointerIndex = mEvent.findPointerIndex(pointerId);
Point clickLocation = mTempPoint;
- if (!computeClickLocation(clickLocation)) {
+ final int result = computeClickLocation(clickLocation);
+
+ if (result == CLICK_LOCATION_NONE) {
return;
}