summaryrefslogtreecommitdiffstats
path: root/services/java/com/android
diff options
context:
space:
mode:
authorSvetoslav Ganov <svetoslavganov@google.com>2012-06-06 21:12:20 -0700
committerSvetoslav Ganov <svetoslavganov@google.com>2012-06-07 12:02:16 -0700
commit86783474fdec98a22bc22e224462767eab13e273 (patch)
tree38ca4f46402c35874a2960ea9bc2da16ca4eb2eb /services/java/com/android
parentfefd48965c5f521f21c10aad86586cf68ae48f71 (diff)
downloadframeworks_base-86783474fdec98a22bc22e224462767eab13e273.zip
frameworks_base-86783474fdec98a22bc22e224462767eab13e273.tar.gz
frameworks_base-86783474fdec98a22bc22e224462767eab13e273.tar.bz2
Cannot interact with dialogs when IME is up and on not touch explored popups.
1. If the last touch explored location is within the active window we used to click on exact location if it is within the accessibility focus otherwise in the accessibility focus center. If the last touch explored location is not within the active window we used to just click there. This breaks in the case were one has touch explored at a given place in the current window and now a dialog opens *not* covering the touch explored location. If one uses swipes to move accessibility focus i.e. to traverse the dialog without touching it one cannot activate anything because the touch explorer is using the last touch explored location that is outside of the active window e.g the dialog. The solution is to clear the last touch explored location when a window opens or accessibility focus moves. If the last touch explored location is null we are clicking in the accessibility focus location. bug:6620911 2. There is a bug in the window manager that does not notify a window that its location has changed (bug:6623031). This breaks accessibility interaction with dialogs that have input because when the IME is up the dialog is moved but not notified. Now the accessibility layer gets incorrect location for the accessibility focus and the window bounds. The soluion is when the accessibility manager service calls into the remove thress to obtain some accessibility node infos it passes the window left and top which it gets from the window manager. These values are used to update the attach info window left and top so all accessibility node infos emitted from that window had correct bounds in screen coordinates. bug:6620796 Change-Id: I18914f2095c55cfc826acf5277bd94b776bda0c8
Diffstat (limited to 'services/java/com/android')
-rw-r--r--services/java/com/android/server/accessibility/AccessibilityInputFilter.java5
-rw-r--r--services/java/com/android/server/accessibility/AccessibilityManagerService.java84
-rw-r--r--services/java/com/android/server/accessibility/TouchExplorer.java138
-rwxr-xr-xservices/java/com/android/server/wm/WindowManagerService.java13
4 files changed, 161 insertions, 79 deletions
diff --git a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 3e35b20..baa2f54 100644
--- a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -25,6 +25,7 @@ import android.view.InputDevice;
import android.view.InputEvent;
import android.view.MotionEvent;
import android.view.WindowManagerPolicy;
+import android.view.accessibility.AccessibilityEvent;
/**
* Input filter for accessibility.
@@ -120,4 +121,8 @@ public class AccessibilityInputFilter extends InputFilter {
super.onInputEvent(event, policyFlags);
}
}
+
+ public void onAccessibilityEvent(AccessibilityEvent event) {
+ mTouchExplorer.onAccessibilityEvent(event);
+ }
}
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 5c814d2..3bddd9d 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -141,8 +141,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
private final SimpleStringSplitter mStringColonSplitter = new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR);
- private final Rect mTempRect = new Rect();
-
private PackageManager mPackageManager;
private int mHandledFeedbackTypes = 0;
@@ -403,7 +401,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
notifyAccessibilityServicesDelayedLocked(event, false);
notifyAccessibilityServicesDelayedLocked(event, true);
}
-
+ if (mHasInputFilter && mInputFilter != null) {
+ mInputFilter.onAccessibilityEvent(event);
+ }
event.recycle();
mHandledFeedbackTypes = 0;
}
@@ -543,17 +543,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
/**
- * Gets the bounds of the accessibility focus if the provided,
- * point coordinates are within the currently active window
- * and accessibility focus is found within the latter.
+ * Gets the bounds of the accessibility focus in the active window.
*
- * @param x X coordinate.
- * @param y Y coordinate
* @param outBounds The output to which to write the focus bounds.
- * @return The accessibility focus rectangle if the point is in the
- * window and the window has accessibility focus.
+ * @return Whether accessibility focus was found and the bounds are populated.
*/
- boolean getAccessibilityFocusBounds(int x, int y, Rect outBounds) {
+ boolean getAccessibilityFocusBoundsInActiveWindow(Rect outBounds) {
// Instead of keeping track of accessibility focus events per
// window to be able to find the focus in the active window,
// we take a stateless approach and look it up. This is fine
@@ -568,11 +563,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
if (root == null) {
return false;
}
- Rect bounds = mTempRect;
- root.getBoundsInScreen(bounds);
- if (!bounds.contains(x, y)) {
- return false;
- }
AccessibilityNodeInfo focus = root.findFocus(
AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
if (focus == null) {
@@ -585,6 +575,19 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
}
+ /**
+ * Gets the bounds of the active window.
+ *
+ * @param outBounds The output to which to write the bounds.
+ */
+ void getActiveWindowBounds(Rect outBounds) {
+ synchronized (mLock) {
+ final int windowId = mSecurityPolicy.mActiveWindowId;
+ IBinder token = mWindowIdToWindowTokenMap.get(windowId);
+ mWindowManagerService.getWindowFrame(token, outBounds);
+ }
+ }
+
private Service getQueryBridge() {
if (mQueryBridge == null) {
AccessibilityServiceInfo info = new AccessibilityServiceInfo();
@@ -1316,6 +1319,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
throws RemoteException {
final int resolvedWindowId = resolveAccessibilityWindowId(accessibilityWindowId);
+ final int windowLeft;
+ final int windowTop;
IAccessibilityInteractionConnection connection = null;
synchronized (mLock) {
mSecurityPolicy.enforceCanRetrieveWindowContent(this);
@@ -1328,6 +1333,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
return 0;
}
}
+ IBinder token = mWindowIdToWindowTokenMap.get(resolvedWindowId);
+ mWindowManagerService.getWindowFrame(token, mTempBounds);
+ windowLeft = mTempBounds.left;
+ windowTop = mTempBounds.top;
}
final int flags = (mIncludeNotImportantViews) ?
AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
@@ -1335,7 +1344,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
final long identityToken = Binder.clearCallingIdentity();
try {
connection.findAccessibilityNodeInfoByViewId(accessibilityNodeId, viewId,
- interactionId, callback, flags, interrogatingPid, interrogatingTid);
+ windowLeft, windowTop, interactionId, callback, flags, interrogatingPid,
+ interrogatingTid);
} catch (RemoteException re) {
if (DEBUG) {
Slog.e(LOG_TAG, "Error findAccessibilityNodeInfoByViewId().");
@@ -1352,6 +1362,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
throws RemoteException {
final int resolvedWindowId = resolveAccessibilityWindowId(accessibilityWindowId);
+ final int windowLeft;
+ final int windowTop;
IAccessibilityInteractionConnection connection = null;
synchronized (mLock) {
mSecurityPolicy.enforceCanRetrieveWindowContent(this);
@@ -1365,14 +1377,19 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
return 0;
}
}
+ IBinder token = mWindowIdToWindowTokenMap.get(resolvedWindowId);
+ mWindowManagerService.getWindowFrame(token, mTempBounds);
+ windowLeft = mTempBounds.left;
+ windowTop = mTempBounds.top;
}
final int flags = (mIncludeNotImportantViews) ?
AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
final int interrogatingPid = Binder.getCallingPid();
final long identityToken = Binder.clearCallingIdentity();
try {
- connection.findAccessibilityNodeInfosByText(accessibilityNodeId, text,
- interactionId, callback, flags, interrogatingPid, interrogatingTid);
+ connection.findAccessibilityNodeInfosByText(accessibilityNodeId, text, windowLeft,
+ windowTop, interactionId, callback, flags, interrogatingPid,
+ interrogatingTid);
} catch (RemoteException re) {
if (DEBUG) {
Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfosByText()");
@@ -1389,6 +1406,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
IAccessibilityInteractionConnectionCallback callback, int flags,
long interrogatingTid) throws RemoteException {
final int resolvedWindowId = resolveAccessibilityWindowId(accessibilityWindowId);
+ final int windowLeft;
+ final int windowTop;
IAccessibilityInteractionConnection connection = null;
synchronized (mLock) {
mSecurityPolicy.enforceCanRetrieveWindowContent(this);
@@ -1402,6 +1421,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
return 0;
}
}
+ IBinder token = mWindowIdToWindowTokenMap.get(resolvedWindowId);
+ mWindowManagerService.getWindowFrame(token, mTempBounds);
+ windowLeft = mTempBounds.left;
+ windowTop = mTempBounds.top;
}
final int allFlags = flags | ((mIncludeNotImportantViews) ?
AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0);
@@ -1409,7 +1432,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
final long identityToken = Binder.clearCallingIdentity();
try {
connection.findAccessibilityNodeInfoByAccessibilityId(accessibilityNodeId,
- interactionId, callback, allFlags, interrogatingPid, interrogatingTid);
+ windowLeft, windowTop, interactionId, callback, allFlags, interrogatingPid,
+ interrogatingTid);
} catch (RemoteException re) {
if (DEBUG) {
Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfoByAccessibilityId()");
@@ -1426,6 +1450,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
throws RemoteException {
final int resolvedWindowId = resolveAccessibilityWindowId(accessibilityWindowId);
+ final int windowLeft;
+ final int windowTop;
IAccessibilityInteractionConnection connection = null;
synchronized (mLock) {
mSecurityPolicy.enforceCanRetrieveWindowContent(this);
@@ -1439,14 +1465,18 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
return 0;
}
}
+ IBinder token = mWindowIdToWindowTokenMap.get(resolvedWindowId);
+ mWindowManagerService.getWindowFrame(token, mTempBounds);
+ windowLeft = mTempBounds.left;
+ windowTop = mTempBounds.top;
}
final int flags = (mIncludeNotImportantViews) ?
AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
final int interrogatingPid = Binder.getCallingPid();
final long identityToken = Binder.clearCallingIdentity();
try {
- connection.findFocus(accessibilityNodeId, interactionId, focusType, callback,
- flags, interrogatingPid, interrogatingTid);
+ connection.findFocus(accessibilityNodeId, focusType, windowLeft, windowTop,
+ interactionId, callback, flags, interrogatingPid, interrogatingTid);
} catch (RemoteException re) {
if (DEBUG) {
Slog.e(LOG_TAG, "Error calling findAccessibilityFocus()");
@@ -1463,6 +1493,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
throws RemoteException {
final int resolvedWindowId = resolveAccessibilityWindowId(accessibilityWindowId);
+ final int windowLeft;
+ final int windowTop;
IAccessibilityInteractionConnection connection = null;
synchronized (mLock) {
mSecurityPolicy.enforceCanRetrieveWindowContent(this);
@@ -1476,14 +1508,18 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
return 0;
}
}
+ IBinder token = mWindowIdToWindowTokenMap.get(resolvedWindowId);
+ mWindowManagerService.getWindowFrame(token, mTempBounds);
+ windowLeft = mTempBounds.left;
+ windowTop = mTempBounds.top;
}
final int flags = (mIncludeNotImportantViews) ?
AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
final int interrogatingPid = Binder.getCallingPid();
final long identityToken = Binder.clearCallingIdentity();
try {
- connection.focusSearch(accessibilityNodeId, interactionId, direction, callback,
- flags, interrogatingPid, interrogatingTid);
+ connection.focusSearch(accessibilityNodeId, direction, windowLeft, windowTop,
+ interactionId, callback, flags, interrogatingPid, interrogatingTid);
} catch (RemoteException re) {
if (DEBUG) {
Slog.e(LOG_TAG, "Error calling accessibilityFocusSearch()");
diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java
index 7e88373..14784dc 100644
--- a/services/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/java/com/android/server/accessibility/TouchExplorer.java
@@ -33,6 +33,7 @@ import android.view.MotionEvent.PointerProperties;
import android.view.VelocityTracker;
import android.view.ViewConfiguration;
import android.view.WindowManagerPolicy;
+import android.view.accessibility.AccessibilityEvent;
import com.android.internal.R;
import com.android.server.input.InputFilter;
@@ -293,6 +294,21 @@ public class TouchExplorer {
}
}
+ public void onAccessibilityEvent(AccessibilityEvent event) {
+ // If a new window opens or the accessibility focus moves we no longer
+ // want to click/long press on the last touch explored location.
+ final int eventType = event.getEventType();
+ switch (eventType) {
+ case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
+ case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
+ if (mInjectedPointerTracker.mLastInjectedHoverEvent != null) {
+ mInjectedPointerTracker.mLastInjectedHoverEvent.recycle();
+ mInjectedPointerTracker.mLastInjectedHoverEvent = null;
+ }
+ } break;
+ }
+ }
+
/**
* Handles a motion event in touch exploring state.
*
@@ -1037,30 +1053,40 @@ public class TouchExplorer {
// is actually clicked.
sendExitEventsIfNeeded(policyFlags);
- // If the last touched explored location is not within the focused
- // window we will click at that exact spot, otherwise we find the
- // accessibility focus and if the tap is within its bounds we click
- // there, otherwise we pick the middle of the focus rectangle.
- MotionEvent lastEvent = mInjectedPointerTracker.getLastInjectedHoverEvent();
- if (lastEvent == null) {
- return;
- }
-
- final int exploreLocationX = (int) lastEvent.getX(lastEvent.getActionIndex());
- final int exploreLocationY = (int) lastEvent.getY(lastEvent.getActionIndex());
-
- Rect bounds = mTempRect;
- boolean useLastHoverLocation = false;
+ int clickLocationX;
+ int clickLocationY;
final int pointerId = secondTapUp.getPointerId(secondTapUp.getActionIndex());
final int pointerIndex = secondTapUp.findPointerIndex(pointerId);
- if (mAms.getAccessibilityFocusBounds(exploreLocationX, exploreLocationY, bounds)) {
- // If the user's last touch explored location is not
- // within the accessibility focus bounds we use the center
- // of the accessibility focused rectangle.
- if (!bounds.contains((int) secondTapUp.getX(pointerIndex),
- (int) secondTapUp.getY(pointerIndex))) {
- useLastHoverLocation = true;
+
+ MotionEvent lastExploreEvent = mInjectedPointerTracker.getLastInjectedHoverEvent();
+ if (lastExploreEvent == null) {
+ // No last touch explored event but there is accessibility focus in
+ // the active window. We click in the middle of the focus bounds.
+ Rect focusBounds = mTempRect;
+ if (mAms.getAccessibilityFocusBoundsInActiveWindow(focusBounds)) {
+ clickLocationX = focusBounds.centerX();
+ clickLocationY = focusBounds.centerY();
+ } else {
+ // Out of luck - do nothing.
+ return;
+ }
+ } else {
+ // If the click is within the active window but not within the
+ // accessibility focus bounds we click in the focus center.
+ final int lastExplorePointerIndex = lastExploreEvent.getActionIndex();
+ clickLocationX = (int) lastExploreEvent.getX(lastExplorePointerIndex);
+ clickLocationY = (int) lastExploreEvent.getY(lastExplorePointerIndex);
+ Rect activeWindowBounds = mTempRect;
+ mAms.getActiveWindowBounds(activeWindowBounds);
+ if (activeWindowBounds.contains(clickLocationX, clickLocationY)) {
+ Rect focusBounds = mTempRect;
+ if (mAms.getAccessibilityFocusBoundsInActiveWindow(focusBounds)) {
+ if (!focusBounds.contains(clickLocationX, clickLocationY)) {
+ clickLocationX = focusBounds.centerX();
+ clickLocationY = focusBounds.centerY();
+ }
+ }
}
}
@@ -1070,8 +1096,8 @@ public class TouchExplorer {
secondTapUp.getPointerProperties(pointerIndex, properties[0]);
PointerCoords[] coords = new PointerCoords[1];
coords[0] = new PointerCoords();
- coords[0].x = (useLastHoverLocation) ? bounds.centerX() : exploreLocationX;
- coords[0].y = (useLastHoverLocation) ? bounds.centerY() : exploreLocationY;
+ coords[0].x = clickLocationX;
+ coords[0].y = clickLocationY;
MotionEvent event = MotionEvent.obtain(secondTapUp.getDownTime(),
secondTapUp.getEventTime(), MotionEvent.ACTION_DOWN, 1, properties,
coords, 0, 0, 1.0f, 1.0f, secondTapUp.getDeviceId(), 0,
@@ -1257,45 +1283,47 @@ public class TouchExplorer {
return;
}
- // If the last touched explored location is not within the focused
- // window we will long press at that exact spot, otherwise we find the
- // accessibility focus and if the tap is within its bounds we long press
- // there, otherwise we pick the middle of the focus rectangle.
- MotionEvent lastEvent = mInjectedPointerTracker.getLastInjectedHoverEvent();
- if (lastEvent == null) {
- return;
- }
-
- final int exploreLocationX = (int) lastEvent.getX(lastEvent.getActionIndex());
- final int exploreLocationY = (int) lastEvent.getY(lastEvent.getActionIndex());
-
- Rect bounds = mTempRect;
- boolean useFocusedBounds = false;
+ int clickLocationX;
+ int clickLocationY;
final int pointerId = mEvent.getPointerId(mEvent.getActionIndex());
final int pointerIndex = mEvent.findPointerIndex(pointerId);
- if (mAms.getAccessibilityFocusBounds(exploreLocationX, exploreLocationY, bounds)) {
- // If the user's last touch explored location is not
- // within the accessibility focus bounds we use the center
- // of the accessibility focused rectangle.
- if (!bounds.contains((int) mEvent.getX(pointerIndex),
- (int) mEvent.getY(pointerIndex))) {
- useFocusedBounds = true;
- }
- }
- mLongPressingPointerId = mEvent.getPointerId(pointerIndex);
-
- final int eventX = (int) mEvent.getX(pointerIndex);
- final int eventY = (int) mEvent.getY(pointerIndex);
- if (useFocusedBounds) {
- mLongPressingPointerDeltaX = eventX - bounds.centerX();
- mLongPressingPointerDeltaY = eventY - bounds.centerY();
+ MotionEvent lastExploreEvent = mInjectedPointerTracker.getLastInjectedHoverEvent();
+ if (lastExploreEvent == null) {
+ // No last touch explored event but there is accessibility focus in
+ // the active window. We click in the middle of the focus bounds.
+ Rect focusBounds = mTempRect;
+ if (mAms.getAccessibilityFocusBoundsInActiveWindow(focusBounds)) {
+ clickLocationX = focusBounds.centerX();
+ clickLocationY = focusBounds.centerY();
+ } else {
+ // Out of luck - do nothing.
+ return;
+ }
} else {
- mLongPressingPointerDeltaX = eventX - exploreLocationX;
- mLongPressingPointerDeltaY = eventY - exploreLocationY;
+ // If the click is within the active window but not within the
+ // accessibility focus bounds we click in the focus center.
+ final int lastExplorePointerIndex = lastExploreEvent.getActionIndex();
+ clickLocationX = (int) lastExploreEvent.getX(lastExplorePointerIndex);
+ clickLocationY = (int) lastExploreEvent.getY(lastExplorePointerIndex);
+ Rect activeWindowBounds = mTempRect;
+ mAms.getActiveWindowBounds(activeWindowBounds);
+ if (activeWindowBounds.contains(clickLocationX, clickLocationY)) {
+ Rect focusBounds = mTempRect;
+ if (mAms.getAccessibilityFocusBoundsInActiveWindow(focusBounds)) {
+ if (!focusBounds.contains(clickLocationX, clickLocationY)) {
+ clickLocationX = focusBounds.centerX();
+ clickLocationY = focusBounds.centerY();
+ }
+ }
+ }
}
+ mLongPressingPointerId = pointerId;
+ mLongPressingPointerDeltaX = (int) mEvent.getX(pointerIndex) - clickLocationX;
+ mLongPressingPointerDeltaY = (int) mEvent.getY(pointerIndex) - clickLocationY;
+
sendExitEventsIfNeeded(mPolicyFlags);
mCurrentState = STATE_DELEGATING;
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 5f63934..9e08584 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -6675,6 +6675,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ // TODO: Put this on the IWindowManagerService and guard with a permission.
public IBinder getFocusedWindowClientToken() {
synchronized (mWindowMap) {
WindowState windowState = getFocusedWindowLocked();
@@ -6685,6 +6686,18 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ // TODO: This is a workaround - remove when 6623031 is fixed.
+ public boolean getWindowFrame(IBinder token, Rect outBounds) {
+ synchronized (mWindowMap) {
+ WindowState windowState = mWindowMap.get(token);
+ if (windowState != null) {
+ outBounds.set(windowState.getFrameLw());
+ return true;
+ }
+ }
+ return false;
+ }
+
private WindowState getFocusedWindow() {
synchronized (mWindowMap) {
return getFocusedWindowLocked();