Muchos usuarios de Android tienen diversas situaciones que los llevan a interactuar con sus teléfonos de diferentes maneras. Para aquellos usuarios que no pueden usar teléfonos inteligentes Android debido a problemas de visión, audición u otras razones físicas, Android proporciona funciones y servicios de accesibilidad para ayudar a estos usuarios a operar el dispositivo de manera más simple, incluida la conversión de texto a voz, retroalimentación táctil, operación por gestos y trackball. y Manejar la operación. Los desarrolladores pueden crear sus propios servicios de accesibilidad, que pueden mejorar la usabilidad de las aplicaciones, como indicaciones sonoras, retroalimentación física y otros modos operativos opcionales.
Su implementación específica es ejecutarse en segundo plano a través del servicio AccessibilityService y recibir devoluciones de llamada para eventos específicos a través de AccessibilityEvent. Dichos eventos representan algunas transiciones de estado realizadas por el usuario en la interfaz, como: cambio de enfoque, se hizo clic en un botón, etc. Opcionalmente, dichos servicios pueden tener la capacidad de solicitar el contenido de la ventana activa. En pocas palabras, AccessibilityService es un servicio de monitoreo en segundo plano. Cuando el contenido que monitorea cambia, se llamará al método de devolución de llamada del servicio en segundo plano.
Escriba su propia clase de Servicio y anule el método onServiceConnected(), el método onAccessibilityEvent() y el método 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 () {
}
}
La siguiente es una introducción a los métodos comúnmente utilizados en AccessibilityService.
Dado que es un servicio en segundo plano, necesitamos configurar la información del servicio en manifiestos.
< 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 >
Debemos prestar atención: cualquier error en la configuración de la información hará que el servicio deje de responder
Configurar los parámetros del servicio se refiere a: configurar para aceptar eventos de tipos específicos, escuchar paquetes específicos, recuperar el contenido de la ventana, obtener la hora de los tipos de eventos, etc. Hay dos formas de configurar los parámetros del servicio:
Agregue la etiqueta de metadatos a los manifiestos originales para especificar el archivo 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 >
Lo siguiente es la configuración del archivo access_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 " />
La siguiente es una introducción a los parámetros xml.
accesibilidadEventTypes: Indica qué cambios en la interfaz le interesan al servicio, es decir, qué eventos se notifican, como apertura de ventana, deslizamiento, cambio de enfoque, pulsación larga, etc. El valor específico se puede encontrar en la clase AccessibilityEvent. Por ejemplo, typeAllMask significa aceptar todas las notificaciones de eventos.
accesibilidadFeedbackType: indica el método de retroalimentación, como reproducción de voz o vibración
canRetrieveWindowContent: indica si el servicio puede acceder al contenido de la ventana activa. Es decir, si desea obtener el contenido del formulario en el servicio, debe establecer su valor en verdadero.
descripción: una descripción de la característica de accesibilidad, como se muestra en la siguiente figura
NotificationTimeout: el intervalo de tiempo para aceptar eventos, generalmente establecido en 100
packageNames: indica qué paquete se utiliza el servicio para monitorear eventos. Aquí tomamos el nombre del paquete de WeChat como ejemplo.
Configure la información de AccessibilityServiceInfo para nuestro AccessibilityService a través del código. Aquí podemos extraerla en un método de configuración.
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 );
}
La clase AccessibilityServiceInfo está involucrada aquí. La clase AccessibilityServiceInfo se utiliza para configurar la información de AccessibilityService. Esta clase contiene una gran cantidad de campos constantes para la configuración y atributos xml. Los más comunes incluyen: accesibilidadEventTypes, canRequestFilterKeyEvents, packageNames, etc.
Aquí debemos activar manualmente esta función en la función de accesibilidad; de lo contrario, no podemos continuar. Puede abrir la lista de funciones de accesibilidad del sistema a través del siguiente código.
Intent intent = new Intent ( Settings . ACTION_ACCESSIBILITY_SETTINGS );
startActivity ( intent );
Dado que monitoreamos la barra de notificaciones y la interfaz del evento, cuando la barra de notificaciones o la interfaz de los nombres de paquete especificados cambian, nuestro evento será llamado nuevamente a través de onAccessibilityEvent y luego se procesará el evento.
@ 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 ;
}
}
Cuando recibimos una notificación en WeChat, llegará un mensaje push a la barra de estado. En este momento, será monitoreado por TYPE_NOTIFICATION_STATE_CHANGED y el contenido interno se ejecutará cuando cambiemos la interfaz de WeChat o usemos WeChat. ser monitoreado por TYPE_WINDOW_STATE_CHANGED Ejecute el contenido dentro.
Métodos AccessibilityEvent
Después de obtener los cambios en la ventana de la interfaz, es necesario obtener los nodos de control en este momento. Los nodos de toda la ventana son esencialmente una estructura de árbol. La información del nodo se opera a través de lo siguiente.
AccessibilityNodeInfo nodeInfo = getRootInActiveWindow ();
//通过文本找到对应的节点集合
List < AccessibilityNodeInfo > list = nodeInfo . findAccessibilityNodeInfosByText ( text );
//通过控件ID找到对应的节点集合,如com.tencent.mm:id/gd
List < AccessibilityNodeInfo > list = nodeInfo . findAccessibilityNodeInfosByViewId ( clickId );
Después de obtener la información del nodo, podemos realizar clics simulados, presiones prolongadas y otras operaciones en los nodos de control. La clase AccessibilityNodeInfo proporciona el método performAction() para permitirnos realizar operaciones simuladas. Para operaciones específicas, consulte la documentación oficial. Las operaciones más utilizadas se enumeran aquí.
//模拟点击
accessibilityNodeInfo . performAction ( AccessibilityNodeInfo . ACTION_CLICK );
//模拟长按
accessibilityNodeInfo . performAction ( AccessibilityNodeInfo . ACTION_LONG_CLICK );
//模拟获取焦点
accessibilityNodeInfo . performAction ( AccessibilityNodeInfo . ACTION_FOCUS );
//模拟粘贴
accessibilityNodeInfo . performAction ( AccessibilityNodeInfo . ACTION_PASTE );
Cuando nuestro teléfono esté conectado al cable USB, seleccione el dispositivo en Android Device Monitor y abra la herramienta Dump View Hierarchy for UI Automator, a través de la cual podemos obtener información de control.
P:
AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
siempre informa un puntero nulo. ¿El blogger ha encontrado este problema? También encontré un problema como el suyo. Creo que está en los "Parámetros del servicio de configuración". Acabo de comenzar a configurarlo en el código y también devolvió nulo. Siento que no escribí esto android:canRetrieveWindowContent="true. ", pero no fue así. Encontré la configuración correspondiente a android:canRetrieveWindowContent="true", así que la cambié para configurarla en xml y estuvo bien.
P: ¿Cómo se obtienen estos nombres de clase com.tencent.mm.ui.LauncherUI? R: String className = event.getClassName().toString(); Utilice Log para imprimirlo y abra WeChat para ver la información del registro.
Texto original: blog de Hensen_