SoloPi安卓自动化测试工具源码研究二:截获用户输入
2019-12-19 本文已影响0人
黑山老雕
截断用户点击事件
截断用户点击事件的代码在AccessbilityServiceImpl.java.
- 它注册了一个自定义的Accessibility服务。通过用setServiceInfo,设置info的flag为FLAG_REQUEST_TOUCH_EXPLORATION_MODE来实现对于用户输入事件的截获。
示例代码;
package com.zzp.floating;
import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
public class InterceptService extends AccessibilityService {
private static final String TAG = "ZZP_Intercept";
private static InterceptService instance = null;
public static InterceptService getInstance(){
return instance;
}
@Override
protected void onServiceConnected() {
Log.d(TAG, "onServiceConnected: ");
instance = this;
super.onServiceConnected();
}
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
Log.d(TAG, "onAccessibilityEvent: Got event " + event.toString());
}
@Override
public void onInterrupt() {
}
public void setBlock() {
AccessibilityServiceInfo info = getServiceInfo();
if (info == null) {
Log.e(TAG, "ServiceInfo为空");
return;
}
info.flags = AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS |
AccessibilityServiceInfo.FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY |
AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS |
AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS |
AccessibilityServiceInfo.DEFAULT |
AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE;
Log.d(TAG, "辅助功能进入触摸监控模式");
setServiceInfo(info);
}
public void setNormal() {
AccessibilityServiceInfo info = getServiceInfo();
if (info == null) {
Log.e(TAG, "ServiceInfo为空");
return;
}
info.flags = AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS |
AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS |
AccessibilityServiceInfo.FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY |
AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS |
AccessibilityServiceInfo.DEFAULT;
Log.d(TAG, "辅助功能进入正常模式");
setServiceInfo(info);
}
}
注意,这个服务的 onServiceConnected 函数会被系统自动的绑定上。并不需要我们自己去bind 这个service。这是因为我们对这个服务声明特定的intent-filter和permission。
- 在manifest中声明一个service,注意提供特定的intent filter, permission 和 meta data。 manifest sample:
<service android:name=".InterceptService"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<!-- android:name必须是以下这个名字 -->
<action android:name="android.accessibilityservice.AccessibilityService"></action>
</intent-filter>
<meta-data
android:name="android.accessibilityservice"
android:resource="@xml/accessibility" />
</service>
meta data sample:
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeAllMask"
android:accessibilityFeedbackType="feedbackAllMask"
android:notificationTimeout="100"
android:canRetrieveWindowContent="true"
android:canRequestFilterKeyEvents="true"
android:description="@string/accessibility_description"
android:accessibilityFlags="flagDefault|flagIncludeNotImportantViews|flagReportViewIds|flagRequestEnhancedWebAccessibility|flagRetrieveInteractiveWindows"
android:canRequestTouchExplorationMode="true"
android:canRequestEnhancedWebAccessibility="true">
</accessibility-service>
参考:https://developer.android.com/guide/topics/ui/accessibility/service
-
基本上,安装app后,需要重启,这个服务才会被注册。切记切记。你可以在onServiceConnected处断点。当服务被bind的时候,断点会命中。
-
在服务中找到无障碍,英文的话找accessibility,启用无障碍权限。当你但确定的时候,服务就会被bind,onSerivceConnected会被调用。
调用无障碍权限的settings页面
在Serivce代码中,可以用
Intent intent1 = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //如果是在Serivce中启动,这行是重点
startActivity(intent1);
启用acessibility service
有些设备上的accessibility service可能被禁用了。查看方法 adb shell dumpsys accessibility。 输出结果类似:
User state[attributes:{id=0, currentUser=true, accessibilityEnabled=false, touchExplorationEnabled=false, displayMagnificationEnabled=false}
services:{}]
正常的话应该看起来像:
DUMP OF SERVICE accessibility:
ACCESSIBILITY MANAGER (dumpsys accessibility)
User state[attributes:{id=0, currentUser=true, touchExplorationEnabled=false, displayMagnificationEnabled=false, navBarMagnificationEnabled=false, autoclickEnabled=false}
services:{Service[label=com.zzp.floating.Interce…, feedbackType[FEEDBACK_SPOKEN, FEEDBACK_HAPTIC, FEEDBACK_AUDIBLE, FEEDBACK_VISUAL, FEEDBACK_GENERIC, FEEDBACK_BRAILLE], capabilities=11, eventTypes=TYPES_ALL_MASK, notificationTimeout=100]}]
Window[AccessibilityWindowInfo[title=null, id=116, type=<UNKNOWN>, layer=0, bounds=Rect(0, 0 - 1080, 2160), focused=true, active=true, pictureInPicture=false, hasParent=false, isAnchored=false, hasChildren=false]]--------- 0.047s was the duration of dumpsys accessibility, ending at: 2019-12-18 16:23:15
那么手动启动的方法:
adb shell settings put secure enabled_accessibility_services packagname/servicename
还有人提到还需要做下述, 不过可能没有必要:
adb shell settings put secure accessibility_enabled 1
不过貌似最好还是在Settings页面里面激活
转载请注明出处。
image更多视频教程请在网易云课堂搜索黑山老雕。