Un servicio de accesibilidad es una app que mejora la interfaz de usuario para brindar asistencia usuarios con discapacidades o que temporalmente no puedan interactuar completamente con un dispositivo. Por ejemplo, los usuarios que conducen, cuidan a un niño pequeño, o asistir a una fiesta muy ruidosa puede necesitar una interfaz adicional o alternativa comentarios.
Android ofrece servicios de accesibilidad estándar, como TalkBack y los desarrolladores pueden crear y distribuir sus propios servicios. Este documento se explican los conceptos básicos de la creación de un servicio de accesibilidad.
Un servicio de accesibilidad se puede incluir en un paquete con una app normal o crearse como una proyecto de Android independiente. Los pasos para crear el servicio son los mismos en en cualquier situación.
Crea tu servicio de accesibilidad
Dentro de tu proyecto, crea una clase que extienda
AccessibilityService
:
Kotlin
package com.example.android.apis.accessibility import android.accessibilityservice.AccessibilityService import android.view.accessibility.AccessibilityEvent class MyAccessibilityService : AccessibilityService() { ... override fun onInterrupt() {} override fun onAccessibilityEvent(event: AccessibilityEvent?) {} ... }
Java
package com.example.android.apis.accessibility; import android.accessibilityservice.AccessibilityService; import android.view.accessibility.AccessibilityEvent; public class MyAccessibilityService extends AccessibilityService { ... @Override public void onAccessibilityEvent(AccessibilityEvent event) { } @Override public void onInterrupt() { } ... }
Si creas un proyecto nuevo para este dispositivo Service
y no tienes pensado tener una app
asociado, puedes quitar la clase de inicio Activity
de tu
fuente.
Permisos y declaraciones de manifiesto
Las apps que brindan servicios de accesibilidad deben incluir declaraciones específicas en los manifiestos de sus apps para que Android los trate como un servicio de accesibilidad. en un sistema de archivos. En esta sección, se explica la configuración obligatoria y opcional para servicios de accesibilidad.
Declaración del servicio de accesibilidad
Para que tu app se considere un servicio de accesibilidad, incluye una service
.
en lugar del elemento activity
, dentro de application
en tu manifiesto. Además, dentro del elemento service
, incluye un
filtro de intents del servicio de accesibilidad. El manifiesto también debe proteger el servicio
si agregas
BIND_ACCESSIBILITY_SERVICE
para asegurarse de que solo el sistema pueda vincularse. Por ejemplo:
<application> <service android:name=".MyAccessibilityService" android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE" android:label="@string/accessibility_service_label"> <intent-filter> <action android:name="android.accessibilityservice.AccessibilityService" /> </intent-filter> </service> </application>
Configuración del servicio de accesibilidad
Los servicios de accesibilidad deben proporcionar una configuración que especifique los tipos de
eventos de accesibilidad que el servicio controla, así como información adicional sobre
el servicio. La configuración de un servicio de accesibilidad se incluye en la
AccessibilityServiceInfo
. Tu servicio puede crear y establecer una configuración usando una instancia de esta
clase y
setServiceInfo()
durante el tiempo de ejecución. Sin embargo, no todas las opciones de configuración están disponibles con este
.
Puedes incluir un elemento <meta-data>
en tu manifiesto con una referencia a un
de Terraform, que te permite establecer la gama completa de opciones para tu
de accesibilidad, como se muestra en el siguiente ejemplo:
<service android:name=".MyAccessibilityService"> ... <meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibility_service_config" /> </service>
Este elemento <meta-data>
hace referencia a un archivo en formato XML que creas en tu
directorio de recursos de la app:
<project_dir>/res/xml/accessibility_service_config.xml>
El siguiente código
se muestra un ejemplo del contenido del archivo de configuración de servicio:
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" android:description="@string/accessibility_service_description" android:packageNames="com.example.android.apis" android:accessibilityEventTypes="typeAllMask" android:accessibilityFlags="flagDefault" android:accessibilityFeedbackType="feedbackSpoken" android:notificationTimeout="100" android:canRetrieveWindowContent="true" android:settingsActivity="com.example.android.accessibility.ServiceSettingsActivity" />
Para obtener más información sobre los atributos XML que se pueden usar en el de servicio de accesibilidad, consulta la siguiente referencia documentación:
android:description
android:packageNames
android:accessibilityEventTypes
android:accessibilityFlags
android:accessibilityFeedbackType
android:notificationTimeout
android:canRetrieveWindowContent
android:settingsActivity
Para obtener más información sobre los parámetros de configuración que se pueden establecer de forma dinámica
durante el tiempo de ejecución, consulta la
AccessibilityServiceInfo
documentación de referencia.
Configura tu servicio de accesibilidad
Ten en cuenta lo siguiente cuando establezcas las variables de configuración de la servicio de accesibilidad para indicarle al sistema cómo y cuándo se debe ejecutar:
- ¿A qué tipos de eventos deseas que responda?
- ¿El servicio debe estar activo para todas las apps o solo para un paquete específico? nombres?
- ¿Qué tipos de comentarios usa?
Tienes dos opciones para configurar estas variables. La opción retrocompatible
es configurarlas en el código, con
setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)
Para ello, anula el
onServiceConnected()
y configura tu servicio allí, como se muestra en el siguiente ejemplo:
Kotlin
override fun onServiceConnected() { info.apply { // Set the type of events that this service wants to listen to. Others // aren't passed to this service. eventTypes = AccessibilityEvent.TYPE_VIEW_CLICKED or AccessibilityEvent.TYPE_VIEW_FOCUSED // If you only want this service to work with specific apps, set their // package names here. Otherwise, when the service is activated, it // listens to events from all apps. packageNames = arrayOf("com.example.android.myFirstApp", "com.example.android.mySecondApp") // Set the type of feedback your service provides. feedbackType = AccessibilityServiceInfo.FEEDBACK_SPOKEN // Default services are invoked only if no package-specific services are // present for the type of AccessibilityEvent generated. This service is // app-specific, so the flag isn't necessary. For a general-purpose // service, consider setting the DEFAULT flag. // flags = AccessibilityServiceInfo.DEFAULT; notificationTimeout = 100 } this.serviceInfo = info }
Java
@Override public void onServiceConnected() { // Set the type of events that this service wants to listen to. Others // aren't passed to this service. info.eventTypes = AccessibilityEvent.TYPE_VIEW_CLICKED | AccessibilityEvent.TYPE_VIEW_FOCUSED; // If you only want this service to work with specific apps, set their // package names here. Otherwise, when the service is activated, it listens // to events from all apps. info.packageNames = new String[] {"com.example.android.myFirstApp", "com.example.android.mySecondApp"}; // Set the type of feedback your service provides. info.feedbackType = AccessibilityServiceInfo.FEEDBACK_SPOKEN; // Default services are invoked only if no package-specific services are // present for the type of AccessibilityEvent generated. This service is // app-specific, so the flag isn't necessary. For a general-purpose service, // consider setting the DEFAULT flag. // info.flags = AccessibilityServiceInfo.DEFAULT; info.notificationTimeout = 100; this.setServiceInfo(info); }
La segunda opción consiste en configurar el servicio usando un archivo XML. Cierto
varias opciones de configuración, como
canRetrieveWindowContent
:
solo están disponibles si configuras tu servicio con XML. La configuración
opciones del ejemplo anterior se ven así cuando se definen con XML:
<accessibility-service android:accessibilityEventTypes="typeViewClicked|typeViewFocused" android:packageNames="com.example.android.myFirstApp, com.example.android.mySecondApp" android:accessibilityFeedbackType="feedbackSpoken" android:notificationTimeout="100" android:settingsActivity="com.example.android.apis.accessibility.TestBackActivity" android:canRetrieveWindowContent="true" />
Si usas XML, haz referencia a él en tu manifiesto agregando un
<meta-data>
etiqueta a tu
de Google Cloud que apunta al archivo en formato XML. Si almacenas tu archivo XML en
res/xml/serviceconfig.xml
, la etiqueta nueva se ve de la siguiente manera:
<service android:name=".MyAccessibilityService"> <intent-filter> <action android:name="android.accessibilityservice.AccessibilityService" /> </intent-filter> <meta-data android:name="android.accessibilityservice" android:resource="@xml/serviceconfig" /> </service>
Métodos del servicio de accesibilidad
Un servicio de accesibilidad debe extender la clase AccessibilityService
y
anular los siguientes métodos de esa clase. Estos métodos se presentan
el orden en que el sistema Android las llama: a partir del momento en que se inicia el servicio
(onServiceConnected()
) mientras se ejecuta
(onAccessibilityEvent()
,
onInterrupt()
),
cuando está apagado
(onUnbind()
).
onServiceConnected()
: (opcional): El sistema llama a este método cuando se conecte a tu servicio de accesibilidad. Usa este método para realizar una configuración única pasos para tu servicio, incluida la conexión al sistema de comentarios de los usuarios servicios, como el administrador de audio o el vibrador del dispositivo. Si quieres establecer la configuración de tu servicio en el tiempo de ejecución o hacer ajustes únicos esta ubicación es conveniente para llamar asetServiceInfo()
.onAccessibilityEvent()
(obligatorio): El sistema vuelve a llamar a este método cuando detecta unAccessibilityEvent
que coincida con los parámetros de filtrado de eventos especificados por tu accesibilidad como cuando el usuario presiona un botón o se enfoca en una interfaz de usuario en una app para la que proporciona comentarios tu servicio de accesibilidad. Cuándo el sistema llama a este método, pasa elAccessibilityEvent
asociado que el servicio puede interpretar y utilizar para proporcionar retroalimentación al usuario. Se puede llamar a este método muchas veces a lo largo del ciclo de vida de tu servicio.onInterrupt()
: (obligatorio): El sistema llama a este método cuando el sistema quiere interrumpir los comentarios que proporciona tu servicio, generalmente en respuesta a una acción del usuario, como mover el enfoque a un control diferente. Esta se puede llamar muchas veces a lo largo del ciclo de vida de tu servicio.onUnbind()
: El sistema llama a este método (opcional) cuando está en a punto de cerrar el servicio de accesibilidad. Usa este método para realizar cualquiera de las siguientes acciones: Procedimientos de cierre por única vez, incluida la anulación de la asignación del sistema de comentarios de los usuarios servicios, como el administrador de audio o el vibrador del dispositivo.
Estos métodos de devolución de llamada proporcionan la estructura básica para tu accesibilidad.
servicio. Puedes decidir cómo procesar los datos que proporciona el sistema Android en
el formato de objetos AccessibilityEvent
y proporcionar comentarios al usuario Para
más información sobre cómo obtener información de un evento de accesibilidad, consulta Obtener
los detalles del evento.
Regístrate para ver los eventos de accesibilidad
Una de las funciones más importantes de la configuración del servicio de accesibilidad de accesibilidad es que te permiten especificar los tipos de eventos de accesibilidad puede manejar. Especificar esta información permite que los servicios de accesibilidad cooperen entre sí y te da la flexibilidad de manejar solo eventos específicos tipos de apps específicas. El filtrado de eventos puede incluir lo siguiente: criterios:
Nombres de paquetes: Especifica los nombres de paquetes de las apps cuya accesibilidad. eventos que quieres que controle tu servicio. Si se omite este parámetro, tu el servicio de accesibilidad se considera disponible eventos para cualquier app. Puedes configurar este parámetro en el servicio de accesibilidad. de configuración con el atributo
android:packageNames
como un lista separada por comas o usa elAccessibilityServiceInfo.packageNames
miembro.Tipos de eventos: Especifica los tipos de eventos de accesibilidad que deseas. que manejar. Puedes configurar este parámetro en el servicio de accesibilidad. archivos de configuración con el atributo
android:accessibilityEventTypes
como una lista separada por el carácter|
, por ejemplo,accessibilityEventTypes="typeViewClicked|typeViewFocused"
También puedes configurar con elAccessibilityServiceInfo.eventTypes
miembro.
Cuando configures tu servicio de accesibilidad, considera cuidadosamente qué eventos servicio puede manejar y solo registrarse en esos eventos. Como los usuarios pueden activar más de un servicio de accesibilidad a la vez, tu servicio no debe consumir eventos que no puede manejar. Recuerda que es posible que otros servicios para mejorar la experiencia del usuario.
Volumen de accesibilidad
Los dispositivos con Android 8.0 (nivel de API 26) y versiones posteriores incluyen
STREAM_ACCESSIBILITY
de volumen, que te permite controlar el volumen de tu accesibilidad
salida de audio del servicio independientemente
de los demás sonidos del dispositivo.
Los servicios de accesibilidad pueden usar este tipo de transmisión estableciendo la
FLAG_ENABLE_ACCESSIBILITY_VOLUME
de 12 a 1 con la nueva opción de compresión. Luego, puedes cambiar el volumen del audio de accesibilidad del dispositivo llamando
el
adjustStreamVolume()
en la instancia del dispositivo
AudioManager
El siguiente fragmento de código demuestra cómo un servicio de accesibilidad puede usar la
Categoría de volumen de STREAM_ACCESSIBILITY
:
Kotlin
import android.media.AudioManager.* class MyAccessibilityService : AccessibilityService() { private val audioManager = getSystemService(AUDIO_SERVICE) as AudioManager override fun onAccessibilityEvent(accessibilityEvent: AccessibilityEvent) { if (accessibilityEvent.source.text == "Increase volume") { audioManager.adjustStreamVolume(AudioManager.STREAM_ACCESSIBILITY, ADJUST_RAISE, 0) } } }
Java
import static android.media.AudioManager.*; public class MyAccessibilityService extends AccessibilityService { private AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE); @Override public void onAccessibilityEvent(AccessibilityEvent accessibilityEvent) { AccessibilityNodeInfo interactedNodeInfo = accessibilityEvent.getSource(); if (interactedNodeInfo.getText().equals("Increase volume")) { audioManager.adjustStreamVolume(AudioManager.STREAM_ACCESSIBILITY, ADJUST_RAISE, 0); } } }
Para obtener más información, consulta el video de la sesión Novedades sobre accesibilidad de Android de Google I/O 2017 (a partir del 6:35.
Acceso directo de accesibilidad
En dispositivos con Android 8.0 (nivel de API 26) y versiones posteriores, los usuarios pueden habilitar y inhabilitar su servicio de accesibilidad preferido desde cualquier pantalla presionando y Manteniendo presionadas las teclas de volumen al mismo tiempo. Aunque este atajo habilita y inhabilita TalkBack de forma predeterminada, los usuarios pueden configurar el botón para habilitar y inhabilitar cualquier servicio que esté instalado en su dispositivo.
Para que los usuarios accedan a un servicio de accesibilidad en particular desde la sección el servicio debe solicitar la función durante el tiempo de ejecución.
Para obtener más información, consulta el video de la sesión Novedades sobre accesibilidad de Android de Google I/O 2017 (a partir del 13:25.
Botón de accesibilidad
En dispositivos que usan un área de navegación renderizada por software y ejecutan Android 8.0 (nivel de API 26) o versiones posteriores, el lado derecho de la barra de navegación incluye un botón de accesibilidad. Cuando los usuarios presionan este botón, pueden invocar uno de varias funciones y servicios de accesibilidad habilitados, según el contenido que se muestra actualmente en la pantalla.
Permitir que los usuarios invoquen un servicio de accesibilidad determinado usando las funciones
, el servicio debe agregar
FLAG_REQUEST_ACCESSIBILITY_BUTTON
marca en el android:accessibilityFlags
de un objeto AccessibilityServiceInfo
. Luego, el servicio puede registrar devoluciones de llamada mediante
registerAccessibilityButtonCallback()
En el siguiente fragmento de código, se demuestra cómo puedes configurar una accesibilidad servicio para responder cuando el usuario presione el botón de accesibilidad:
Kotlin
private var mAccessibilityButtonController: AccessibilityButtonController? = null private var accessibilityButtonCallback: AccessibilityButtonController.AccessibilityButtonCallback? = null private var mIsAccessibilityButtonAvailable: Boolean = false override fun onServiceConnected() { mAccessibilityButtonController = accessibilityButtonController mIsAccessibilityButtonAvailable = mAccessibilityButtonController?.isAccessibilityButtonAvailable ?: false if (!mIsAccessibilityButtonAvailable) return serviceInfo = serviceInfo.apply { flags = flags or AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON } accessibilityButtonCallback = object : AccessibilityButtonController.AccessibilityButtonCallback() { override fun onClicked(controller: AccessibilityButtonController) { Log.d("MY_APP_TAG", "Accessibility button pressed!") // Add custom logic for a service to react to the // accessibility button being pressed. } override fun onAvailabilityChanged( controller: AccessibilityButtonController, available: Boolean ) { if (controller == mAccessibilityButtonController) { mIsAccessibilityButtonAvailable = available } } } accessibilityButtonCallback?.also { mAccessibilityButtonController?.registerAccessibilityButtonCallback(it, null) } }
Java
private AccessibilityButtonController accessibilityButtonController; private AccessibilityButtonController .AccessibilityButtonCallback accessibilityButtonCallback; private boolean mIsAccessibilityButtonAvailable; @Override protected void onServiceConnected() { accessibilityButtonController = getAccessibilityButtonController(); mIsAccessibilityButtonAvailable = accessibilityButtonController.isAccessibilityButtonAvailable(); if (!mIsAccessibilityButtonAvailable) { return; } AccessibilityServiceInfo serviceInfo = getServiceInfo(); serviceInfo.flags |= AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON; setServiceInfo(serviceInfo); accessibilityButtonCallback = new AccessibilityButtonController.AccessibilityButtonCallback() { @Override public void onClicked(AccessibilityButtonController controller) { Log.d("MY_APP_TAG", "Accessibility button pressed!"); // Add custom logic for a service to react to the // accessibility button being pressed. } @Override public void onAvailabilityChanged( AccessibilityButtonController controller, boolean available) { if (controller.equals(accessibilityButtonController)) { mIsAccessibilityButtonAvailable = available; } } }; if (accessibilityButtonCallback != null) { accessibilityButtonController.registerAccessibilityButtonCallback( accessibilityButtonCallback, null); } }
Para obtener más información, consulta el video de la sesión Novedades sobre accesibilidad de Android de Google I/O 2017 (a partir del 4:28.
Gestos del sensor de huellas digitales
Servicios de accesibilidad en dispositivos con Android 8.0 (nivel de API 26) o versiones posteriores responde a deslizamientos direccionales (hacia arriba, abajo, izquierda y derecha) en la pantalla sensor de huellas dactilares. Para configurar un servicio de modo que reciba devoluciones de llamada sobre estas interacciones, completa la siguiente secuencia:
- Declara el
USE_BIOMETRIC
. permiso y elCAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES
de recuperación ante desastres. - Establece el elemento
FLAG_REQUEST_FINGERPRINT_GESTURES
. en el atributoandroid:accessibilityFlags
. - Regístrate para recibir devoluciones de llamada con
registerFingerprintGestureCallback()
.
Ten en cuenta que no todos los dispositivos tienen sensores de huellas digitales. Para identificar
si un dispositivo es compatible con el sensor, usa el
isHardwareDetected()
. Incluso en un dispositivo con sensor de huellas dactilares, tu servicio no puede
usar el sensor cuando esté en uso con fines de autenticación. Para identificar cuándo
de que el sensor esté disponible, llama al
isGestureDetectionAvailable()
método e implementaremos
onGestureDetectionAvailabilityChanged()
devolución de llamada.
En el siguiente fragmento de código, se muestra un ejemplo de cómo usar los gestos del sensor de huellas digitales para navegar por un tablero de juegos virtual.
// AndroidManifest.xml <manifest ... > <uses-permission android:name="android.permission.USE_FINGERPRINT" /> ... <application> <service android:name="com.example.MyFingerprintGestureService" ... > <meta-data android:name="android.accessibilityservice" android:resource="@xml/myfingerprintgestureservice" /> </service> </application> </manifest>
// myfingerprintgestureservice.xml <accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" ... android:accessibilityFlags=" ... |flagRequestFingerprintGestures" android:canRequestFingerprintGestures="true" ... />
Kotlin
// MyFingerprintGestureService.kt import android.accessibilityservice.FingerprintGestureController.* class MyFingerprintGestureService : AccessibilityService() { private var gestureController: FingerprintGestureController? = null private var fingerprintGestureCallback: FingerprintGestureController.FingerprintGestureCallback? = null private var mIsGestureDetectionAvailable: Boolean = false override fun onCreate() { gestureController = fingerprintGestureController mIsGestureDetectionAvailable = gestureController?.isGestureDetectionAvailable ?: false } override fun onServiceConnected() { if (mFingerprintGestureCallback != null || !mIsGestureDetectionAvailable) return fingerprintGestureCallback = object : FingerprintGestureController.FingerprintGestureCallback() { override fun onGestureDetected(gesture: Int) { when (gesture) { FINGERPRINT_GESTURE_SWIPE_DOWN -> moveGameCursorDown() FINGERPRINT_GESTURE_SWIPE_LEFT -> moveGameCursorLeft() FINGERPRINT_GESTURE_SWIPE_RIGHT -> moveGameCursorRight() FINGERPRINT_GESTURE_SWIPE_UP -> moveGameCursorUp() else -> Log.e(MY_APP_TAG, "Error: Unknown gesture type detected!") } } override fun onGestureDetectionAvailabilityChanged(available: Boolean) { mIsGestureDetectionAvailable = available } } fingerprintGestureCallback?.also { gestureController?.registerFingerprintGestureCallback(it, null) } } }
Java
// MyFingerprintGestureService.java import static android.accessibilityservice.FingerprintGestureController.*; public class MyFingerprintGestureService extends AccessibilityService { private FingerprintGestureController gestureController; private FingerprintGestureController .FingerprintGestureCallback fingerprintGestureCallback; private boolean mIsGestureDetectionAvailable; @Override public void onCreate() { gestureController = getFingerprintGestureController(); mIsGestureDetectionAvailable = gestureController.isGestureDetectionAvailable(); } @Override protected void onServiceConnected() { if (fingerprintGestureCallback != null || !mIsGestureDetectionAvailable) { return; } fingerprintGestureCallback = new FingerprintGestureController.FingerprintGestureCallback() { @Override public void onGestureDetected(int gesture) { switch (gesture) { case FINGERPRINT_GESTURE_SWIPE_DOWN: moveGameCursorDown(); break; case FINGERPRINT_GESTURE_SWIPE_LEFT: moveGameCursorLeft(); break; case FINGERPRINT_GESTURE_SWIPE_RIGHT: moveGameCursorRight(); break; case FINGERPRINT_GESTURE_SWIPE_UP: moveGameCursorUp(); break; default: Log.e(MY_APP_TAG, "Error: Unknown gesture type detected!"); break; } } @Override public void onGestureDetectionAvailabilityChanged(boolean available) { mIsGestureDetectionAvailable = available; } }; if (fingerprintGestureCallback != null) { gestureController.registerFingerprintGestureCallback( fingerprintGestureCallback, null); } } }
Para obtener más información, consulta el video de la sesión Novedades sobre accesibilidad de Android de Google I/O 2017 (a partir del 9:03.
Texto a voz multilingüe
A partir de Android 8.0 (nivel de API 26), el servicio de texto a voz (TTS) de Android
puede identificar y decir frases en varios idiomas dentro de un solo bloque de
texto. Para habilitar esta función de cambio automático de idioma en un entorno
servicio, une todas las cadenas de
Objetos LocaleSpan
, como se muestra
en el siguiente fragmento de código:
Kotlin
val localeWrappedTextView = findViewById<TextView>(R.id.my_french_greeting_text).apply { text = wrapTextInLocaleSpan("Bonjour!", Locale.FRANCE) } private fun wrapTextInLocaleSpan(originalText: CharSequence, loc: Locale): SpannableStringBuilder { return SpannableStringBuilder(originalText).apply { setSpan(LocaleSpan(loc), 0, originalText.length - 1, 0) } }
Java
TextView localeWrappedTextView = findViewById(R.id.my_french_greeting_text); localeWrappedTextView.setText(wrapTextInLocaleSpan("Bonjour!", Locale.FRANCE)); private SpannableStringBuilder wrapTextInLocaleSpan( CharSequence originalText, Locale loc) { SpannableStringBuilder myLocaleBuilder = new SpannableStringBuilder(originalText); myLocaleBuilder.setSpan(new LocaleSpan(loc), 0, originalText.length() - 1, 0); return myLocaleBuilder; }
Para obtener más información, consulta el video de la sesión Novedades sobre accesibilidad de Android de Google I/O 2017 (a partir del 10:59.
Actuar en nombre de los usuarios
A partir de 2011, los servicios de accesibilidad pueden actuar en nombre de los usuarios, lo que incluye cambiar el enfoque de entrada y seleccionar (activar) elementos de la interfaz de usuario En 2012, se amplió el rango de acciones para incluir el desplazamiento por listas y la interacción con campos de texto. Los servicios de accesibilidad también pueden realizar acciones globales, como navegando a la pantalla de inicio, presionando el botón Atrás y abriendo la pantalla de notificaciones y la lista de apps recientes. Desde 2012, Android incluye enfoque de accesibilidad, que hace que todos los elementos visibles puedan seleccionarse con una de accesibilidad.
Estas capacidades permiten que los desarrolladores de servicios de accesibilidad creen soluciones modos de navegación, como la navegación por gestos, y brindan a los usuarios con discapacidades mejor control de sus dispositivos con Android.
Detecta gestos
Los servicios de accesibilidad pueden escuchar gestos específicos y responder realizando acciones
nombre de un usuario. Esta función requiere que tu solicitud de servicio de accesibilidad
activación de la función Exploración táctil. Tu servicio puede solicitarlo
activación estableciendo la
flags
miembro de la instancia AccessibilityServiceInfo
del servicio para
FLAG_REQUEST_TOUCH_EXPLORATION_MODE
,
como se muestra en el siguiente ejemplo.
Kotlin
class MyAccessibilityService : AccessibilityService() { override fun onCreate() { serviceInfo.flags = AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE } ... }
Java
public class MyAccessibilityService extends AccessibilityService { @Override public void onCreate() { getServiceInfo().flags = AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE; } ... }
Después de que tu servicio solicita la activación de Exploración táctil, el usuario debe permitir
Activar la función, si aún no está activa. Cuando esta función es
activo, tu servicio recibe la notificación de los gestos de accesibilidad mediante
la de tu servicio
onGesture()
de devolución de llamada y puede responder actuando en nombre del usuario.
Gestos continuos
Los dispositivos con Android 8.0 (nivel de API 26) admiten gestos continuos, o
gestos programáticos que contienen más de un
objeto Path
.
Al especificar una secuencia de trazos, puedes indicar que pertenecen al
mismo gesto programático con el argumento final willContinue
en el
GestureDescription.StrokeDescription
, como se muestra en el siguiente fragmento de código:
Kotlin
// Simulates an L-shaped drag path: 200 pixels right, then 200 pixels down. private fun doRightThenDownDrag() { val dragRightPath = Path().apply { moveTo(200f, 200f) lineTo(400f, 200f) } val dragRightDuration = 500L // 0.5 second // The starting point of the second path must match // the ending point of the first path. val dragDownPath = Path().apply { moveTo(400f, 200f) lineTo(400f, 400f) } val dragDownDuration = 500L val rightThenDownDrag = GestureDescription.StrokeDescription( dragRightPath, 0L, dragRightDuration, true ).apply { continueStroke(dragDownPath, dragRightDuration, dragDownDuration, false) } }
Java
// Simulates an L-shaped drag path: 200 pixels right, then 200 pixels down. private void doRightThenDownDrag() { Path dragRightPath = new Path(); dragRightPath.moveTo(200, 200); dragRightPath.lineTo(400, 200); long dragRightDuration = 500L; // 0.5 second // The starting point of the second path must match // the ending point of the first path. Path dragDownPath = new Path(); dragDownPath.moveTo(400, 200); dragDownPath.lineTo(400, 400); long dragDownDuration = 500L; GestureDescription.StrokeDescription rightThenDownDrag = new GestureDescription.StrokeDescription(dragRightPath, 0L, dragRightDuration, true); rightThenDownDrag.continueStroke(dragDownPath, dragRightDuration, dragDownDuration, false); }
Para obtener más información, consulta el video de la sesión Novedades sobre accesibilidad de Android de Google I/O 2017 (a partir del 15:47.
Usa acciones de accesibilidad
Los servicios de accesibilidad pueden actuar en nombre de los usuarios para simplificar las interacciones con y aumentar tu productividad. La capacidad de los servicios de accesibilidad para realizar acciones se agregó en 2011 y se expandió considerablemente en 2012.
Para actuar en nombre de los usuarios, tu servicio de accesibilidad debe registrarse.
recibir eventos de las apps y solicitar permiso para ver el contenido
de las apps estableciendo android:canRetrieveWindowContent
en true
archivo de configuración del servicio. Cuando reciba los eventos el
en el servicio, puede recuperar la
AccessibilityNodeInfo
objeto del evento con
getSource()
Con el objeto AccessibilityNodeInfo
, tu servicio puede explorar la vista
jerarquía para determinar qué acción tomar y luego actuar por el usuario utilizando
performAction()
Kotlin
class MyAccessibilityService : AccessibilityService() { override fun onAccessibilityEvent(event: AccessibilityEvent) { // Get the source node of the event. event.source?.apply { // Use the event and node information to determine what action to // take. // Act on behalf of the user. performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD) // Recycle the nodeInfo object. recycle() } } ... }
Java
public class MyAccessibilityService extends AccessibilityService { @Override public void onAccessibilityEvent(AccessibilityEvent event) { // Get the source node of the event. AccessibilityNodeInfo nodeInfo = event.getSource(); // Use the event and node information to determine what action to take. // Act on behalf of the user. nodeInfo.performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); // Recycle the nodeInfo object. nodeInfo.recycle(); } ... }
El método performAction()
permite que tu servicio realice acciones en un
. Si tu servicio necesita realizar una acción global, como
navegar a la pantalla principal, presionar el botón Atrás o abrir
en la pantalla de notificaciones o la lista de apps recientes,
performGlobalAction()
.
Usa tipos de enfoque
En 2012, Android introdujo un enfoque de interfaz de usuario llamado foco de accesibilidad. Los servicios de accesibilidad pueden usar este enfoque para seleccionar cualquier interfaz de usuario visible elemento y actuar en consecuencia. Este tipo de enfoque es diferente del enfoque de entrada, que Determina qué elemento de la interfaz de usuario en pantalla recibe la entrada cuando un usuario escribe caracteres, presiona Intro en un teclado o empuja el centro de un pad direccional.
Es posible que un elemento en una interfaz de usuario tenga foco de entrada mientras otro elemento tiene el enfoque de accesibilidad. El objetivo del enfoque de accesibilidad es servicios de accesibilidad con un método de interacción con datos visibles, elementos en una pantalla, independientemente de si el elemento se puede enfocar en la entrada desde desde una perspectiva del sistema. Para ayudar a garantizar que tu servicio de accesibilidad interactúe correctamente con las funciones elementos de entrada, sigue las pautas para probar la experiencia accesibilidad para probar el servicio mientras usan una aplicación típica.
Un servicio de accesibilidad puede determinar qué elemento de la interfaz de usuario tiene entrada
o de accesibilidad con el
AccessibilityNodeInfo.findFocus()
. También puedes buscar elementos que se pueden seleccionar con el enfoque de entrada
con el
focusSearch()
. Por último, tu servicio de accesibilidad puede establecer el enfoque de accesibilidad usando
el
performAction(AccessibilityNodeInfo.ACTION_SET_ACCESSIBILITY_FOCUS)
.
Recopila información
Los servicios de accesibilidad tienen métodos estándar para recopilar y representar unidades de información proporcionada por el usuario, como detalles de eventos, texto y números.
Obtén información sobre el cambio de ventanas
Android 9 (nivel de API 28) y las versiones posteriores permiten que las apps hagan un seguimiento de las actualizaciones de ventanas cuando
una app vuelve a dibujar varias ventanas al mismo tiempo Cuando un elemento
TYPE_WINDOWS_CHANGED
de un evento, usa el
getWindowChanges()
para determinar cómo cambian las ventanas. Durante una actualización multiventana, cada
la ventana produce su propio conjunto de eventos. El método getSource()
muestra el valor
de la ventana asociada con cada evento.
Si una app define el panel de accesibilidad
títulos para su
View
, tu servicio puede reconocer cuando
cuando se actualice la IU de la app. Cuando un elemento
TYPE_WINDOW_STATE_CHANGED
cuando ocurre un evento, usa los tipos
getContentChangeTypes()
para determinar cómo cambia la ventana. Por ejemplo, el framework puede detectar cuándo
un panel tiene un título nuevo o cuando desaparece un panel.
Obtén detalles del evento
Android proporciona información sobre la interfaz de usuario a los servicios de accesibilidad
interacción a través de objetos AccessibilityEvent
. En versiones anteriores de Android,
la información disponible en un evento de accesibilidad, a la vez que proporciona
detalles sobre el control de la interfaz de usuario que seleccionan los usuarios, ofrecidos limitados
información contextual. En muchos casos, la información contextual faltante
es fundamental para comprender el significado del control seleccionado.
Un ejemplo de una interfaz donde el contexto es fundamental es un calendario o un día planificador. Si el usuario selecciona un horario disponible de 4:00 p.m. en una lista diaria de lunes a viernes. y el servicio de accesibilidad anuncia "4:00 p.m.", pero no anuncia el día de la semana nombre, el día del mes o el nombre del mes, el feedback será confusas. En este caso, el contexto de un control de interfaz de usuario es fundamental para un usuario que desea programar una reunión.
Desde 2011, Android amplía significativamente la cantidad de información que un servicio de accesibilidad puede obtener sobre una interacción de la interfaz de usuario redactando de accesibilidad en función de la jerarquía de vistas. Una jerarquía de vistas es el conjunto de componentes de la interfaz de usuario que contienen el componente (sus elementos superiores) y el nombre elementos de la interfaz que podría contener ese componente (sus elementos secundarios). En de esta manera, Android puede brindar más detalles sobre los eventos de accesibilidad, lo que permite servicios de accesibilidad proporcionan comentarios más útiles a los usuarios.
Un servicio de accesibilidad obtiene información sobre un evento de la interfaz de usuario a través de
un AccessibilityEvent
que pasa el sistema al
Método de devolución de llamada onAccessibilityEvent()
. Este objeto proporciona detalles sobre la
evento, incluido el tipo de objeto sobre el que se realiza la acción, su texto descriptivo y
otros detalles.
AccessibilityEvent.getRecordCount()
ygetRecord(int)
: estos métodos te permiten recuperar el conjunto deAccessibilityRecord
objetos que contribuyen alAccessibilityEvent
que te pasa el en un sistema de archivos. Este nivel de detalle proporciona más contexto sobre el evento que activa tu servicio de accesibilidad.AccessibilityRecord.getSource()
: este método muestra un objetoAccessibilityNodeInfo
. Este objeto te permite solicitar la jerarquía de diseño de las vistas (elementos superiores y secundarios) del componente que origina el evento de accesibilidad. Esta función permite que un equipo de investigar el contexto completo de un evento, incluidos el contenido y estado de cualquier vista contenedora o secundaria.
La plataforma de Android permite que un AccessibilityService
realice consultas
la jerarquía de vistas, recopilando información sobre el componente de la IU que genera
un evento, así como su elemento superior y sus elementos secundarios. Para hacer esto, configura la siguiente línea
en tu configuración XML:
android:canRetrieveWindowContent="true"
Cuando termines, obtén un objeto AccessibilityNodeInfo
mediante getSource()
.
Esta llamada solo devuelve un objeto si la ventana donde se origina el evento es
la ventana activa. De lo contrario, muestra un valor nulo, por lo que debes comportarte según corresponda.
En el siguiente ejemplo, el código hace lo siguiente cuando se recibe un evento:
- Captura inmediatamente el elemento superior de la vista donde se origina el evento.
- En esa vista, busca una etiqueta y una casilla de verificación como vistas secundarias.
- Si los encuentra, crea una cadena para informar al usuario que indica etiqueta y si se marcó.
Si en algún momento se devuelve un valor nulo mientras recorres la jerarquía de vistas, el método se abandona en silencio.
Kotlin
// Alternative onAccessibilityEvent that uses AccessibilityNodeInfo. override fun onAccessibilityEvent(event: AccessibilityEvent) { val source: AccessibilityNodeInfo = event.source ?: return // Grab the parent of the view that fires the event. val rowNode: AccessibilityNodeInfo = getListItemNodeInfo(source) ?: return // Using this parent, get references to both child nodes, the label, and the // checkbox. val taskLabel: CharSequence = rowNode.getChild(0)?.text ?: run { rowNode.recycle() return } val isComplete: Boolean = rowNode.getChild(1)?.isChecked ?: run { rowNode.recycle() return } // Determine what the task is and whether it's complete based on the text // inside the label, and the state of the checkbox. if (rowNode.childCount < 2 || !rowNode.getChild(1).isCheckable) { rowNode.recycle() return } val completeStr: String = if (isComplete) { getString(R.string.checked) } else { getString(R.string.not_checked) } val reportStr = "$taskLabel$completeStr" speakToUser(reportStr) }
Java
// Alternative onAccessibilityEvent that uses AccessibilityNodeInfo. @Override public void onAccessibilityEvent(AccessibilityEvent event) { AccessibilityNodeInfo source = event.getSource(); if (source == null) { return; } // Grab the parent of the view that fires the event. AccessibilityNodeInfo rowNode = getListItemNodeInfo(source); if (rowNode == null) { return; } // Using this parent, get references to both child nodes, the label, and the // checkbox. AccessibilityNodeInfo labelNode = rowNode.getChild(0); if (labelNode == null) { rowNode.recycle(); return; } AccessibilityNodeInfo completeNode = rowNode.getChild(1); if (completeNode == null) { rowNode.recycle(); return; } // Determine what the task is and whether it's complete based on the text // inside the label, and the state of the checkbox. if (rowNode.getChildCount() < 2 || !rowNode.getChild(1).isCheckable()) { rowNode.recycle(); return; } CharSequence taskLabel = labelNode.getText(); final boolean isComplete = completeNode.isChecked(); String completeStr = null; if (isComplete) { completeStr = getString(R.string.checked); } else { completeStr = getString(R.string.not_checked); } String reportStr = taskLabel + completeStr; speakToUser(reportStr); }
Ahora tienes un servicio de accesibilidad completo y en funcionamiento. Intentar configurar cómo
este interactúa con el usuario agregando el texto a voz de Android
motor
o usar un objeto Vibrator
para proporcionar una respuesta táctil
comentarios.
Procesa texto
Los dispositivos con Android 8.0 (API nivel 26) y versiones posteriores incluyen varias funciones de procesamiento de texto que permiten que los servicios de accesibilidad identifiquen y operen con mayor facilidad en unidades de texto específicas que aparecen en la pantalla.
Información sobre la herramienta
Android 9 (nivel de API 28) presenta varias capacidades que te permiten acceder a
información sobre la herramienta en la IU de una app. Usa
getTooltipText()
para leer el texto de un cuadro de información y usar el
ACTION_SHOW_TOOLTIP
y
ACTION_HIDE_TOOLTIP
para indicar a las instancias de View
que muestren u oculten su información sobre la herramienta.
Texto de la sugerencia
A partir de 2017, Android incluye varios métodos para interactuar con un Texto de la sugerencia del objeto basado en texto:
- El
isShowingHintText()
ysetShowingHintText()
indican y establecen, respectivamente, si el texto actual del nodo content representa el texto de la sugerencia del nodo. getHintText()
y proporciona acceso al propio texto de la sugerencia. Incluso si un objeto no se muestra texto de la sugerencia, la llamada agetHintText()
se realiza correctamente.
Ubicaciones de los caracteres de texto en la pantalla
En dispositivos con Android 8.0 (nivel de API 26) y versiones posteriores, los servicios de accesibilidad
puede determinar las coordenadas de la pantalla para el cuadro delimitador de cada carácter visible.
dentro de un widget TextView
. Servicios
llamar a estas coordenadas
refreshWithExtraData()
:
pasando
EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY
como primer argumento y un objeto Bundle
como segundo argumento. A medida que se ejecuta el método, el sistema completa
El argumento Bundle
con un array parcelable de
Objetos Rect
. Cada objeto Rect
que representa el cuadro delimitador de un carácter determinado.
Valores de rango unilaterales estandarizados
Algunos objetos AccessibilityNodeInfo
usan una instancia de
AccessibilityNodeInfo.RangeInfo
para indicar que un elemento de la IU puede adoptar un rango de valores. Al crear un
rango con
RangeInfo.obtain()
:
o cuando se recuperan los valores extremos del rango usando
getMin()
y
getMax()
,
ten en cuenta que los dispositivos con Android 8.0 (nivel de API 26) y versiones posteriores representan
rangos unilaterales de forma estandarizada:
- Para los rangos sin mínimo,
Float.NEGATIVE_INFINITY
representa el valor mínimo. - Para los rangos sin máximo,
Float.POSITIVE_INFINITY
representa el valor máximo.
Responde a los eventos de accesibilidad
Ahora que tu servicio está configurado para ejecutarse y escuchar eventos, escribe el código
sabe qué hacer cuando llega un AccessibilityEvent
. Para comenzar, anula el
onAccessibilityEvent(AccessibilityEvent)
. En ese método, usa
getEventType()
para determinar el tipo de evento y
getContentDescription()
para extraer cualquier texto de etiqueta asociado con la vista que activa el evento:
Kotlin
override fun onAccessibilityEvent(event: AccessibilityEvent) { var eventText: String = when (event.eventType) { AccessibilityEvent.TYPE_VIEW_CLICKED -> "Clicked: " AccessibilityEvent.TYPE_VIEW_FOCUSED -> "Focused: " else -> "" } eventText += event.contentDescription // Do something nifty with this text, like speak the composed string back to // the user. speakToUser(eventText) ... }
Java
@Override public void onAccessibilityEvent(AccessibilityEvent event) { final int eventType = event.getEventType(); String eventText = null; switch(eventType) { case AccessibilityEvent.TYPE_VIEW_CLICKED: eventText = "Clicked: "; break; case AccessibilityEvent.TYPE_VIEW_FOCUSED: eventText = "Focused: "; break; } eventText = eventText + event.getContentDescription(); // Do something nifty with this text, like speak the composed string back to // the user. speakToUser(eventText); ... }
Recursos adicionales
Para obtener más información, consulta los siguientes recursos: