blob: b1bb32e16e6773c230275b50ca91b7d74b18b9f6 [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.accessibilityservice.cts;
import static android.accessibilityservice.cts.utils.AsyncUtils.await;
import static android.accessibilityservice.cts.utils.GestureUtils.IS_ACTION_DOWN;
import static android.accessibilityservice.cts.utils.GestureUtils.IS_ACTION_UP;
import static android.accessibilityservice.cts.utils.GestureUtils.add;
import static android.accessibilityservice.cts.utils.GestureUtils.ceil;
import static android.accessibilityservice.cts.utils.GestureUtils.click;
import static android.accessibilityservice.cts.utils.GestureUtils.diff;
import static android.accessibilityservice.cts.utils.GestureUtils.dispatchGesture;
import static android.accessibilityservice.cts.utils.GestureUtils.doubleTap;
import static android.accessibilityservice.cts.utils.GestureUtils.doubleTapAndHold;
import static android.accessibilityservice.cts.utils.GestureUtils.isRawAtPoint;
import static android.accessibilityservice.cts.utils.GestureUtils.multiTap;
import static android.accessibilityservice.cts.utils.GestureUtils.secondFingerMultiTap;
import static android.accessibilityservice.cts.utils.GestureUtils.swipe;
import static android.accessibilityservice.cts.utils.GestureUtils.times;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_HOVER_ENTER;
import static android.view.MotionEvent.ACTION_HOVER_EXIT;
import static android.view.MotionEvent.ACTION_HOVER_MOVE;
import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_POINTER_DOWN;
import static android.view.MotionEvent.ACTION_POINTER_UP;
import static android.view.MotionEvent.ACTION_UP;
import static android.view.accessibility.AccessibilityEvent.TYPE_GESTURE_DETECTION_END;
import static android.view.accessibility.AccessibilityEvent.TYPE_GESTURE_DETECTION_START;
import static android.view.accessibility.AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END;
import static android.view.accessibility.AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START;
import static android.view.accessibility.AccessibilityEvent.TYPE_TOUCH_INTERACTION_END;
import static android.view.accessibility.AccessibilityEvent.TYPE_TOUCH_INTERACTION_START;
import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED;
import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_CLICKED;
import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_LONG_CLICKED;
import static org.hamcrest.CoreMatchers.both;
import static org.hamcrest.MatcherAssert.assertThat;
import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
import android.accessibility.cts.common.InstrumentedAccessibilityServiceTestRule;
import android.accessibilityservice.GestureDescription;
import android.accessibilityservice.GestureDescription.StrokeDescription;
import android.accessibilityservice.cts.AccessibilityGestureDispatchTest.GestureDispatchActivity;
import android.accessibilityservice.cts.utils.EventCapturingClickListener;
import android.accessibilityservice.cts.utils.EventCapturingHoverListener;
import android.accessibilityservice.cts.utils.EventCapturingLongClickListener;
import android.accessibilityservice.cts.utils.EventCapturingTouchListener;
import android.app.Instrumentation;
import android.app.UiAutomation;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Region;
import android.platform.test.annotations.AppModeFull;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityNodeInfo;
import androidx.test.InstrumentationRegistry;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;
import java.util.List;
/**
* A set of tests for testing touch exploration. Each test dispatches a gesture and checks for the
* appropriate hover and/or touch events followed by the appropriate accessibility events. Some
* tests will then check for events from the view.
*/
@RunWith(AndroidJUnit4.class)
@AppModeFull
public class TouchExplorerTest {
// Constants
private static final float GESTURE_LENGTH_INCHES = 1.0f;
private static final int SWIPE_TIME_MILLIS = 400;
private TouchExplorationStubAccessibilityService mService;
private Instrumentation mInstrumentation;
private UiAutomation mUiAutomation;
private boolean mHasTouchscreen;
private boolean mScreenBigEnough;
private EventCapturingHoverListener mHoverListener = new EventCapturingHoverListener(false);
private EventCapturingTouchListener mTouchListener = new EventCapturingTouchListener(false);
private EventCapturingClickListener mClickListener = new EventCapturingClickListener();
private EventCapturingLongClickListener mLongClickListener =
new EventCapturingLongClickListener();
private ActivityTestRule<GestureDispatchActivity> mActivityRule =
new ActivityTestRule<>(GestureDispatchActivity.class, false);
private InstrumentedAccessibilityServiceTestRule<TouchExplorationStubAccessibilityService>
mServiceRule = new InstrumentedAccessibilityServiceTestRule<>(
TouchExplorationStubAccessibilityService.class, false);
private AccessibilityDumpOnFailureRule mDumpOnFailureRule =
new AccessibilityDumpOnFailureRule();
@Rule
public final RuleChain mRuleChain = RuleChain
.outerRule(mActivityRule)
.around(mServiceRule)
.around(mDumpOnFailureRule);
Point mCenter; // Center of screen. Gestures all start from this point.
PointF mTapLocation;
float mSwipeDistance;
View mView;
@Before
public void setUp() throws Exception {
mInstrumentation = InstrumentationRegistry.getInstrumentation();
mUiAutomation = mInstrumentation.getUiAutomation(
UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
PackageManager pm = mInstrumentation.getContext().getPackageManager();
mHasTouchscreen = pm.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)
|| pm.hasSystemFeature(PackageManager.FEATURE_FAKETOUCH);
// Find screen size, check that it is big enough for gestures.
// Gestures will start in the center of the screen, so we need enough horiz/vert space.
WindowManager windowManager =
(WindowManager)
mInstrumentation.getContext().getSystemService(Context.WINDOW_SERVICE);
final DisplayMetrics metrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getRealMetrics(metrics);
mCenter = new Point((int) metrics.widthPixels / 2, (int) metrics.heightPixels / 2);
mTapLocation = new PointF(mCenter);
mScreenBigEnough = (metrics.widthPixels / (2 * metrics.xdpi) > GESTURE_LENGTH_INCHES);
if (!mHasTouchscreen || !mScreenBigEnough) return;
mService = mServiceRule.enableService();
mView = mActivityRule.getActivity().findViewById(R.id.full_screen_text_view);
mView.setOnHoverListener(mHoverListener);
mView.setOnTouchListener(mTouchListener);
mInstrumentation.runOnMainSync(
() -> {
mSwipeDistance = mView.getWidth() / 4;
mView.setOnClickListener(mClickListener);
mView.setOnLongClickListener(mLongClickListener);
});
}
/** Test a slow swipe which should initiate touch exploration. */
@Test
@AppModeFull
public void testSlowSwipe_initiatesTouchExploration() {
if (!mHasTouchscreen || !mScreenBigEnough) return;
dispatch(swipe(mTapLocation, add(mTapLocation, mSwipeDistance, 0), SWIPE_TIME_MILLIS));
mHoverListener.assertPropagated(ACTION_HOVER_ENTER, ACTION_HOVER_MOVE, ACTION_HOVER_EXIT);
mTouchListener.assertNonePropagated();
mService.assertPropagated(
TYPE_TOUCH_INTERACTION_START,
TYPE_TOUCH_EXPLORATION_GESTURE_START,
TYPE_TOUCH_EXPLORATION_GESTURE_END,
TYPE_TOUCH_INTERACTION_END);
}
/** Test a fast swipe which should not initiate touch exploration. */
@Test
@AppModeFull
public void testFastSwipe_doesNotInitiateTouchExploration() {
if (!mHasTouchscreen || !mScreenBigEnough) return;
dispatch(swipe(mTapLocation, add(mTapLocation, mSwipeDistance, 0)));
mHoverListener.assertNonePropagated();
mTouchListener.assertNonePropagated();
mService.assertPropagated(
TYPE_TOUCH_INTERACTION_START,
TYPE_GESTURE_DETECTION_START,
TYPE_GESTURE_DETECTION_END,
TYPE_TOUCH_INTERACTION_END);
}
/**
* Test a two finger drag. TouchExplorer would perform a drag gesture when two fingers moving in
* the same direction.
*/
@Test
@AppModeFull
public void testTwoFingerDrag_dispatchesEventsBetweenFingers() {
if (!mHasTouchscreen || !mScreenBigEnough) return;
// A two point moving that are in the same direction can perform a drag gesture by
// TouchExplorer while one point moving can not perform a drag gesture. We use two swipes
// to emulate a two finger drag gesture.
final int twoFingerOffset = (int) mSwipeDistance;
final PointF dragStart = mTapLocation;
final PointF dragEnd = add(dragStart, 0, mSwipeDistance);
final PointF finger1Start = add(dragStart, twoFingerOffset, 0);
final PointF finger1End = add(finger1Start, 0, mSwipeDistance);
final PointF finger2Start = add(dragStart, -twoFingerOffset, 0);
final PointF finger2End = add(finger2Start, 0, mSwipeDistance);
dispatch(
swipe(finger1Start, finger1End, SWIPE_TIME_MILLIS),
swipe(finger2Start, finger2End, SWIPE_TIME_MILLIS));
List<MotionEvent> twoFingerPoints = mTouchListener.getRawEvents();
// Check the drag events performed by a two finger drag. The moving locations would be
// adjusted to the middle of two fingers.
final int numEvents = twoFingerPoints.size();
final int upEventIndex = numEvents - 1;
final float stepDuration =
(float)
(twoFingerPoints.get(1).getEventTime()
- twoFingerPoints.get(0).getEventTime());
final float gestureDuration =
(float)
(twoFingerPoints.get(upEventIndex).getEventTime()
- twoFingerPoints.get(0).getEventTime());
final float intervalFraction =
stepDuration * (mSwipeDistance / gestureDuration) / gestureDuration;
PointF downPoint = add(dragStart, ceil(times(intervalFraction, diff(dragEnd, dragStart))));
assertThat(twoFingerPoints.get(0), both(IS_ACTION_DOWN).and(isRawAtPoint(downPoint, 1.0f)));
assertThat(
twoFingerPoints.get(upEventIndex),
both(IS_ACTION_UP).and(isRawAtPoint(finger2End, 1.0f)));
}
/** Test a basic single tap which should initiate touch exploration. */
@Test
@AppModeFull
public void testSingleTap_initiatesTouchExploration() {
if (!mHasTouchscreen || !mScreenBigEnough) return;
dispatch(click(mTapLocation));
mHoverListener.assertPropagated(ACTION_HOVER_ENTER, ACTION_HOVER_EXIT);
mTouchListener.assertNonePropagated();
mService.assertPropagated(
TYPE_TOUCH_INTERACTION_START,
TYPE_TOUCH_EXPLORATION_GESTURE_START,
TYPE_TOUCH_EXPLORATION_GESTURE_END,
TYPE_TOUCH_INTERACTION_END);
}
/**
* Test the case where we execute a "sloppy" double tap, meaning that the second tap isn't
* exactly in the same location as the first but still within tolerances. It should behave the
* same as a standard double tap. Note that this test does not request that double tap be
* dispatched to the accessibility service, meaning that it will be handled by the framework and
* the view will be clicked.
*/
@Test
@AppModeFull
public void testSloppyDoubleTapAccessibilityFocus_performsClick() {
if (!mHasTouchscreen || !mScreenBigEnough) return;
syncAccessibilityFocusToInputFocus();
int slop = ViewConfiguration.get(mInstrumentation.getContext()).getScaledDoubleTapSlop();
dispatch(multiTap(mTapLocation, 2, slop));
mHoverListener.assertNonePropagated();
// The click should not be delivered via touch events in this case.
mTouchListener.assertNonePropagated();
mService.assertPropagated(
TYPE_VIEW_ACCESSIBILITY_FOCUSED,
TYPE_TOUCH_INTERACTION_START,
TYPE_TOUCH_INTERACTION_END,
TYPE_VIEW_CLICKED);
mClickListener.assertClicked(mView);
}
/**
* Test the case where we want to click on the item that has accessibility focus by using
* AccessibilityNodeInfo.performAction. Note that this test does not request that double tap be
* dispatched to the accessibility service, meaning that it will be handled by the framework and
* the view will be clicked.
*/
@Test
@AppModeFull
public void testDoubleTapAccessibilityFocus_performsClick() {
if (!mHasTouchscreen || !mScreenBigEnough) return;
syncAccessibilityFocusToInputFocus();
dispatch(doubleTap(mTapLocation));
mHoverListener.assertNonePropagated();
// The click should not be delivered via touch events in this case.
mTouchListener.assertNonePropagated();
mService.assertPropagated(
TYPE_VIEW_ACCESSIBILITY_FOCUSED,
TYPE_TOUCH_INTERACTION_START,
TYPE_TOUCH_INTERACTION_END,
TYPE_VIEW_CLICKED);
mClickListener.assertClicked(mView);
}
/**
* Test the case where we double tap but there is no accessibility focus. Nothing should
* happen.
*/
@Test
@AppModeFull
public void testDoubleTapNoAccessibilityFocus_doesNotPerformClick() {
if (!mHasTouchscreen || !mScreenBigEnough) return;
dispatch(doubleTap(mTapLocation));
mHoverListener.assertNonePropagated();
mTouchListener.assertNonePropagated();
mService.assertPropagated(
TYPE_TOUCH_INTERACTION_START, TYPE_TOUCH_INTERACTION_END);
mService.clearEvents();
mClickListener.assertNoneClicked();
}
/**
* Test the case where we want to long click on the item that has accessibility focus. Note that
* this test does not request that double tap and hold be dispatched to the accessibility
* service, meaning that it will be handled by the framework and the view will be long clicked.
*/
@Test
@AppModeFull
public void testDoubleTapAndHoldAccessibilityFocus_performsLongClick() {
if (!mHasTouchscreen || !mScreenBigEnough) return;
syncAccessibilityFocusToInputFocus();
dispatch(doubleTapAndHold(mTapLocation));
mHoverListener.assertNonePropagated();
// The click should not be delivered via touch events in this case.
mTouchListener.assertNonePropagated();
mService.assertPropagated(
TYPE_VIEW_ACCESSIBILITY_FOCUSED,
TYPE_TOUCH_INTERACTION_START,
TYPE_VIEW_LONG_CLICKED,
TYPE_TOUCH_INTERACTION_END);
mLongClickListener.assertLongClicked(mView);
}
/**
* Test the case where we double tap and hold but there is no accessibility focus.
* Nothing should happen.
*/
@Test
@AppModeFull
public void testDoubleTapAndHoldNoAccessibilityFocus_doesNotPerformLongClick() {
if (!mHasTouchscreen || !mScreenBigEnough) return;
dispatch(doubleTap(mTapLocation));
mHoverListener.assertNonePropagated();
mTouchListener.assertNonePropagated();
mService.assertPropagated(TYPE_TOUCH_INTERACTION_START, TYPE_TOUCH_INTERACTION_END);
mService.clearEvents();
mLongClickListener.assertNoneLongClicked();
}
/**
* Test the case where we want to double tap using a second finger while the first finger is
* touch exploring.
*/
@Test
@AppModeFull
public void testSecondFingerDoubleTapTouchExploring_performsClick() {
if (!mHasTouchscreen || !mScreenBigEnough) return;
syncAccessibilityFocusToInputFocus();
// hold the first finger for long enough to trigger touch exploration before double-tapping.
// Touch exploration is triggered after the double tap timeout.
dispatch(
secondFingerMultiTap(
mTapLocation,
add(mTapLocation, mSwipeDistance, 0),
2,
ViewConfiguration.getDoubleTapTimeout() + 50));
mHoverListener.assertPropagated(ACTION_HOVER_ENTER, ACTION_HOVER_EXIT);
mTouchListener.assertNonePropagated();
mService.assertPropagated(
TYPE_VIEW_ACCESSIBILITY_FOCUSED,
TYPE_TOUCH_INTERACTION_START,
TYPE_TOUCH_EXPLORATION_GESTURE_START,
TYPE_TOUCH_EXPLORATION_GESTURE_END,
TYPE_TOUCH_INTERACTION_END,
TYPE_VIEW_CLICKED);
mClickListener.assertClicked(mView);
}
/**
* Test the case where we want to double tap using a second finger without triggering touch
* exploration.
*/
@Test
@AppModeFull
public void testSecondFingerDoubleTapNotTouchExploring_performsClick() {
if (!mHasTouchscreen || !mScreenBigEnough) return;
syncAccessibilityFocusToInputFocus();
// Hold the first finger for less than the double tap timeout which will not trigger touch
// exploration.
// Touch exploration is triggered after the double tap timeout.
dispatch(
secondFingerMultiTap(
mTapLocation,
add(mTapLocation, mSwipeDistance, 0),
2,
ViewConfiguration.getDoubleTapTimeout() / 3));
mHoverListener.assertNonePropagated();
mTouchListener.assertNonePropagated();
mService.assertPropagated(
TYPE_VIEW_ACCESSIBILITY_FOCUSED,
TYPE_TOUCH_INTERACTION_START,
TYPE_TOUCH_INTERACTION_END,
TYPE_VIEW_CLICKED);
mClickListener.assertClicked(mView);
}
/**
* This method tests a three-finger swipe. The gesture will be delegated to the view as-is. This
* is distinct from dragging, where two fingers are delegated to the view as one finger. Note
* that because multi-finger gestures are disabled this gesture will not be handled by the
* gesture detector.
*/
@Test
@AppModeFull
public void testThreeFingerMovement_shouldDelegate() {
if (!mHasTouchscreen || !mScreenBigEnough) return;
// Move three fingers down the screen slowly.
PointF finger1Start = add(mTapLocation, -mSwipeDistance, 0);
PointF finger1End = add(mTapLocation, -mSwipeDistance, mSwipeDistance);
PointF finger2Start = mTapLocation;
PointF finger2End = add(mTapLocation, 0, mSwipeDistance);
PointF finger3Start = add(mTapLocation, mSwipeDistance, 0);
PointF finger3End = add(mTapLocation, mSwipeDistance, mSwipeDistance);
StrokeDescription swipe1 = swipe(finger1Start, finger1End, SWIPE_TIME_MILLIS);
StrokeDescription swipe2 = swipe(finger2Start, finger2End, SWIPE_TIME_MILLIS);
StrokeDescription swipe3 = swipe(finger3Start, finger3End, SWIPE_TIME_MILLIS);
dispatch(swipe1, swipe2, swipe3);
mHoverListener.assertNonePropagated();
mTouchListener.assertPropagated(
ACTION_DOWN,
ACTION_POINTER_DOWN,
ACTION_POINTER_DOWN,
ACTION_MOVE,
ACTION_POINTER_UP,
ACTION_POINTER_UP,
ACTION_UP);
}
/**
* This method tests the case where two fingers are moving independently. The gesture will be
* delegated to the view as-is. This is distinct from dragging, where two fingers are delegated
* to the view as one finger.
*/
@Test
@AppModeFull
public void testTwoFingersMovingIndependently_shouldDelegate() {
if (!mHasTouchscreen || !mScreenBigEnough) return;
// Move two fingers towards eacher slowly.
PointF finger1Start = add(mTapLocation, -mSwipeDistance, 0);
PointF finger1End = add(mTapLocation, -10, 0);
StrokeDescription swipe1 = swipe(finger1Start, finger1End, SWIPE_TIME_MILLIS);
PointF finger2Start = add(mTapLocation, mSwipeDistance, 0);
PointF finger2End = add(mTapLocation, 10, 0);
StrokeDescription swipe2 = swipe(finger2Start, finger2End, SWIPE_TIME_MILLIS);
dispatch(swipe1, swipe2);
mHoverListener.assertNonePropagated();
mTouchListener.assertPropagated(
ACTION_DOWN, ACTION_POINTER_DOWN, ACTION_MOVE, ACTION_POINTER_UP, ACTION_UP);
}
/**
* Test the gesture detection passthrough by performing a fast swipe in the passthrough region.
* It should bypass the gesture detector entirely.
*/
@Test
@AppModeFull
public void testGestureDetectionPassthrough_initiatesTouchExploration() {
if (!mHasTouchscreen || !mScreenBigEnough) return;
setRightSideOfScreenGestureDetectionPassthrough();
// Swipe in the passthrough region. This should generate hover events.
dispatch(swipe(mTapLocation, add(mTapLocation, mSwipeDistance, 0)));
mHoverListener.assertPropagated(ACTION_HOVER_ENTER, ACTION_HOVER_MOVE, ACTION_HOVER_EXIT);
mService.assertPropagated(
TYPE_TOUCH_INTERACTION_START,
TYPE_TOUCH_EXPLORATION_GESTURE_START,
TYPE_TOUCH_EXPLORATION_GESTURE_END,
TYPE_TOUCH_INTERACTION_END);
mService.clearEvents();
// Swipe starting inside the passthrough region but ending outside of it. This should still
// behave as a passthrough interaction.
dispatch(swipe(mTapLocation, add(mTapLocation, -mSwipeDistance, 0)));
mHoverListener.assertPropagated(ACTION_HOVER_ENTER, ACTION_HOVER_MOVE, ACTION_HOVER_EXIT);
mService.assertPropagated(
TYPE_TOUCH_INTERACTION_START,
TYPE_TOUCH_EXPLORATION_GESTURE_START,
TYPE_TOUCH_EXPLORATION_GESTURE_END,
TYPE_TOUCH_INTERACTION_END);
mService.clearEvents();
// Swipe outside the passthrough region. This should not generate hover events.
dispatch(swipe(add(mTapLocation, -1, 0), add(mTapLocation, -mSwipeDistance, 0)));
mHoverListener.assertNonePropagated();
mService.assertPropagated(
TYPE_TOUCH_INTERACTION_START,
TYPE_GESTURE_DETECTION_START,
TYPE_GESTURE_DETECTION_END,
TYPE_TOUCH_INTERACTION_END);
mService.clearEvents();
// There should be no touch events in this test.
mTouchListener.assertNonePropagated();
clearPassthroughRegions();
}
/**
* Test the touch exploration passthrough by performing a fast swipe in the passthrough region.
* It should generate touch events.
*/
@Test
@AppModeFull
public void testTouchExplorationPassthrough_sendsTouchEvents() {
if (!mHasTouchscreen || !mScreenBigEnough) return;
setRightSideOfScreenTouchExplorationPassthrough();
// Swipe in the passthrough region. This should generate touch events.
dispatch(swipe(mTapLocation, add(mTapLocation, mSwipeDistance, 0)));
mTouchListener.assertPropagated(ACTION_DOWN, ACTION_MOVE, ACTION_UP);
// We still want accessibility events to tell us when the gesture starts and ends.
mService.assertPropagated(
TYPE_TOUCH_INTERACTION_START, TYPE_TOUCH_INTERACTION_END, TYPE_VIEW_CLICKED);
mService.clearEvents();
// Swipe starting inside the passthrough region but ending outside of it. This should still
// behave as a passthrough interaction.
dispatch(swipe(mTapLocation, add(mTapLocation, -mSwipeDistance, 0)));
mTouchListener.assertPropagated(ACTION_DOWN, ACTION_MOVE, ACTION_UP);
mService.assertPropagated(
TYPE_TOUCH_INTERACTION_START, TYPE_TOUCH_INTERACTION_END, TYPE_VIEW_CLICKED);
mService.clearEvents();
// Swipe outside the passthrough region. This should not generate touch events.
dispatch(swipe(add(mTapLocation, -1, 0), add(mTapLocation, -mSwipeDistance, 0)));
mTouchListener.assertNonePropagated();
mService.assertPropagated(
TYPE_TOUCH_INTERACTION_START,
TYPE_GESTURE_DETECTION_START,
TYPE_GESTURE_DETECTION_END,
TYPE_TOUCH_INTERACTION_END);
// There should be no hover events in this test.
mHoverListener.assertNonePropagated();
clearPassthroughRegions();
}
public void dispatch(StrokeDescription firstStroke, StrokeDescription... rest) {
GestureDescription.Builder builder =
new GestureDescription.Builder().addStroke(firstStroke);
for (StrokeDescription stroke : rest) {
builder.addStroke(stroke);
}
dispatch(builder.build());
}
public void dispatch(GestureDescription gesture) {
await(dispatchGesture(mService, gesture));
}
/** Set the accessibility focus to the element that has input focus. */
private void syncAccessibilityFocusToInputFocus() {
mService.runOnServiceSync(
() -> {
mUiAutomation
.getRootInActiveWindow()
.findFocus(AccessibilityNodeInfo.FOCUS_INPUT)
.performAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
});
}
private void setRightSideOfScreenGestureDetectionPassthrough() {
Region region = getRightSideOfScreenRegion();
mService.runOnServiceSync(
() -> {
mService.setGestureDetectionPassthroughRegion(Display.DEFAULT_DISPLAY, region);
});
}
private void setRightSideOfScreenTouchExplorationPassthrough() {
Region region = getRightSideOfScreenRegion();
mService.runOnServiceSync(
() -> {
mService.setTouchExplorationPassthroughRegion(Display.DEFAULT_DISPLAY, region);
});
}
private void clearPassthroughRegions() {
mService.runOnServiceSync(
() -> {
mService.setGestureDetectionPassthroughRegion(
Display.DEFAULT_DISPLAY, new Region());
mService.setTouchExplorationPassthroughRegion(
Display.DEFAULT_DISPLAY, new Region());
});
}
private Region getRightSideOfScreenRegion() {
WindowManager windowManager =
(WindowManager)
mInstrumentation.getContext().getSystemService(Context.WINDOW_SERVICE);
final DisplayMetrics metrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getRealMetrics(metrics);
int top = 0;
int left = metrics.widthPixels / 2;
int right = metrics.widthPixels;
int bottom = metrics.heightPixels;
Region region = new Region(left, top, right, bottom);
return region;
}
}