下面列出了怎么用android.app.UiAutomation的API类实例代码及写法,或者点击链接到github查看源代码。
/** Returns a list containing the root {@link AccessibilityNodeInfo}s for each active window */
@TargetApi(VERSION_CODES.LOLLIPOP)
public static Set<AccessibilityNodeInfo> getWindowRoots() {
Set<AccessibilityNodeInfo> roots = new HashSet();
// Start with the active window, which seems to sometimes be missing from the list returned
// by the UiAutomation.
UiAutomation uiAutomation = getUiAutomation();
AccessibilityNodeInfo activeRoot = uiAutomation.getRootInActiveWindow();
if (activeRoot != null) {
roots.add(activeRoot);
}
// Support multi-window searches for API level 21 and up.
for (AccessibilityWindowInfo window : uiAutomation.getWindows()) {
AccessibilityNodeInfo root = window.getRoot();
Log.i(TAG, String.format("Getting Layer: %d", window.getLayer()));
if (root == null) {
Log.w(TAG, String.format("Skipping null root node for window: %s", window.toString()));
continue;
}
roots.add(root);
}
return roots;
}
public void initialize(ShellUiAutomatorBridge uiAutomatorBridge) {
mUiAutomationBridge = uiAutomatorBridge;
// 监听activity变化,用于getAct
try {
IActivityManager am = ActivityManagerNative.getDefault();
am.setActivityController(new DummyActivityController());
} catch (RemoteException e) {
}
UiAutomation uiAutomation = uiAutomatorBridge.getUiAutomation();
uiAutomation
.setOnAccessibilityEventListener(new OnAccessibilityEventListener() {
public void onAccessibilityEvent(AccessibilityEvent event) {
synchronized (onAccessibilityEventListeners) {
for (OnAccessibilityEventListener listener : onAccessibilityEventListeners) {
listener.onAccessibilityEvent(event);
}
}
}
});
}
static void connectUiautomation() {
try {
// 配置空闲等待时间
Configurator.getInstance().setWaitForIdleTimeout(0);
// 配置空闲等待间隔
Configurator.getInstance().setWaitForSelectorTimeout(0);
// 连接uiautomation服务
UiAutomationShellWrapper automationWrapper = new UiAutomationShellWrapper();
automationWrapper.connect();
UiAutomation uiAutomation = automationWrapper.getUiAutomation();
// 初始化UiDevice
UiDevice.getInstance().initialize(
new ShellUiAutomatorBridge(uiAutomation));
deviceInfo.canConnectUiautomation = true;
} catch (Throwable e) {
}
}
/**
* Elevates permission as require for proper wifi controls.
*
* Starting in Android Q (29), additional restrictions are added for wifi operation. See
* below Android Q privacy changes for additional details.
* https://developer.android.com/preview/privacy/camera-connectivity
*
* @throws Throwable if failed to cleanup connection with UiAutomation
*/
private void adaptShellPermissionIfRequired() throws Throwable {
if (mContext.getApplicationContext().getApplicationInfo().targetSdkVersion >= 29
&& Build.VERSION.SDK_INT >= 29) {
Log.d("Elevating permission require to enable support for wifi operation in Android Q+");
UiAutomation uia = InstrumentationRegistry.getInstrumentation().getUiAutomation();
uia.adoptShellPermissionIdentity();
try {
Class<?> cls = Class.forName("android.app.UiAutomation");
Method destroyMethod = cls.getDeclaredMethod("destroy");
destroyMethod.invoke(uia);
} catch (NoSuchMethodException
| IllegalAccessException
| ClassNotFoundException
| InvocationTargetException e) {
throw new WifiManagerSnippetException("Failed to cleaup Ui Automation", e);
}
}
}
private void setAccessibilityServiceState() {
String disableSuppressAccessibilityService = InstrumentationRegistry.getArguments().getString("DISABLE_SUPPRESS_ACCESSIBILITY_SERVICES");
if (disableSuppressAccessibilityService == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
return;
}
boolean shouldDisableSuppressAccessibilityService = Boolean.parseBoolean(disableSuppressAccessibilityService);
if (shouldDisableSuppressAccessibilityService) {
Configurator.getInstance().setUiAutomationFlags(
UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
} else {
// We can disable UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES
// only when we set the value as zero
Configurator.getInstance().setUiAutomationFlags(0);
}
}
/** Private constructor. Clients should use {@link UiDevice#getInstance(Instrumentation)}. */
private UiDevice(Instrumentation instrumentation) {
mInstrumentation = instrumentation;
UiAutomation uiAutomation = instrumentation.getUiAutomation();
mUiAutomationBridge = new InstrumentationUiAutomatorBridge(
instrumentation.getContext(), uiAutomation);
// Enable multi-window support for API level 21 and up
if (UiDevice.API_LEVEL_ACTUAL >= Build.VERSION_CODES.LOLLIPOP) {
// Subscribe to window information
AccessibilityServiceInfo info = uiAutomation.getServiceInfo();
info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS;
uiAutomation.setServiceInfo(info);
}
}
/**
* Check if the device is in its natural orientation. This is determined by checking if the
* orientation is at 0 or 180 degrees.
* @return true if it is in natural orientation
* @since API Level 17
*/
public boolean isNaturalOrientation() {
Tracer.trace();
waitForIdle();
int ret = getAutomatorBridge().getRotation();
return ret == UiAutomation.ROTATION_FREEZE_0 ||
ret == UiAutomation.ROTATION_FREEZE_180;
}
public static void request(String... permissions) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
UiAutomation auto = InstrumentationRegistry.getInstrumentation().getUiAutomation();
String cmd = "pm grant " + InstrumentationRegistry.getTargetContext().getPackageName() + " %1$s";
String cmdTest = "pm grant " + InstrumentationRegistry.getContext().getPackageName() + " %1$s";
String currCmd;
for (String perm : permissions) {
execute(String.format(cmd, perm), auto);
execute(String.format(cmdTest, perm), auto);
}
}
//GrantPermissionRule.grant(permissions);
}
public UiAutomatorBridge(UiAutomation uiAutomation) {
mUiAutomation = uiAutomation;
mInteractionController = new InteractionController(this);
mQueryController = new QueryController(this);
// 打开web增强
setWebMode(false);
// 关闭高速模式
setFastMode(true);
}
public void connect() throws Exception {
if (mHandlerThread.isAlive()) {
throw new Exception("Already connected!");
}
mHandlerThread.start();
mUiAutomation = new UiAutomation(mHandlerThread.getLooper(),
new UiAutomationConnection());
mUiAutomation.connect();
}
public int getDisplayUnRotationWidth() {
int rotation = getDisplayRotation();
if (rotation == UiAutomation.ROTATION_FREEZE_0
|| rotation == UiAutomation.ROTATION_FREEZE_180) {
return getDisplayWidth();
} else {
return getDisplayHeight();
}
}
public int getDisplayUnRotationHeight() {
int rotation = getDisplayRotation();
if (rotation == UiAutomation.ROTATION_FREEZE_0
|| rotation == UiAutomation.ROTATION_FREEZE_180) {
return getDisplayHeight();
} else {
return getDisplayWidth();
}
}
/**
* Check if the device is in its natural orientation. This is determined by
* checking if the orientation is at 0 or 180 degrees.
*
* @return true if it is in natural orientation
* @since API Level 17
*/
public boolean isNaturalOrientation() {
Tracer.trace();
waitForIdle();
int ret = getAutomatorBridge().getRotation();
return ret == UiAutomation.ROTATION_FREEZE_0
|| ret == UiAutomation.ROTATION_FREEZE_180;
}
public String waitToast(final String pkg, final long timeout) {
final StringBuffer result = new StringBuffer();
final Runnable emptyRunnable = new Runnable() {
@Override
public void run() {
}
};
final UiAutomation.AccessibilityEventFilter checkWindowUpdate = (UiAutomation.AccessibilityEventFilter) new UiAutomation.AccessibilityEventFilter() {
public boolean accept(final AccessibilityEvent event) {
if (event.getEventType() == 64) {
final String sourcePackageName = (String) event
.getPackageName();
if (sourcePackageName.equals(pkg)) {
final Parcelable parcelable = event.getParcelableData();
if (!(parcelable instanceof Notification)) {
final String toastMsg = (String) event.getText()
.get(0);
if (toastMsg != null) {
result.append(toastMsg);
}
return true;
}
}
}
return false;
}
};
try {
this.getAutomatorBridge()
.executeCommandAndWaitForAccessibilityEvent(emptyRunnable,
checkWindowUpdate, timeout);
} catch (TimeoutException ex) {
} catch (Exception ex2) {
}
return result.toString();
}
@Override
public Statement apply(Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
uiAutomation.executeShellCommand("settings put global window_animation_scale 0");
uiAutomation.executeShellCommand("settings put global transition_animation_scale 0");
uiAutomation.executeShellCommand("settings put global animator_duration_scale 0");
base.evaluate();
}
};
}
private void grantAllPermissions() {
Context context = InstrumentationRegistry.getTargetContext();
try {
PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_PERMISSIONS);
UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
for (int i = 0; i < packageInfo.requestedPermissions.length; ++i) {
if ((packageInfo.requestedPermissionsFlags[i] & PackageInfo.REQUESTED_PERMISSION_GRANTED) == 0) {
grantReal(uiAutomation, packageInfo.requestedPermissions[i]);
}
}
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, "packageInfo not found for: " + context.getPackageName());
}
}
private static void grantReal(UiAutomation automation, String permission) {
try {
String targetPackageName = InstrumentationRegistry.getTargetContext().getPackageName();
ParcelFileDescriptor pfn = automation.executeShellCommand("pm grant " + targetPackageName + " " + permission);
pfn.close();
} catch (IOException e) {
Log.w(TAG, e);
}
}
@Override
public void run() {
while (!stopLooping) {
AccessibilityEvent accessibilityEvent = null;
//return true if the AccessibilityEvent type is NOTIFICATION type
UiAutomation.AccessibilityEventFilter eventFilter = new UiAutomation.AccessibilityEventFilter() {
@Override
public boolean accept(AccessibilityEvent event) {
return event.getEventType() == AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED;
}
};
Runnable runnable = new Runnable() {
@Override
public void run() {
// Not performing any event.
}
};
try {
//wait for AccessibilityEvent filter
accessibilityEvent = Device.getInstance().getUiAutomation()
.executeAndWaitForEvent(runnable /*executable event*/, eventFilter /* event to filter*/, 500 /*time out in ms*/);
} catch (Exception ignore) {}
if (accessibilityEvent != null) {
toastMessages.addAll(accessibilityEvent.getText());
}
}
}
UiAutomatorBridge(UiAutomation uiAutomation) {
mUiAutomation = uiAutomation;
mInteractionController = new InteractionController(this);
mQueryController = new QueryController(this);
}
public InstrumentationUiAutomatorBridge(Context context, UiAutomation uiAutomation) {
super(uiAutomation);
mContext = context;
}
private void initListener() {
Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
mInstrumentation.getUiAutomation().setOnAccessibilityEventListener(
new UiAutomation.OnAccessibilityEventListener() {
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
try {
final int eventType = event.getEventType();
//处理权限框
if (eventType == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED && permissionsWindowHandler) {
//package 符合
final String packageName = event.getPackageName().toString();
if (!Pattern.matches(packages, packageName)) {
return;
}
//部分机型无法获取全部的Texts,故下面部分进行注释
// String btnText = null;
// final List<CharSequence> texts = event.getText();
// for (CharSequence text : texts) {
// if (Pattern.matches(allowButton, text)) {
// btnText = text.toString();
// break;
// }
// }
//
// //btnText 符合
// if (btnText == null) {
// return;
// }
//
// //文本日志
// LogUtils.getInstance().info("permissions window: package " + packageName
// + ",text " + texts);
BySelector permissionsSelector = By.pkg(packageName).text(Pattern.compile(allowButton));
UiObject2 obj = uiDevice.findObjectOnce(permissionsSelector);
if (obj!= null) {
//截图日志
LogUtils.getInstance().infoScreenshot(new RectCanvasHandler(obj.getVisibleBounds()));
obj.click();
}
} else if (eventType == AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED) {
//判断是否是通知事件
Parcelable parcelable = event.getParcelableData();
//如果不是下拉通知栏消息,则为其它通知信息,包括Toast
if (!(parcelable instanceof Notification)) {
List <CharSequence> messageList = event.getText();
for (CharSequence toast_Message : messageList) {
if (!TextUtils.isEmpty(toast_Message)) {
for (IGlobalEventChecker toastChecker : toastCheckerSet) {
toastChecker.check(toast_Message.toString());
}
return;
}
}
}
}
} catch (Exception ex) {
LogUtils.getInstance().error(ex);
}
}
}
);
}
@Override
public UiAutomation getUiAutomation() {
return mBase.getUiAutomation();
}
@Override
public UiAutomation getUiAutomation(int flags) {
return mBase.getUiAutomation(flags);
}
private static void execute(String currCmd, UiAutomation auto){
Log.d(TAG, "exec cmd: " + currCmd);
auto.executeShellCommand(currCmd);
}
private static UiAutomation getUiAutomation() {
if (uiAutomation == null) {
uiAutomation = getInstrumentation().getUiAutomation();
}
return uiAutomation;
}
public static void touchDown(UiAutomation uiAutomation, int x, int y) {
long eventTimeInMs = SystemClock.uptimeMillis();
MotionEvent event = getMotionEvent(eventTimeInMs, eventTimeInMs, MotionEvent.ACTION_DOWN, x, y);
uiAutomation.injectInputEvent(event, true);
}
public static void touchMove(UiAutomation uiAutomation, int x, int y) {
long eventTimeInMs = SystemClock.uptimeMillis();
MotionEvent event = getMotionEvent(eventTimeInMs, eventTimeInMs, MotionEvent.ACTION_MOVE, x, y);
uiAutomation.injectInputEvent(event, true);
}
public static void touchUp(UiAutomation uiAutomation, int x, int y) {
long eventTimeInMs = SystemClock.uptimeMillis();
MotionEvent event = getMotionEvent(eventTimeInMs, eventTimeInMs, MotionEvent.ACTION_UP, x, y);
uiAutomation.injectInputEvent(event, true);
}
public UiAutomation getUiAutomation() {
return mUiAutomation;
}
public UiAutomation getUiAutomation() {
return mUiAutomation;
}