am 0f7ed1f4: Merge "Adding system support for a single accessibility focus."

* commit '0f7ed1f4776844f3ee8d3ce9d903f62cace66a06':
  Adding system support for a single accessibility focus.
This commit is contained in:
Svetoslav
2014-04-11 18:26:42 +00:00
committed by Android Git Automerger
8 changed files with 276 additions and 91 deletions

View File

@@ -2456,6 +2456,7 @@ package android.accessibilityservice {
public abstract class AccessibilityService extends android.app.Service {
ctor public AccessibilityService();
method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows();
@@ -4755,6 +4756,7 @@ package android.app {
method public void clearWindowAnimationFrameStats();
method public boolean clearWindowContentFrameStats(int);
method public android.view.accessibility.AccessibilityEvent executeAndWaitForEvent(java.lang.Runnable, android.app.UiAutomation.AccessibilityEventFilter, long) throws java.util.concurrent.TimeoutException;
method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
method public android.view.WindowAnimationFrameStats getWindowAnimationFrameStats();

View File

@@ -525,6 +525,31 @@ public abstract class AccessibilityService extends Service {
return false;
}
/**
* Find the view that has the specified focus type. The search is performed
* across all windows.
* <p>
* <strong>Note:</strong> In order to access the windows your service has
* to declare the capability to retrieve window content by setting the
* {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent}
* property in its meta-data. For details refer to {@link #SERVICE_META_DATA}.
* Also the service has to opt-in to retrieve the interactive windows by
* setting the {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS}
* flag.Otherwise, the search will be performed only in the active window.
* </p>
*
* @param focus The focus to find. One of {@link AccessibilityNodeInfo#FOCUS_INPUT} or
* {@link AccessibilityNodeInfo#FOCUS_ACCESSIBILITY}.
* @return The node info of the focused view or null.
*
* @see AccessibilityNodeInfo#FOCUS_INPUT
* @see AccessibilityNodeInfo#FOCUS_ACCESSIBILITY
*/
public AccessibilityNodeInfo findFocus(int focus) {
return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId,
AccessibilityNodeInfo.ANY_WINDOW_ID, AccessibilityNodeInfo.ROOT_NODE_ID, focus);
}
/**
* Gets the an {@link AccessibilityServiceInfo} describing this
* {@link AccessibilityService}. This method is useful if one wants

View File

@@ -296,6 +296,28 @@ public final class UiAutomation {
return false;
}
/**
* Find the view that has the specified focus type. The search is performed
* across all windows.
* <p>
* <strong>Note:</strong> In order to access the windows you have to opt-in
* to retrieve the interactive windows by setting the
* {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS} flag.
* Otherwise, the search will be performed only in the active window.
* </p>
*
* @param focus The focus to find. One of {@link AccessibilityNodeInfo#FOCUS_INPUT} or
* {@link AccessibilityNodeInfo#FOCUS_ACCESSIBILITY}.
* @return The node info of the focused view or null.
*
* @see AccessibilityNodeInfo#FOCUS_INPUT
* @see AccessibilityNodeInfo#FOCUS_ACCESSIBILITY
*/
public AccessibilityNodeInfo findFocus(int focus) {
return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId,
AccessibilityNodeInfo.ANY_WINDOW_ID, AccessibilityNodeInfo.ROOT_NODE_ID, focus);
}
/**
* Gets the an {@link AccessibilityServiceInfo} describing this UiAutomation.
* This method is useful if one wants to change some of the dynamically

View File

@@ -8790,11 +8790,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
&& !pointInView(event.getX(), event.getY()))) {
mSendingHoverAccessibilityEvents = false;
sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
// If the window does not have input focus we take away accessibility
// focus as soon as the user stop hovering over the view.
if (mAttachInfo != null && !mAttachInfo.mHasWindowFocus) {
getViewRootImpl().setAccessibilityFocus(null, null);
}
}
}

View File

@@ -162,6 +162,19 @@ public final class AccessibilityInteractionClient
false, AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS);
}
/**
* Gets the root {@link AccessibilityNodeInfo} in a given window.
*
* @param connectionId The id of a connection for interacting with the system.
* @param windowId The window id.
* @return The root {@link AccessibilityNodeInfo} if found, null otherwise.
*/
public AccessibilityNodeInfo getRootInWindow(int connectionId, int windowId) {
return findAccessibilityNodeInfoByAccessibilityId(connectionId, windowId,
AccessibilityNodeInfo.ROOT_NODE_ID, false,
AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS);
}
/**
* Gets the info for a window.
*

View File

@@ -76,6 +76,9 @@ public class AccessibilityNodeInfo implements Parcelable {
/** @hide */
public static final int ACTIVE_WINDOW_ID = UNDEFINED_ITEM_ID;
/** @hide */
public static final int ANY_WINDOW_ID = -2;
/** @hide */
public static final int FLAG_PREFETCH_PREDECESSORS = 0x00000001;

View File

@@ -166,8 +166,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
private final Point mTempPoint = new Point();
private final Display mDefaultDisplay;
private final PackageManager mPackageManager;
private final WindowManagerInternal mWindowManagerService;
@@ -176,7 +174,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
private final MainHandler mMainHandler;
private Service mQueryBridge;
private InteractionBridge mInteractionBridge;
private AlertDialog mEnableTouchExplorationDialog;
@@ -232,10 +230,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
mWindowManagerService = LocalServices.getService(WindowManagerInternal.class);
mSecurityPolicy = new SecurityPolicy();
mMainHandler = new MainHandler(mContext.getMainLooper());
//TODO: (multi-display) We need to support multiple displays.
DisplayManager displayManager = (DisplayManager)
mContext.getSystemService(Context.DISPLAY_SERVICE);
mDefaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
registerBroadcastReceivers();
new AccessibilityContentObserver(mMainHandler).register(
context.getContentResolver());
@@ -401,7 +395,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
return true; // yes, recycle the event
}
if (mSecurityPolicy.canDispatchAccessibilityEventLocked(event)) {
mSecurityPolicy.updateActiveWindowLocked(event.getWindowId(), event.getEventType());
mSecurityPolicy.updateActiveAndAccessibilityFocusedWindowLocked(event.getWindowId(),
event.getSourceNodeId(), event.getEventType());
mSecurityPolicy.updateEventSourceLocked(event);
notifyAccessibilityServicesDelayedLocked(event, false);
notifyAccessibilityServicesDelayedLocked(event, true);
@@ -725,46 +720,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
* @return Whether accessibility focus was found and the bounds are populated.
*/
// TODO: (multi-display) Make sure this works for multiple displays.
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
// since we do this only when the user clicks/long presses.
Service service = getQueryBridge();
final int connectionId = service.mId;
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
client.addConnection(connectionId, service);
try {
AccessibilityNodeInfo root = AccessibilityInteractionClient.getInstance()
.getRootInActiveWindow(connectionId);
if (root == null) {
return false;
}
AccessibilityNodeInfo focus = root.findFocus(
AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
if (focus == null) {
return false;
}
focus.getBoundsInScreen(outBounds);
MagnificationSpec spec = service.getCompatibleMagnificationSpec(focus.getWindowId());
if (spec != null && !spec.isNop()) {
outBounds.offset((int) -spec.offsetX, (int) -spec.offsetY);
outBounds.scale(1 / spec.scale);
}
// Clip to the window rectangle.
Rect windowBounds = mTempRect;
getActiveWindowBounds(windowBounds);
outBounds.intersect(windowBounds);
// Clip to the screen rectangle.
mDefaultDisplay.getRealSize(mTempPoint);
outBounds.intersect(0, 0, mTempPoint.x, mTempPoint.y);
return true;
} finally {
client.removeConnection(connectionId);
}
boolean getAccessibilityFocusBounds(Rect outBounds) {
return getInteractionBridgeLocked().getAccessibilityFocusBoundsNotLocked(outBounds);
}
/**
@@ -855,14 +812,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
}
private Service getQueryBridge() {
if (mQueryBridge == null) {
AccessibilityServiceInfo info = new AccessibilityServiceInfo();
info.setCapabilities(AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT);
mQueryBridge = new Service(UserHandle.USER_NULL,
sFakeAccessibilityServiceComponentName, info);
private InteractionBridge getInteractionBridgeLocked() {
if (mInteractionBridge == null) {
mInteractionBridge = new InteractionBridge();
}
return mQueryBridge;
return mInteractionBridge;
}
private boolean notifyGestureLocked(int gestureId, boolean isDefault) {
@@ -1333,9 +1287,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
private void onUserStateChangedLocked(UserState userState) {
// TODO: Remove this hack
mInitialized = true;
updateLegacyCapabilities(userState);
updateLegacyCapabilitiesLocked(userState);
updateServicesLocked(userState);
updateWindowsForAccessibilityCallback(userState);
updateWindowsForAccessibilityCallbackLocked(userState);
updateAccessibilityFocusBehaviorLocked(userState);
updateFilterKeyEventsLocked(userState);
updateTouchExplorationLocked(userState);
updateEnhancedWebAccessibilityLocked(userState);
@@ -1344,7 +1299,29 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
scheduleUpdateClientsIfNeededLocked(userState);
}
private void updateWindowsForAccessibilityCallback(UserState userState) {
private void updateAccessibilityFocusBehaviorLocked(UserState userState) {
// If there is no service that can operate with interactive windows
// then we keep the old behavior where a window loses accessibility
// focus if it is no longer active. This still changes the behavior
// for services that do not operate with interactive windows and run
// at the same time as the one(s) which does. In practice however,
// there is only one service that uses accessibility focus and it
// is typically the one that operates with interactive windows, So,
// this is fine. Note that to allow a service to work across windows
// we have to allow accessibility focus stay in any of them. Sigh...
List<Service> boundServices = userState.mBoundServices;
final int boundServiceCount = boundServices.size();
for (int i = 0; i < boundServiceCount; i++) {
Service boundService = boundServices.get(i);
if (boundService.canRetrieveInteractiveWindowsLocked()) {
userState.mAccessibilityFocusOnlyInActiveWindow = false;
return;
}
}
userState.mAccessibilityFocusOnlyInActiveWindow = true;
}
private void updateWindowsForAccessibilityCallbackLocked(UserState userState) {
if (userState.mIsAccessibilityEnabled) {
// We observe windows for accessibility only if there is at least
// one bound service that can retrieve window content that specified
@@ -1357,8 +1334,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
final int boundServiceCount = boundServices.size();
for (int i = 0; i < boundServiceCount; i++) {
Service boundService = boundServices.get(i);
if (mSecurityPolicy.canRetrieveWindowContentLocked(boundService)
&& boundService.mRetrieveInteractiveWindows) {
if (boundService.canRetrieveInteractiveWindowsLocked()) {
boundServiceCanRetrieveInteractiveWindows = true;
break;
}
@@ -1381,7 +1357,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
}
private void updateLegacyCapabilities(UserState userState) {
private void updateLegacyCapabilitiesLocked(UserState userState) {
// Up to JB-MR1 we had a white list with services that can enable touch
// exploration. When a service is first started we show a dialog to the
// use to get a permission to white list the service.
@@ -1582,6 +1558,18 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
DisplayAdjustmentUtils.applyAdjustments(mContext, userState.mUserId);
}
private MagnificationSpec getCompatibleMagnificationSpecLocked(int windowId) {
IBinder windowToken = mGlobalWindowTokens.get(windowId);
if (windowToken == null) {
windowToken = getCurrentUserStateLocked().mWindowTokens.get(windowId);
}
if (windowToken != null) {
return mWindowManagerService.getCompatibleMagnificationSpecForWindow(
windowToken);
}
return null;
}
@Override
public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
mSecurityPolicy.enforceCallingPermission(Manifest.permission.DUMP, FUNCTION_DUMP);
@@ -1658,6 +1646,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
public static final int MSG_UPDATE_INPUT_FILTER = 6;
public static final int MSG_SHOW_ENABLED_TOUCH_EXPLORATION_DIALOG = 7;
public static final int MSG_SEND_KEY_EVENT_TO_INPUT_FILTER = 8;
public static final int MSG_CLEAR_ACCESSIBILITY_FOCUS = 9;
public MainHandler(Looper looper) {
super(looper);
@@ -1713,6 +1702,15 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
Service service = (Service) msg.obj;
showEnableTouchExplorationDialog(service);
} break;
case MSG_CLEAR_ACCESSIBILITY_FOCUS: {
final int windowId = msg.arg1;
InteractionBridge bridge;
synchronized (mLock) {
bridge = getInteractionBridgeLocked();
}
bridge.clearAccessibilityFocusNotLocked(windowId);
} break;
}
}
@@ -1981,6 +1979,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
}
public boolean canRetrieveInteractiveWindowsLocked() {
return mSecurityPolicy.canRetrieveWindowContentLocked(this)
&& mRetrieveInteractiveWindows;
}
@Override
public void setServiceInfo(AccessibilityServiceInfo info) {
final long identity = Binder.clearCallingIdentity();
@@ -2109,7 +2112,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
final int interrogatingPid = Binder.getCallingPid();
final long identityToken = Binder.clearCallingIdentity();
MagnificationSpec spec = getCompatibleMagnificationSpec(resolvedWindowId);
MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId);
try {
connection.findAccessibilityNodeInfosByViewId(accessibilityNodeId,
viewIdResName, interactionId, callback, mFetchFlags, interrogatingPid,
@@ -2153,7 +2156,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
final int interrogatingPid = Binder.getCallingPid();
final long identityToken = Binder.clearCallingIdentity();
MagnificationSpec spec = getCompatibleMagnificationSpec(resolvedWindowId);
MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId);
try {
connection.findAccessibilityNodeInfosByText(accessibilityNodeId, text,
interactionId, callback, mFetchFlags, interrogatingPid, interrogatingTid,
@@ -2197,7 +2200,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
final int interrogatingPid = Binder.getCallingPid();
final long identityToken = Binder.clearCallingIdentity();
MagnificationSpec spec = getCompatibleMagnificationSpec(resolvedWindowId);
MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId);
try {
connection.findAccessibilityNodeInfoByAccessibilityId(accessibilityNodeId,
interactionId, callback, mFetchFlags | flags, interrogatingPid,
@@ -2227,7 +2230,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
if (resolvedUserId != mCurrentUserId) {
return false;
}
resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
resolvedWindowId = resolveAccessibilityWindowIdForFindFocusLocked(
accessibilityWindowId, focusType);
final boolean permissionGranted =
mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
if (!permissionGranted) {
@@ -2241,14 +2245,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
final int interrogatingPid = Binder.getCallingPid();
final long identityToken = Binder.clearCallingIdentity();
MagnificationSpec spec = getCompatibleMagnificationSpec(resolvedWindowId);
MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId);
try {
connection.findFocus(accessibilityNodeId, focusType, interactionId, callback,
mFetchFlags, interrogatingPid, interrogatingTid, spec);
return true;
} catch (RemoteException re) {
if (DEBUG) {
Slog.e(LOG_TAG, "Error calling findAccessibilityFocus()");
Slog.e(LOG_TAG, "Error calling findFocus()");
}
} finally {
Binder.restoreCallingIdentity(identityToken);
@@ -2284,7 +2288,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
final int interrogatingPid = Binder.getCallingPid();
final long identityToken = Binder.clearCallingIdentity();
MagnificationSpec spec = getCompatibleMagnificationSpec(resolvedWindowId);
MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId);
try {
connection.focusSearch(accessibilityNodeId, direction, interactionId, callback,
mFetchFlags, interrogatingPid, interrogatingTid, spec);
@@ -2729,16 +2733,18 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
return accessibilityWindowId;
}
private MagnificationSpec getCompatibleMagnificationSpec(int windowId) {
IBinder windowToken = mGlobalWindowTokens.get(windowId);
if (windowToken == null) {
windowToken = getCurrentUserStateLocked().mWindowTokens.get(windowId);
private int resolveAccessibilityWindowIdForFindFocusLocked(int windowId, int focusType) {
if (windowId == AccessibilityNodeInfo.ACTIVE_WINDOW_ID) {
return mSecurityPolicy.mActiveWindowId;
}
if (windowToken != null) {
return mWindowManagerService.getCompatibleMagnificationSpecForWindow(
windowToken);
if (windowId == AccessibilityNodeInfo.ANY_WINDOW_ID) {
if (focusType == AccessibilityNodeInfo.FOCUS_INPUT) {
return mSecurityPolicy.mFocusedWindowId;
} else if (focusType == AccessibilityNodeInfo.FOCUS_ACCESSIBILITY) {
return mSecurityPolicy.mAccessibilityFocusedWindowId;
}
}
return null;
return windowId;
}
private final class InvocationHandler extends Handler {
@@ -3031,7 +3037,86 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
}
private final class InteractionBridge {
private final Display mDefaultDisplay;
private final int mConnectionId;
private final AccessibilityInteractionClient mClient;
public InteractionBridge() {
AccessibilityServiceInfo info = new AccessibilityServiceInfo();
info.setCapabilities(AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT);
info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS;
info.flags |= AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
Service service = new Service(UserHandle.USER_NULL,
sFakeAccessibilityServiceComponentName, info);
mConnectionId = service.mId;
mClient = AccessibilityInteractionClient.getInstance();
mClient.addConnection(mConnectionId, service);
//TODO: (multi-display) We need to support multiple displays.
DisplayManager displayManager = (DisplayManager)
mContext.getSystemService(Context.DISPLAY_SERVICE);
mDefaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
}
public void clearAccessibilityFocusNotLocked(int windowId) {
AccessibilityNodeInfo focus = getAccessibilityFocusNotLocked(windowId);
if (focus != null) {
focus.performAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
}
}
public boolean getAccessibilityFocusBoundsNotLocked(Rect outBounds) {
AccessibilityNodeInfo focus = getAccessibilityFocusNotLocked();
if (focus == null) {
return false;
}
synchronized (mLock) {
focus.getBoundsInScreen(outBounds);
MagnificationSpec spec = getCompatibleMagnificationSpecLocked(focus.getWindowId());
if (spec != null && !spec.isNop()) {
outBounds.offset((int) -spec.offsetX, (int) -spec.offsetY);
outBounds.scale(1 / spec.scale);
}
// Clip to the window rectangle.
Rect windowBounds = mTempRect;
getActiveWindowBounds(windowBounds);
outBounds.intersect(windowBounds);
// Clip to the screen rectangle.
mDefaultDisplay.getRealSize(mTempPoint);
outBounds.intersect(0, 0, mTempPoint.x, mTempPoint.y);
return true;
}
}
private AccessibilityNodeInfo getAccessibilityFocusNotLocked() {
final int focusedWindowId;
synchronized (mLock) {
focusedWindowId = mSecurityPolicy.mAccessibilityFocusedWindowId;
if (focusedWindowId == SecurityPolicy.INVALID_WINDOW_ID) {
return null;
}
}
return getAccessibilityFocusNotLocked(focusedWindowId);
}
private AccessibilityNodeInfo getAccessibilityFocusNotLocked(int windowId) {
return mClient.findFocus(mConnectionId,
windowId, AccessibilityNodeInfo.ROOT_NODE_ID,
AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
}
}
final class SecurityPolicy {
public static final int INVALID_WINDOW_ID = -1;
private static final int VALID_ACTIONS =
AccessibilityNodeInfo.ACTION_CLICK
| AccessibilityNodeInfo.ACTION_LONG_CLICK
@@ -3075,8 +3160,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
public final List<AccessibilityWindowInfo> mWindows =
new ArrayList<AccessibilityWindowInfo>();
public int mActiveWindowId;
public int mFocusedWindowId;
public int mActiveWindowId = INVALID_WINDOW_ID;
public int mFocusedWindowId = INVALID_WINDOW_ID;
public int mAccessibilityFocusedWindowId = INVALID_WINDOW_ID;
public long mAccessibilityFocusNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
public AccessibilityEvent mShowingFocusedWindowEvent;
private boolean mTouchInteractionInProgress;
@@ -3129,9 +3217,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
mWindows.remove(i).recycle();
}
mFocusedWindowId = -1;
mFocusedWindowId = INVALID_WINDOW_ID;
if (!mTouchInteractionInProgress) {
mActiveWindowId = -1;
mActiveWindowId = INVALID_WINDOW_ID;
}
// If the active window goes away while the user is touch exploring we
@@ -3159,7 +3247,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
if (mTouchInteractionInProgress && activeWindowGone) {
mActiveWindowId = -1;
mActiveWindowId = INVALID_WINDOW_ID;
}
// Focused window may change the active one, so set the
@@ -3193,7 +3281,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
}
public void updateActiveWindowLocked(int windowId, int eventType) {
public void updateActiveAndAccessibilityFocusedWindowLocked(int windowId, long nodeId,
int eventType) {
// The active window is either the window that has input focus or
// the window that the user is currently touching. If the user is
// touching a window that does not have input focus as soon as the
@@ -3228,6 +3317,29 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
}
} break;
case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
synchronized (mLock) {
if (mAccessibilityFocusedWindowId != windowId) {
mMainHandler.obtainMessage(MainHandler.MSG_CLEAR_ACCESSIBILITY_FOCUS,
mAccessibilityFocusedWindowId, 0).sendToTarget();
mAccessibilityFocusedWindowId = windowId;
mAccessibilityFocusNodeId = nodeId;
}
}
} break;
case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
synchronized (mLock) {
if (mAccessibilityFocusNodeId == nodeId) {
mAccessibilityFocusNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
}
if (mAccessibilityFocusNodeId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID
&& mAccessibilityFocusedWindowId == windowId) {
mAccessibilityFocusedWindowId = INVALID_WINDOW_ID;
}
}
} break;
}
}
@@ -3248,7 +3360,19 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
// (they are a result of user touching the screen) so change of
// the active window before all hover accessibility events from
// the touched window are delivered is fine.
final int oldActiveWindow = mSecurityPolicy.mActiveWindowId;
setActiveWindowLocked(mFocusedWindowId);
// If there is no service that can operate with active windows
// we keep accessibility focus behavior to constrain it only in
// the active window. Look at updateAccessibilityFocusBehaviorLocked
// for details.
if (oldActiveWindow != mSecurityPolicy.mActiveWindowId
&& mAccessibilityFocusedWindowId == oldActiveWindow
&& getCurrentUserStateLocked().mAccessibilityFocusOnlyInActiveWindow) {
mMainHandler.obtainMessage(MainHandler.MSG_CLEAR_ACCESSIBILITY_FOCUS,
oldActiveWindow, 0).sendToTarget();
}
}
}
@@ -3403,6 +3527,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
public boolean mIsDisplayMagnificationEnabled;
public boolean mIsFilterKeyEventsEnabled;
public boolean mHasDisplayColorAdjustment;
public boolean mAccessibilityFocusOnlyInActiveWindow;
private Service mUiAutomationService;
private IAccessibilityServiceClient mUiAutomationServiceClient;

View File

@@ -1159,7 +1159,7 @@ class TouchExplorer implements EventStreamTransformation {
// 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)) {
if (mAms.getAccessibilityFocusBounds(focusBounds)) {
clickLocationX = focusBounds.centerX();
clickLocationY = focusBounds.centerY();
} else {
@@ -1177,7 +1177,7 @@ class TouchExplorer implements EventStreamTransformation {
mAms.getActiveWindowBounds(activeWindowBounds);
if (activeWindowBounds.contains(clickLocationX, clickLocationY)) {
Rect focusBounds = mTempRect;
if (mAms.getAccessibilityFocusBoundsInActiveWindow(focusBounds)) {
if (mAms.getAccessibilityFocusBounds(focusBounds)) {
if (!focusBounds.contains(clickLocationX, clickLocationY)) {
clickLocationX = focusBounds.centerX();
clickLocationY = focusBounds.centerY();
@@ -1332,7 +1332,7 @@ class TouchExplorer implements EventStreamTransformation {
// 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)) {
if (mAms.getAccessibilityFocusBounds(focusBounds)) {
clickLocationX = focusBounds.centerX();
clickLocationY = focusBounds.centerY();
} else {
@@ -1350,7 +1350,7 @@ class TouchExplorer implements EventStreamTransformation {
mAms.getActiveWindowBounds(activeWindowBounds);
if (activeWindowBounds.contains(clickLocationX, clickLocationY)) {
Rect focusBounds = mTempRect;
if (mAms.getAccessibilityFocusBoundsInActiveWindow(focusBounds)) {
if (mAms.getAccessibilityFocusBounds(focusBounds)) {
if (!focusBounds.contains(clickLocationX, clickLocationY)) {
clickLocationX = focusBounds.centerX();
clickLocationY = focusBounds.centerY();