Merge "Add passthrough functionality for touch exploration and gesture detection."

This commit is contained in:
Ameer Armaly
2020-02-19 06:16:20 +00:00
committed by Android (Google) Code Review
8 changed files with 172 additions and 5 deletions

View File

@@ -2871,7 +2871,9 @@ package android.accessibilityservice {
method protected void onServiceConnected();
method public void onSystemActionsChanged();
method public final boolean performGlobalAction(int);
method public void setGestureDetectionPassthroughRegion(int, @NonNull android.graphics.Region);
method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo);
method public void setTouchExplorationPassthroughRegion(int, @NonNull android.graphics.Region);
method public boolean takeScreenshot(int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.accessibilityservice.AccessibilityService.ScreenshotResult>);
field public static final int GESTURE_2_FINGER_DOUBLE_TAP = 20; // 0x14
field public static final int GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD = 40; // 0x28

View File

@@ -2414,4 +2414,55 @@ public abstract class AccessibilityService extends Service {
return mTimestamp;
};
}
/**
* When {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is enabled, this
* function requests that touch interactions starting in the specified region of the screen
* bypass the gesture detector. There can only be one gesture detection passthrough region per
* display. Requesting a new gesture detection passthrough region clears the existing one. To
* disable this passthrough and return to the original behavior, pass in an empty region. When
* {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is disabled this
* function has no effect.
*
* @param displayId The display on which to set this region.
* @param region the region of the screen.
*/
public void setGestureDetectionPassthroughRegion(int displayId, @NonNull Region region) {
Preconditions.checkNotNull(region, "region cannot be null");
final IAccessibilityServiceConnection connection =
AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
if (connection != null) {
try {
connection.setGestureDetectionPassthroughRegion(displayId, region);
} catch (RemoteException re) {
throw new RuntimeException(re);
}
}
}
/**
* When {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is enabled, this
* function requests that touch interactions starting in the specified region of the screen
* bypass the touch explorer and go straight to the view hierarchy. There can only be one touch
* exploration passthrough region per display. Requesting a new touch explorationpassthrough
* region clears the existing one. To disable this passthrough and return to the original
* behavior, pass in an empty region. When {@link
* AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is disabled this function has
* no effect.
*
* @param displayId The display on which to set this region.
* @param region the region of the screen .
*/
public void setTouchExplorationPassthroughRegion(int displayId, @NonNull Region region) {
Preconditions.checkNotNull(region, "region cannot be null");
final IAccessibilityServiceConnection connection =
AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
if (connection != null) {
try {
connection.setTouchExplorationPassthroughRegion(displayId, region);
} catch (RemoteException re) {
throw new RuntimeException(re);
}
}
}
}

View File

@@ -111,4 +111,8 @@ interface IAccessibilityServiceConnection {
int getWindowIdForLeashToken(IBinder token);
void takeScreenshot(int displayId, in RemoteCallback callback);
void setGestureDetectionPassthroughRegion(int displayId, in Region region);
void setTouchExplorationPassthroughRegion(int displayId, in Region region);
}

View File

@@ -157,4 +157,8 @@ public class AccessibilityServiceConnectionImpl extends IAccessibilityServiceCon
}
public void takeScreenshot(int displayId, RemoteCallback callback) {}
public void setTouchExplorationPassthroughRegion(int displayId, Region region) {}
public void setGestureDetectionPassthroughRegion(int displayId, Region region) {}
}

View File

@@ -230,6 +230,10 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
/* This is exactly PendingIntent.getActivity, separated out for testability */
PendingIntent getPendingIntentActivity(Context context, int requestCode, Intent intent,
int flags);
void setGestureDetectionPassthroughRegion(int displayId, Region region);
void setTouchExplorationPassthroughRegion(int displayId, Region region);
}
public AbstractAccessibilityServiceConnection(Context context, ComponentName componentName,
@@ -1736,4 +1740,14 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
public boolean isMultiFingerGesturesEnabled() {
return mRequestMultiFingerGestures;
}
@Override
public void setGestureDetectionPassthroughRegion(int displayId, Region region) {
mSystemSupport.setGestureDetectionPassthroughRegion(displayId, region);
}
@Override
public void setTouchExplorationPassthroughRegion(int displayId, Region region) {
mSystemSupport.setTouchExplorationPassthroughRegion(displayId, region);
}
}

View File

@@ -17,6 +17,7 @@
package com.android.server.accessibility;
import android.content.Context;
import android.graphics.Region;
import android.os.PowerManager;
import android.util.Slog;
import android.util.SparseArray;
@@ -726,4 +727,16 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
return shouldProcess;
}
}
public void setGestureDetectionPassthroughRegion(int displayId, Region region) {
if (region != null && mTouchExplorer.contains(displayId)) {
mTouchExplorer.get(displayId).setGestureDetectionPassthroughRegion(region);
}
}
public void setTouchExplorationPassthroughRegion(int displayId, Region region) {
if (region != null && mTouchExplorer.contains(displayId)) {
mTouchExplorer.get(displayId).setTouchExplorationPassthroughRegion(region);
}
}
}

View File

@@ -3058,4 +3058,40 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
}
}
@Override
public void setGestureDetectionPassthroughRegion(int displayId, Region region) {
mMainHandler.sendMessage(
obtainMessage(
AccessibilityManagerService::setGestureDetectionPassthroughRegionInternal,
this,
displayId,
region));
}
@Override
public void setTouchExplorationPassthroughRegion(int displayId, Region region) {
mMainHandler.sendMessage(
obtainMessage(
AccessibilityManagerService::setTouchExplorationPassthroughRegionInternal,
this,
displayId,
region));
}
private void setTouchExplorationPassthroughRegionInternal(int displayId, Region region) {
synchronized (mLock) {
if (mHasInputFilter && mInputFilter != null) {
mInputFilter.setTouchExplorationPassthroughRegion(displayId, region);
}
}
}
private void setGestureDetectionPassthroughRegionInternal(int displayId, Region region) {
synchronized (mLock) {
if (mHasInputFilter && mInputFilter != null) {
mInputFilter.setGestureDetectionPassthroughRegion(displayId, region);
}
}
}
}

View File

@@ -23,6 +23,7 @@ import static com.android.server.accessibility.gestures.TouchState.ALL_POINTER_I
import android.accessibilityservice.AccessibilityGestureEvent;
import android.content.Context;
import android.graphics.Point;
import android.graphics.Region;
import android.os.Handler;
import android.util.Slog;
import android.view.InputDevice;
@@ -120,6 +121,8 @@ public class TouchExplorer extends BaseEventStreamTransformation
// Context in which this explorer operates.
private final Context mContext;
private Region mGestureDetectionPassthroughRegion;
private Region mTouchExplorationPassthroughRegion;
/**
* Creates a new instance.
@@ -165,6 +168,8 @@ public class TouchExplorer extends BaseEventStreamTransformation
} else {
mGestureDetector = detector;
}
mGestureDetectionPassthroughRegion = new Region();
mTouchExplorationPassthroughRegion = new Region();
}
@Override
@@ -230,10 +235,11 @@ public class TouchExplorer extends BaseEventStreamTransformation
}
mState.onReceivedMotionEvent(rawEvent);
if (mGestureDetector.onMotionEvent(event, rawEvent, policyFlags)) {
// Event was handled by the gesture detector.
return;
if (shouldPerformGestureDetection(event)) {
if (mGestureDetector.onMotionEvent(event, rawEvent, policyFlags)) {
// Event was handled by the gesture detector.
return;
}
}
if (event.getActionMasked() == MotionEvent.ACTION_CANCEL) {
@@ -418,6 +424,21 @@ public class TouchExplorer extends BaseEventStreamTransformation
mSendTouchExplorationEndDelayed.forceSendAndRemove();
mSendTouchInteractionEndDelayed.forceSendAndRemove();
mDispatcher.sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_START);
if (mTouchExplorationPassthroughRegion.contains(
(int) event.getX(), (int) event.getY())) {
// The touch exploration passthrough overrides the gesture detection passthrough in
// the event they overlap.
// Pass this entire gesture through to the system as-is.
mState.startDelegating();
event = MotionEvent.obtainNoHistory(event);
mDispatcher.sendMotionEvent(
event, event.getAction(), rawEvent, ALL_POINTER_ID_BITS, policyFlags);
mSendHoverEnterAndMoveDelayed.cancel();
} else if (mGestureDetectionPassthroughRegion.contains(
(int) event.getX(), (int) event.getY())) {
// Jump straight to touch exploration.
mSendHoverEnterAndMoveDelayed.forceSendAndRemove();
}
} else {
// Avoid duplicated TYPE_TOUCH_INTERACTION_START event when 2nd tap of double tap.
mSendTouchInteractionEndDelayed.cancel();
@@ -909,6 +930,29 @@ public class TouchExplorer extends BaseEventStreamTransformation
mGestureDetector.setMultiFingerGesturesEnabled(enabled);
}
public void setGestureDetectionPassthroughRegion(Region region) {
mGestureDetectionPassthroughRegion = region;
}
public void setTouchExplorationPassthroughRegion(Region region) {
mTouchExplorationPassthroughRegion = region;
}
private boolean shouldPerformGestureDetection(MotionEvent event) {
if (mState.isDelegating()) {
return false;
}
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
final int x = (int) event.getX();
final int y = (int) event.getY();
if (mTouchExplorationPassthroughRegion.contains(x, y)
|| mGestureDetectionPassthroughRegion.contains(x, y)) {
return false;
}
}
return true;
}
/**
* Class for delayed exiting from gesture detecting mode.
*/
@@ -1135,5 +1179,4 @@ public class TouchExplorer extends BaseEventStreamTransformation
+ ", mTempPoint: " + mTempPoint
+ " }";
}
}