1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.accessibilityservice.cts.utils; 18 19 import android.accessibility.cts.common.InstrumentedAccessibilityService; 20 import android.accessibilityservice.AccessibilityService.GestureResultCallback; 21 import android.accessibilityservice.GestureDescription; 22 import android.accessibilityservice.GestureDescription.StrokeDescription; 23 import android.graphics.Path; 24 import android.graphics.PointF; 25 import android.view.ViewConfiguration; 26 27 import java.util.concurrent.CompletableFuture; 28 29 public class GestureUtils { 30 GestureUtils()31 private GestureUtils() {} 32 dispatchGesture( InstrumentedAccessibilityService service, GestureDescription gesture)33 public static CompletableFuture<Void> dispatchGesture( 34 InstrumentedAccessibilityService service, 35 GestureDescription gesture) { 36 CompletableFuture<Void> result = new CompletableFuture<>(); 37 GestureResultCallback callback = new GestureResultCallback() { 38 @Override 39 public void onCompleted(GestureDescription gestureDescription) { 40 result.complete(null); 41 } 42 43 @Override 44 public void onCancelled(GestureDescription gestureDescription) { 45 result.cancel(false); 46 } 47 }; 48 service.runOnServiceSync(() -> { 49 if (!service.dispatchGesture(gesture, callback, null)) { 50 result.completeExceptionally(new IllegalStateException()); 51 } 52 }); 53 return result; 54 } 55 pointerDown(PointF point)56 public static StrokeDescription pointerDown(PointF point) { 57 return new StrokeDescription(path(point), 0, ViewConfiguration.getTapTimeout(), true); 58 } 59 pointerUp(StrokeDescription lastStroke)60 public static StrokeDescription pointerUp(StrokeDescription lastStroke) { 61 return lastStroke.continueStroke(path(lastPointOf(lastStroke)), 62 endTimeOf(lastStroke), ViewConfiguration.getTapTimeout(), false); 63 } 64 lastPointOf(StrokeDescription stroke)65 public static PointF lastPointOf(StrokeDescription stroke) { 66 float[] p = stroke.getPath().approximate(0.3f); 67 return new PointF(p[p.length - 2], p[p.length - 1]); 68 } 69 click(PointF point)70 public static StrokeDescription click(PointF point) { 71 return new StrokeDescription(path(point), 0, ViewConfiguration.getTapTimeout()); 72 } 73 longClick(PointF point)74 public static StrokeDescription longClick(PointF point) { 75 return new StrokeDescription(path(point), 0, 76 ViewConfiguration.getLongPressTimeout() * 3 / 2); 77 } 78 swipe(PointF from, PointF to)79 public static StrokeDescription swipe(PointF from, PointF to) { 80 return swipe(from, to, ViewConfiguration.getTapTimeout()); 81 } 82 swipe(PointF from, PointF to, long duration)83 public static StrokeDescription swipe(PointF from, PointF to, long duration) { 84 return new StrokeDescription(path(from, to), 0, duration); 85 } 86 drag(StrokeDescription from, PointF to)87 public static StrokeDescription drag(StrokeDescription from, PointF to) { 88 return from.continueStroke( 89 path(lastPointOf(from), to), 90 endTimeOf(from), ViewConfiguration.getTapTimeout(), true); 91 } 92 path(PointF first, PointF... rest)93 public static Path path(PointF first, PointF... rest) { 94 Path path = new Path(); 95 path.moveTo(first.x, first.y); 96 for (PointF point : rest) { 97 path.lineTo(point.x, point.y); 98 } 99 return path; 100 } 101 startingAt(long timeMs, StrokeDescription prototype)102 public static StrokeDescription startingAt(long timeMs, StrokeDescription prototype) { 103 return new StrokeDescription( 104 prototype.getPath(), timeMs, prototype.getDuration(), prototype.willContinue()); 105 } 106 endTimeOf(StrokeDescription stroke)107 public static long endTimeOf(StrokeDescription stroke) { 108 return stroke.getStartTime() + stroke.getDuration(); 109 } 110 distance(PointF a, PointF b)111 public static float distance(PointF a, PointF b) { 112 if (a == null) throw new NullPointerException(); 113 if (b == null) throw new NullPointerException(); 114 return (float) Math.hypot(a.x - b.x, a.y - b.y); 115 } 116 add(PointF a, float x, float y)117 public static PointF add(PointF a, float x, float y) { 118 return new PointF(a.x + x, a.y + y); 119 } 120 add(PointF a, PointF b)121 public static PointF add(PointF a, PointF b) { 122 return add(a, b.x, b.y); 123 } 124 diff(PointF a, PointF b)125 public static PointF diff(PointF a, PointF b) { 126 return add(a, -b.x, -b.y); 127 } 128 negate(PointF p)129 public static PointF negate(PointF p) { 130 return times(-1, p); 131 } 132 times(float mult, PointF p)133 public static PointF times(float mult, PointF p) { 134 return new PointF(p.x * mult, p.y * mult); 135 } 136 length(PointF p)137 public static float length(PointF p) { 138 return (float) Math.hypot(p.x, p.y); 139 } 140 ceil(PointF p)141 public static PointF ceil(PointF p) { 142 return new PointF((float) Math.ceil(p.x), (float) Math.ceil(p.y)); 143 } 144 } 145