У многих пользователей Android возникают различные ситуации, которые заставляют их по-разному взаимодействовать со своими телефонами. Для тех пользователей, которые не могут использовать смартфоны Android из-за зрения, слуха или других физических причин, Android предоставляет функции и услуги специальных возможностей, которые помогают этим пользователям проще управлять устройством, включая преобразование текста в речь, тактильную обратную связь, управление жестами, трекбол. и Управление работой. Разработчики могут создавать свои собственные службы специальных возможностей, которые могут повысить удобство использования приложений, например звуковые подсказки, физическую обратную связь и другие дополнительные режимы работы.
Его конкретная реализация заключается в запуске в фоновом режиме через службу AccessibilityService и получении обратных вызовов для указанных событий через AccessibilityEvent. Такие события представляют собой некоторые переходы состояний пользователя в интерфейсе, например: изменение фокуса, нажатие кнопки и т. д. Такие службы могут дополнительно иметь возможность запрашивать содержимое активного окна. Проще говоря, AccessibilityService — это служба фонового мониторинга. Когда контент, который вы отслеживаете, изменяется, вызывается метод обратного вызова фоновой службы.
Напишите свой собственный класс службы и переопределите метод onServiceConnected(), метод onAccessibilityEvent() и метод onInterrupt().
public class QHBAccessibilityService extends AccessibilityService {
/**
* 当启动服务的时候就会被调用
*/
@ Override
protected void onServiceConnected () {
super . onServiceConnected ();
}
/**
* 监听窗口变化的回调
*/
@ Override
public void onAccessibilityEvent ( AccessibilityEvent event ) {
int eventType = event . getEventType ();
//根据事件回调类型进行处理
}
/**
* 中断服务的回调
*/
@ Override
public void onInterrupt () {
}
}
Ниже приводится введение в часто используемые методы AccessibilityService.
Поскольку это фоновая служба, нам необходимо настроить информацию о службе в манифестах.
< service
android : name = " .AccessibilityService.QHBAccessibilityService "
android : enabled = " true "
android : exported = " true "
android : label = " @string/label "
android : permission = " android.permission.BIND_ACCESSIBILITY_SERVICE " >
< intent-filter >
< action android : name = " android.accessibilityservice.AccessibilityService " />
</ intent-filter >
</ service >
Следует обратить внимание: любая ошибка в конфигурации информации приведет к тому, что сервис перестанет отвечать на запросы.
К настройке параметров службы относятся: настройка приема событий указанных типов, прослушивания указанных пакетов, получения содержимого окна, получения времени типов событий и т. д. Существует два способа настройки параметров сервиса:
Добавьте тег метаданных в исходные манифесты, чтобы указать XML-файл.
< service
android : name = " .AccessibilityService.QHBAccessibilityService "
android : enabled = " true "
android : exported = " true "
android : label = " @string/label "
android : permission = " android.permission.BIND_ACCESSIBILITY_SERVICE " >
< intent-filter >
< action android : name = " android.accessibilityservice.AccessibilityService " />
</ intent-filter >
< meta-data
android : name = " android.accessibilityservice "
android : resource = " @xml/accessibility_service_config " />
</ service >
Далее идет настройка файла accessibility_service_config.
<? xml version = " 1.0 " encoding = " utf-8 " ?>
< accessibility-service xmlns : android = " http://schemas.android.com/apk/res/android "
android : accessibilityEventTypes = " typeNotificationStateChanged|typeWindowStateChanged|typeWindowContentChanged|typeWindowsChanged "
android : accessibilityFeedbackType = " feedbackGeneric "
android : accessibilityFlags = " flagDefault "
android : canRetrieveWindowContent = " true "
android : description = " @string/description "
android : notificationTimeout = " 100 "
android : packageNames = " com.tencent.mm " />
Ниже приводится введение в параметры XML.
accessibilityEventTypes: указывает, какие изменения в интерфейсе интересуют службу, то есть о каких событиях уведомляется, например, открытие окна, скольжение, изменение фокуса, длительное нажатие и т. д. Конкретное значение можно найти в классе AccessibilityEvent. Например, typeAllMask означает принятие всех уведомлений о событиях.
accessibilityFeedbackType: указывает метод обратной связи, например воспроизведение голоса или вибрацию.
canRetrieveWindowContent: указывает, может ли служба получить доступ к содержимому активного окна. То есть, если вы хотите получить содержимое формы в сервисе, вам нужно установить для нее значение true
описание: описание функции специальных возможностей, как показано на рисунке ниже.
NotificationTimeout: интервал времени для приема событий, обычно устанавливается равным 100.
packageNames: указывает, какой пакет используется службой для отслеживания событий. В качестве примера мы возьмем имя пакета WeChat.
Настройте информацию AccessibilityServiceInfo для нашей AccessibilityService с помощью кода. Здесь мы можем извлечь ее в метод для настройки.
private void settingAccessibilityInfo () {
String [] packageNames = { "com.tencent.mm" };
AccessibilityServiceInfo mAccessibilityServiceInfo = new AccessibilityServiceInfo ();
// 响应事件的类型,这里是全部的响应事件(长按,单击,滑动等)
mAccessibilityServiceInfo . eventTypes = AccessibilityEvent . TYPES_ALL_MASK ;
// 反馈给用户的类型,这里是语音提示
mAccessibilityServiceInfo . feedbackType = AccessibilityServiceInfo . FEEDBACK_SPOKEN ;
// 过滤的包名
mAccessibilityServiceInfo . packageNames = packageNames ;
setServiceInfo ( mAccessibilityServiceInfo );
}
Здесь используется класс AccessibilityServiceInfo. Класс AccessibilityServiceInfo используется для настройки информации AccessibilityService. Этот класс содержит большое количество константных полей для атрибутов конфигурации и XML.
Здесь нам нужно вручную включить эту функцию в функции доступности, иначе мы не сможем продолжить. Открыть список функций доступности системы можно с помощью следующего кода.
Intent intent = new Intent ( Settings . ACTION_ACCESSIBILITY_SETTINGS );
startActivity ( intent );
Поскольку мы отслеживаем панель уведомлений и интерфейс события, при изменении панели уведомлений или интерфейса указанных имен пакетов наше событие будет вызвано обратно через onAccessibilityEvent, а затем событие будет обработано.
@ Override
public void onAccessibilityEvent ( AccessibilityEvent event ) {
int eventType = event . getEventType ();
//根据事件回调类型进行处理
switch ( eventType ) {
//当通知栏发生改变时
case AccessibilityEvent . TYPE_NOTIFICATION_STATE_CHANGED :
break ;
//当窗口的状态发生改变时
case AccessibilityEvent . TYPE_WINDOW_STATE_CHANGED :
break ;
}
}
Когда мы получим уведомление в WeChat, в строке состояния появится push-сообщение. В это время оно будет отслеживаться TYPE_NOTIFICATION_STATE_CHANGED, и содержимое внутри будет выполнено, когда мы переключим интерфейс WeChat или воспользуемся WeChat, на этот раз оно будет выполнено. контролироваться TYPE_WINDOW_STATE_CHANGED. Выполнить содержимое внутри.
Методы AccessibilityEvent
После получения изменений окна интерфейса необходимо в это время получить узлы управления. Узлы всего окна по существу представляют собой древовидную структуру. Информация об узлах обрабатывается следующим образом.
AccessibilityNodeInfo nodeInfo = getRootInActiveWindow ();
//通过文本找到对应的节点集合
List < AccessibilityNodeInfo > list = nodeInfo . findAccessibilityNodeInfosByText ( text );
//通过控件ID找到对应的节点集合,如com.tencent.mm:id/gd
List < AccessibilityNodeInfo > list = nodeInfo . findAccessibilityNodeInfosByViewId ( clickId );
После получения информации об узлах мы можем выполнять имитацию щелчков, длительных нажатий и других операций на узлах управления. Класс AccessibilityNodeInfo предоставляет метод PerformAction(), позволяющий выполнять моделируемые операции. Подробные операции см. в официальной документации. Здесь перечислены часто используемые операции.
//模拟点击
accessibilityNodeInfo . performAction ( AccessibilityNodeInfo . ACTION_CLICK );
//模拟长按
accessibilityNodeInfo . performAction ( AccessibilityNodeInfo . ACTION_LONG_CLICK );
//模拟获取焦点
accessibilityNodeInfo . performAction ( AccessibilityNodeInfo . ACTION_FOCUS );
//模拟粘贴
accessibilityNodeInfo . performAction ( AccessibilityNodeInfo . ACTION_PASTE );
Когда наш телефон подключен к USB-кабелю, выберите устройство в Android Device Monitor и откройте инструмент Dump View Hierarchy for UI Automator, с помощью которого мы можем получить управляющую информацию.
Вопрос:
AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
всегда сообщает нулевой указатель. Сталкивался ли блоггер с этой проблемой? Я также столкнулся с такой проблемой, как ваша. Думаю, она связана с «Параметры службы конфигурации». Я только начал настраивать ее в коде, и она также вернула значение null. Я чувствую, что не писал это android:canRetrieveWindowContent="true. ", но это не так. Я нашел настройку, соответствующую android:canRetrieveWindowContent="true", поэтому изменил ее, чтобы настроить в xml, и все было в порядке.
Вопрос: Как получить имена классов com.tencent.mm.ui.LauncherUI? A: String className = event.getClassName().toString(). Используйте журнал, чтобы распечатать его, и откройте WeChat, чтобы просмотреть информацию журнала.
Исходный текст: блог Hensen_