只能在AndroidTest里运行
UiDevice myDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
try {
myDevice.findObject(new UiSelector().text("element text to be found")).pinchIn(50, 10); //to zoom in
myDevice.findObject(new UiSelector().text("element text to be found")).pinchOut(50, 20); //to zoom out
} catch (UiObjectNotFoundException e) {
e.printStackTrace();
}
接下来,走到pinchIn里:
//UiObject.class
public boolean pinchIn(int percent, int steps) throws UiObjectNotFoundException {
percent = percent < 0 ? 0 : (percent > 100 ? 100 : percent);
float percentage = (float)percent / 100.0F;
AccessibilityNodeInfo node = this.findAccessibilityNodeInfo(this.mConfig.getWaitForSelectorTimeout());
if (node == null) {
throw new UiObjectNotFoundException(this.mUiSelector.toString());
} else {
Rect rect = this.getVisibleBounds(node);
if (rect.width() <= 40) {
throw new IllegalStateException("Object width is too small for operation");
} else {
Point startPoint1 = new Point(rect.centerX() - (int)((float)(rect.width() / 2) * percentage), rect.centerY());
Point startPoint2 = new Point(rect.centerX() + (int)((float)(rect.width() / 2) * percentage), rect.centerY());
Point endPoint1 = new Point(rect.centerX() - 20, rect.centerY());
Point endPoint2 = new Point(rect.centerX() + 20, rect.centerY());
return this.performTwoPointerGesture(startPoint1, startPoint2, endPoint1, endPoint2, steps);
}
}
}
public boolean performTwoPointerGesture(Point startPoint1, Point startPoint2, Point endPoint1, Point endPoint2, int steps) {
if (steps == 0) {
steps = 1;
}
float stepX1 = (float)((endPoint1.x - startPoint1.x) / steps);
float stepY1 = (float)((endPoint1.y - startPoint1.y) / steps);
float stepX2 = (float)((endPoint2.x - startPoint2.x) / steps);
float stepY2 = (float)((endPoint2.y - startPoint2.y) / steps);
int eventX1 = startPoint1.x;
int eventY1 = startPoint1.y;
int eventX2 = startPoint2.x;
int eventY2 = startPoint2.y;
PointerCoords[] points1 = new PointerCoords[steps + 2];
PointerCoords[] points2 = new PointerCoords[steps + 2];
PointerCoords p2;
for(int i = 0; i < steps + 1; ++i) {
p2 = new PointerCoords();
p2.x = (float)eventX1;
p2.y = (float)eventY1;
p2.pressure = 1.0F;
p2.size = 1.0F;
points1[i] = p2;
PointerCoords p2 = new PointerCoords();
p2.x = (float)eventX2;
p2.y = (float)eventY2;
p2.pressure = 1.0F;
p2.size = 1.0F;
points2[i] = p2;
eventX1 = (int)((float)eventX1 + stepX1);
eventY1 = (int)((float)eventY1 + stepY1);
eventX2 = (int)((float)eventX2 + stepX2);
eventY2 = (int)((float)eventY2 + stepY2);
}
PointerCoords p1 = new PointerCoords();
p1.x = (float)endPoint1.x;
p1.y = (float)endPoint1.y;
p1.pressure = 1.0F;
p1.size = 1.0F;
points1[steps + 1] = p1;
p2 = new PointerCoords();
p2.x = (float)endPoint2.x;
p2.y = (float)endPoint2.y;
p2.pressure = 1.0F;
p2.size = 1.0F;
points2[steps + 1] = p2;
return this.performMultiPointerGesture(points1, points2);
}
public boolean performMultiPointerGesture(PointerCoords[]... touches) {
return this.getInteractionController().performMultiPointerGesture(touches);
}
//InteractionController.class
public boolean performMultiPointerGesture(PointerCoords[]... touches) {
boolean ret = true;
if (touches.length < 2) {
throw new IllegalArgumentException("Must provide coordinates for at least 2 pointers");
} else {
int maxSteps = 0;
for(int x = 0; x < touches.length; ++x) {
maxSteps = maxSteps < touches[x].length ? touches[x].length : maxSteps;
}
PointerProperties[] properties = new PointerProperties[touches.length];
PointerCoords[] pointerCoords = new PointerCoords[touches.length];
for(int x = 0; x < touches.length; ++x) {
PointerProperties prop = new PointerProperties();
prop.id = x;
prop.toolType = Configurator.getInstance().getToolType();
properties[x] = prop;
pointerCoords[x] = touches[x][0];
}
long downTime = SystemClock.uptimeMillis();
MotionEvent event = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(), 0, 1, properties, pointerCoords, 0, 0, 1.0F, 1.0F, 0, 0, 4098, 0);
ret &= this.injectEventSync(event);
int x;
for(x = 1; x < touches.length; ++x) {
event = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(), this.getPointerAction(5, x), x + 1, properties, pointerCoords, 0, 0, 1.0F, 1.0F, 0, 0, 4098, 0);
ret &= this.injectEventSync(event);
}
for(x = 1; x < maxSteps - 1; ++x) {
for(int x = 0; x < touches.length; ++x) {
if (touches[x].length > x) {
pointerCoords[x] = touches[x][x];
} else {
pointerCoords[x] = touches[x][touches[x].length - 1];
}
}
event = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(), 2, touches.length, properties, pointerCoords, 0, 0, 1.0F, 1.0F, 0, 0, 4098, 0);
ret &= this.injectEventSync(event);
SystemClock.sleep(5L);
}
for(x = 0; x < touches.length; ++x) {
pointerCoords[x] = touches[x][touches[x].length - 1];
}
for(x = 1; x < touches.length; ++x) {
event = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(), this.getPointerAction(6, x), x + 1, properties, pointerCoords, 0, 0, 1.0F, 1.0F, 0, 0, 4098, 0);
ret &= this.injectEventSync(event);
}
Log.i(LOG_TAG, "x " + pointerCoords[0].x);
event = MotionEvent.obtain(downTime, SystemClock.uptimeMillis(), 1, 1, properties, pointerCoords, 0, 0, 1.0F, 1.0F, 0, 0, 4098, 0);
ret &= this.injectEventSync(event);
return ret;
}
}
private boolean injectEventSync(InputEvent event) {
return this.getUiAutomation().injectInputEvent(event, true);
}
看起来,getUiAutomation()的injectInputEvent,也可以使用 ‘android.hardware.input.InputManager’的injectInputEvent去做,接受的参数也是InputEvent类型。
pinchOut:
public boolean pinchOut(int percent, int steps) throws UiObjectNotFoundException {
percent = percent < 0 ? 1 : (percent > 100 ? 100 : percent);
float percentage = (float)percent / 100.0F;
AccessibilityNodeInfo node = this.findAccessibilityNodeInfo(this.mConfig.getWaitForSelectorTimeout());
if (node == null) {
throw new UiObjectNotFoundException(this.mUiSelector.toString());
} else {
Rect rect = this.getVisibleBounds(node);
if (rect.width() <= 40) {
throw new IllegalStateException("Object width is too small for operation");
} else {
Point startPoint1 = new Point(rect.centerX() - 20, rect.centerY());
Point startPoint2 = new Point(rect.centerX() + 20, rect.centerY());
Point endPoint1 = new Point(rect.centerX() - (int)((float)(rect.width() / 2) * percentage), rect.centerY());
Point endPoint2 = new Point(rect.centerX() + (int)((float)(rect.width() / 2) * percentage), rect.centerY());
return this.performTwoPointerGesture(startPoint1, startPoint2, endPoint1, endPoint2, steps);
}
}
}
直接在Activity里用UIAutomator的UIDevice里,报RuntimeException:
Process: com.example.myapplication, PID: 14409
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.myapplication/com.example.myapplication.MainActivity}: java.lang.IllegalStateException: UiDevice singleton not initialized
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3895)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4074)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:91)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:149)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:103)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2473)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:219)
at android.app.ActivityThread.main(ActivityThread.java:8347)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1055)
Caused by: java.lang.IllegalStateException: UiDevice singleton not initialized
at androidx.test.uiautomator.UiDevice.getInstance(UiDevice.java:249)
at com.example.myapplication.MainActivity.onCreate(MainActivity.java:17)
at android.app.Activity.performCreate(Activity.java:8085)
at android.app.Activity.performCreate(Activity.java:8073)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1320)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3868)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4074)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:91)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:149)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:103)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2473)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:219)
at android.app.ActivityThread.main(ActivityThread.java:8347)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1055)