summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jackal Guo <jackalguo@google.com> 2018-09-13 05:09:49 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2018-09-13 05:09:49 +0000
commitf6493516ebb320716b43e5a6fd394d6b0a519da1 (patch)
tree5c0dd708363eea2f6df96d831d4ad65373680988
parent80058fd2eac4b20c52f551e78c71e71843ddeade (diff)
parentac2b62e9b5c51c7ff29f8e5bc7193a6cc9b24c86 (diff)
Merge "Accessibility actions should trigger ACTION_OUTSIDE"
-rw-r--r--core/java/android/view/AccessibilityInteractionController.java9
-rw-r--r--core/java/android/view/WindowInfo.java7
-rw-r--r--core/res/res/values/ids.xml3
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java57
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java2
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();