diff options
| author | 2018-09-13 05:09:49 +0000 | |
|---|---|---|
| committer | 2018-09-13 05:09:49 +0000 | |
| commit | f6493516ebb320716b43e5a6fd394d6b0a519da1 (patch) | |
| tree | 5c0dd708363eea2f6df96d831d4ad65373680988 | |
| parent | 80058fd2eac4b20c52f551e78c71e71843ddeade (diff) | |
| parent | ac2b62e9b5c51c7ff29f8e5bc7193a6cc9b24c86 (diff) | |
Merge "Accessibility actions should trigger ACTION_OUTSIDE"
6 files changed, 79 insertions, 0 deletions
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java index 45fa5614abb7..eb41e078e59f 100644 --- a/core/java/android/view/AccessibilityInteractionController.java +++ b/core/java/android/view/AccessibilityInteractionController.java @@ -32,6 +32,7 @@ import android.os.Message; import android.os.Parcelable; import android.os.Process; import android.os.RemoteException; +import android.os.SystemClock; import android.text.style.AccessibilityClickableSpan; import android.text.style.ClickableSpan; import android.util.LongSparseArray; @@ -702,6 +703,14 @@ final class AccessibilityInteractionController { // Handle this hidden action separately succeeded = handleClickableSpanActionUiThread( target, virtualDescendantId, arguments); + } else if (action == R.id.accessibilityActionOutsideTouch) { + // trigger ACTION_OUTSIDE to notify windows + final long now = SystemClock.uptimeMillis(); + MotionEvent event = MotionEvent.obtain(now, now, MotionEvent.ACTION_OUTSIDE, + 0, 0, 0); + event.setSource(InputDevice.SOURCE_TOUCHSCREEN); + mViewRootImpl.dispatchInputEvent(event); + succeeded = true; } else { AccessibilityNodeProvider provider = target.getAccessibilityNodeProvider(); if (provider != null) { diff --git a/core/java/android/view/WindowInfo.java b/core/java/android/view/WindowInfo.java index 7bae28a4e817..82e9a5c71eae 100644 --- a/core/java/android/view/WindowInfo.java +++ b/core/java/android/view/WindowInfo.java @@ -49,6 +49,7 @@ public class WindowInfo implements Parcelable { public CharSequence title; public long accessibilityIdOfAnchor = AccessibilityNodeInfo.UNDEFINED_NODE_ID; public boolean inPictureInPicture; + public boolean hasFlagWatchOutsideTouch; private WindowInfo() { /* do nothing - hide constructor */ @@ -74,6 +75,7 @@ public class WindowInfo implements Parcelable { window.title = other.title; window.accessibilityIdOfAnchor = other.accessibilityIdOfAnchor; window.inPictureInPicture = other.inPictureInPicture; + window.hasFlagWatchOutsideTouch = other.hasFlagWatchOutsideTouch; if (other.childTokens != null && !other.childTokens.isEmpty()) { if (window.childTokens == null) { @@ -108,6 +110,7 @@ public class WindowInfo implements Parcelable { parcel.writeCharSequence(title); parcel.writeLong(accessibilityIdOfAnchor); parcel.writeInt(inPictureInPicture ? 1 : 0); + parcel.writeInt(hasFlagWatchOutsideTouch ? 1 : 0); if (childTokens != null && !childTokens.isEmpty()) { parcel.writeInt(1); @@ -130,6 +133,8 @@ public class WindowInfo implements Parcelable { builder.append(", focused=").append(focused); builder.append(", children=").append(childTokens); builder.append(", accessibility anchor=").append(accessibilityIdOfAnchor); + builder.append(", pictureInPicture=").append(inPictureInPicture); + builder.append(", watchOutsideTouch=").append(hasFlagWatchOutsideTouch); builder.append(']'); return builder.toString(); } @@ -145,6 +150,7 @@ public class WindowInfo implements Parcelable { title = parcel.readCharSequence(); accessibilityIdOfAnchor = parcel.readLong(); inPictureInPicture = (parcel.readInt() == 1); + hasFlagWatchOutsideTouch = (parcel.readInt() == 1); final boolean hasChildren = (parcel.readInt() == 1); if (hasChildren) { @@ -167,6 +173,7 @@ public class WindowInfo implements Parcelable { childTokens.clear(); } inPictureInPicture = false; + hasFlagWatchOutsideTouch = false; } public static final Parcelable.Creator<WindowInfo> CREATOR = diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml index bf7e0682e91b..8bca211899d1 100644 --- a/core/res/res/values/ids.xml +++ b/core/res/res/values/ids.xml @@ -172,4 +172,7 @@ <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_HIDE_TOOLTIP}. --> <item type="id" name="accessibilityActionHideTooltip" /> + + <!-- Accessibility action to notify a window there is an outside touch. --> + <item type="id" name="accessibilityActionOutsideTouch" /> </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 389278f87fa1..7b6e064c9cf9 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -218,6 +218,7 @@ <java-symbol type="id" name="selection_end_handle" /> <java-symbol type="id" name="insertion_handle" /> <java-symbol type="id" name="accessibilityActionClickOnClickableSpan" /> + <java-symbol type="id" name="accessibilityActionOutsideTouch" /> <java-symbol type="id" name="camera" /> <java-symbol type="id" name="mic" /> <java-symbol type="id" name="overlay" /> diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index d675f922141f..9bee8dba87ad 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -21,6 +21,8 @@ import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY import static android.view.accessibility.AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED; import static android.view.accessibility.AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS; import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS; +import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK; +import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK; import static com.android.internal.util.FunctionalUtils.ignoreRemoteException; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; import static android.accessibilityservice.AccessibilityService.SHOW_MODE_AUTO; @@ -2621,6 +2623,38 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub return -1; } + private void notifyOutsideTouchIfNeeded(int targetWindowId, int action, Bundle arguments, + int interactionId, IAccessibilityInteractionConnectionCallback callback, int fetchFlags, + int interrogatingPid, long interrogatingTid) { + if (action != ACTION_CLICK && action != ACTION_LONG_CLICK) { + return; + } + + final List<Integer> outsideWindowsIds; + final List<RemoteAccessibilityConnection> connectionList = new ArrayList<>(); + synchronized (mLock) { + outsideWindowsIds = mSecurityPolicy.getWatchOutsideTouchWindowId(targetWindowId); + for (int i = 0; i < outsideWindowsIds.size(); i++) { + connectionList.add(getConnectionLocked(outsideWindowsIds.get(i))); + } + } + for (int i = 0; i < connectionList.size(); i++) { + final RemoteAccessibilityConnection connection = connectionList.get(i); + if (connection != null) { + try { + connection.mConnection.performAccessibilityAction( + AccessibilityNodeInfo.ROOT_ITEM_ID, + R.id.accessibilityActionOutsideTouch, arguments, interactionId, + callback, fetchFlags, interrogatingPid, interrogatingTid); + } catch (RemoteException re) { + if (DEBUG) { + Slog.e(LOG_TAG, "Error calling performAccessibilityAction: " + re); + } + } + } + } + } + @Override public void ensureWindowsAvailableTimed() { synchronized (mLock) { @@ -2700,6 +2734,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mPowerManager.userActivity(SystemClock.uptimeMillis(), PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY, 0); + notifyOutsideTouchIfNeeded(resolvedWindowId, action, arguments, interactionId, callback, + fetchFlags, interrogatingPid, interrogatingTid); if (activityToken != null) { LocalServices.getService(ActivityTaskManagerInternal.class) .setFocusedActivity(activityToken); @@ -3027,6 +3063,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub public long mAccessibilityFocusNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID; private boolean mTouchInteractionInProgress; + private boolean mHasWatchOutsideTouchWindow; private boolean canDispatchAccessibilityEventLocked(AccessibilityEvent event) { final int eventType = event.getEventType(); @@ -3184,6 +3221,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mWindowInfoById.valueAt(i).recycle(); } mWindowInfoById.clear(); + mHasWatchOutsideTouchWindow = false; mFocusedWindowId = INVALID_WINDOW_ID; if (!mTouchInteractionInProgress) { @@ -3228,6 +3266,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub activeWindowGone = false; } } + if (!mHasWatchOutsideTouchWindow && windowInfo.hasFlagWatchOutsideTouch) { + mHasWatchOutsideTouchWindow = true; + } mWindows.add(window); mA11yWindowInfoById.put(windowId, window); mWindowInfoById.put(windowId, WindowInfo.obtain(windowInfo)); @@ -3646,6 +3687,22 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub return mWindowInfoById.get(windowId); } + private List<Integer> getWatchOutsideTouchWindowId(int targetWindowId) { + if (mWindowInfoById != null && mHasWatchOutsideTouchWindow) { + final List<Integer> outsideWindowsId = new ArrayList<>(); + final WindowInfo targetWindow = mWindowInfoById.get(targetWindowId); + for (int i = 0; i < mWindowInfoById.size(); i++) { + WindowInfo window = mWindowInfoById.valueAt(i); + if (window.layer < targetWindow.layer + && window.hasFlagWatchOutsideTouch) { + outsideWindowsId.add(mWindowInfoById.keyAt(i)); + } + } + return outsideWindowsId; + } + return Collections.emptyList(); + } + private AccessibilityWindowInfo getPictureInPictureWindow() { if (mWindows != null) { final int windowCount = mWindows.size(); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 637c0eabdac4..110027962e72 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -3734,6 +3734,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP windowInfo.focused = isFocused(); Task task = getTask(); windowInfo.inPictureInPicture = (task != null) && task.inPinnedWindowingMode(); + windowInfo.hasFlagWatchOutsideTouch = + (mAttrs.flags & WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH) != 0; if (mIsChildWindow) { windowInfo.parentToken = getParentWindow().mClient.asBinder(); |