lunes, 19 de febrero de 2018

Apps nativas de Android accesibles

Código ImageView. Una alerta indica que no tiene contentDescription

En este artículo explico cómo hacer una app nativa de Android accesible, con ejemplos de código, y cómo aplicar los requisitos de la EN 301 549.

A partir del 23 de junio de 2021 las apps deberán ser accesibles.

Hasta que se apruebe el Real Decreto que traspone este año la Directiva (UE) 2016/2102 a la legislación española, solo podemos asegurar que al menos deberán ser accesibles las apps del sector público.

Existen diferentes tipos de aplicaciones móviles (web, híbrida, híbrida mixta, nativa). En otros artículos del blog he tratado la accesibilidad móvil desde diversos puntos de vista, pero en este caso abordo solo la accesibilidad en las apps nativas de Android.

El artículo se organiza en tres partes:

  • Parte 1. Principales requisitos y buenas prácticas para mejorar sustancialmente la accesibilidad de las apps nativas de Android, con ejemplos de código.
  • Parte 2. Aplicación de la norma EN 301 549 a las apps nativas de Android. En la primera parte no enumero todos los requisitos obligatorios que debe cumplir una app para ser accesible de acuerdo a la próxima obligación legal. Eso lo hago en esta segunda parte.
  • Parte 3. Revisión y herramientas.

Índice

Parte 1. Principales requisitos y buenas prácticas de accesibilidad para las apps nativas de Android

El objetivo de esta primera parte es repasar los requisitos de accesibilidad más importantes que deberían cumplir las apps nativas de Android, puesto que suponen los problemas más graves y habituales en las aplicaciones.

1.1 Conocer las características de accesibilidad de Android

El primer requisito para poder hacer apps accesibles es:

  • Conocer cómo usan las personas con discapacidad los dispositivos móviles y los problemas que suelen encontrarse.
  • Conocer las funciones de accesibilidad de Android, probarlas y familiarizarse con ellas, puesto que deberás:
    • asegurarte de que tu app es compatible con ellas y que no interfiere en su uso;
    • testear tu app con las diversas funciones y servicios de accesibilidad activos (TalkBack, texto grande, etc.).

1.1.1 Necesidades de las personas con discapacidad

  • Las personas ciegas necesitan que la información que se presenta en pantalla se convierta a voz y/o Braille, siendo esta segunda opción imprescindible para las personas sordociegas.
  • Las personas con baja visión necesitan ampliar la pantalla e incrementar el contraste.
  • Las personas daltónicas necesitan medios alternativos para distinguir la información que se transmite solo por el color.
  • Los usuarios sordos necesitan alternativas al audio, en algunos casos textuales (subtítulos, mensajes de texto para alertas sonoras), pero que en otros casos pueden ser alternativas hápticas, como una vibración.
  • Los usuarios sordos cuya lengua materna es la lengua de signos preferirían recibir la información en lengua de signos y comunicarse con ella, y no mediante texto.
  • Las personas con problemas de audición necesitan que el audio sea claro, poder aumentar el volumen y silenciar los ruidos extraños.
  • Muchas personas con discapacidad motriz no pueden usar un teclado o una pantalla táctil, ellos necesitan usar la entrada de voz o dispositivos de entrada especializados, como un pulsador (single switch).
  • Las personas con dislexia necesitarán un diseño claro y agradecerán una opción de salida de texto a voz.
  • Las personas con limitaciones en el habla no podrán utilizar aplicaciones que requieran la entrada de voz.
  • Las personas con discapacidad cognitiva necesitarán textos e instrucciones claras, simples y consistentes.
  • Los usuarios con epilepsia se verán afectados por los contenidos que destellan y necesitarán poder deshabilitarlos.
  • Las personas extranjeras cuya lengua no sea la de nuestra aplicación, así como las personas con menor experiencia en el uso de aplicaciones móviles, como pueden ser las personas mayores, también se beneficiarán de estas soluciones.
  • Hay muchas personas que por culpa de un accidente o de una enfermedad, o cualquiera de nosotros en determinadas circunstancias y contextos de uso, tenemos temporalmente las mismas limitaciones que cualquiera de las personas mencionadas.

Basado en "First Seven Steps to accessible mobile apps > Learn about Accessibility", OneVoiceICT

1.1.2 Funciones y servicios de accesibilidad

El menú de accesibilidad de Android está en "Ajustes" y difiere por marca y gama del dispositivo. En los de gama alta suele aparecer dividido por tipo de discapacidad o interacción (Visión, Audición, Destrezas e Interacción).

Puede haber otras funciones útiles para las personas con discapacidad que no se encuentren en el menú de accesibilidad. Por ejemplo, las opciones "Modo Sencillo" o "Enviar Mensajes SOS" de Samsung están en el menú Pantalla y Llamada, respectivamente.

Las principales funciones de accesibilidad de Android organizadas por tipo de discapacidad son:

Discapacidad visual
  • Lector de pantalla: TalkBack o en Samsung Voice Assistant. El acceso mediante un lector de pantalla se basa en la verbalización del contenido que hay en pantalla y en una serie de gestos que nos permiten interactuar. Por ejemplo en TalkBack tenemos gestos como:
    • deslizar de derecha a izquierda y viceversa para ir al contenido anterior o posterior;
    • pulsar dos veces para seleccionar;
    • deslizar abajo y derecha para sacar el menú global, donde está por ejemplo la opción de leer desde arriba;
    • deslizar arriba y derecha para sacar el menú local;
    • deslizar abajo y a la izquierda para volver atrás;
    • etc.
  • BrailleBack: permite conectar una línea braille al dispositivo y, junto con TalkBack, combinar la salida de voz y la salida/introducción de información en Braille.
  • Escuchar Selección: al activar esta opción te aparece un icono en pantalla, abajo a la derecha, que al pulsarlo te leerá en voz alta los elementos que selecciones.
  • Relacionados con el zoom o la configuración del tamaño:
    • Gestos de magnificación: permite ampliar el contenido de la pantalla a través de gestos táctiles.
    • Lupa: es una ventana virtual que agranda solo una zona.
    • Texto grande: amplia el tamaño de texto; en el menú Pantalla también se puede modificar el tamaño de texto con más opciones.
    • Zoom y fuente de pantalla
  • Relacionados con el color:
    • Texto de alto contraste: los textos tienen un borde negro.
    • Teclado de alto contraste: el teclado virtual aparece en colores de alto contraste.
    • Mostrar formas de botones: muestra los botones con el fondo sombreado para resaltarlos.
    • Invertir colores (o Colores negativos) como el negativo fotográfico.
    • Corrección del color: para compensar el daltonismo.
    • Escala de grises
Discapacidad auditiva
  • Sonido monoaural: la salida estéreo por distintos canales puede suponer para algunos usuarios pérdida de información.
  • Subtítulos: esta opción te permite activar y configurar los subtítulos en el dispositivo.
  • Notificación de parpadeo: la luz de la cámara parpadea para indicar que se han recibido notificaciones o que la alarma está sonando; también hay opción de alertas visibles y vibratorias, que informa al usuario de las alertas y mensajes a través de luces y vibración.
  • Videollamada: aunque no forma parte del menú de accesibilidad es muy útil para las personas cuya lengua materna es la lengua de signos.
  • Compatibilidad con audífonos o implantes cocleares.
Discapacidad motriz y cognitiva
  • Voice Access (en beta), Google Now, Google Assistant: permiten el control por voz o el reconocimiento de voz.
  • Switch Access ("Accesibilidad mediante interruptores" en español): es una opción que permite ir accediendo a cada uno de los elementos de pantalla linealmente mediante toques de un interruptor, bien un botón físico del teléfono o un pulsador externo. A medida que los elementos cogen el foco quedan resaltados.
  • Dictado por voz: permite al usuario realizar entrada de texto a través de voz.
  • Menú de asistencia (Touch Assistant): permite reproducir las funciones de los botones físicos del dispositivo. Aparece un icono flotante que despliega un menú alternativo para hacer con un clic funciones como, por ejemplo, una captura de pantalla.
  • Texto predictivo en los campos de introducción de texto.
  • Conexión de un teclado externo u otro dispositivo de entrada.
  • Modo sencillo: opción que permite simplificar la pantalla de inicio e incluye además los iconos más grandes. No está en el menú de accesibilidad sino en el menú Pantalla.

Recursos que te serán de utilidad

1.2 Texto alternativo al contenido no textual  (android:contentDescription)

Para que el lector de pantalla anuncie correctamente una imagen, debemos incluir en la misma una descripción que comunique su función o la información que transmite.

En HTML lo hacemos con el atributo ALT, en una app nativa de Android lo hacemos con el atributo android:contentDescription.

<ImageButton
   …
   android:contentDescription= "@string/share"
   android:src="@drawable/ic_share" />

Debemos incluir android:contentDescription especialmente en: ImageButton, ImageView y también en CheckBox.

También podemos asociar la descripción con el método setContentDescription(). Esto es muy útil, por ejemplo, si cambias la imagen dinámicamente, como en el caso de un botón de reproducción que se convierte en botón de pausa.

private void  updateImageButton() {
  if (mediaCurrentlyPlaying) {
     playPauseImageView.setImageResource(R.drawable.ic_pause);
     playPauseImageView.setContentDescription(getString(R.string.pause));
  } else {
     playPauseImageView.setImageResource(R.drawable.ic_play);
     playPauseImageView.setContentDescription(getString(R.string.play));
  }
}

- Ejemplo de "Making Apps More Accessible", Android Developers, "Accessibility"

Igual que en HTML dejamos el ALT vacío (alt="") cuando la imagen es decorativa para que sea ignorada por el lector de pantalla, en Android utilizamos para el mismo propósito android:contentDescription="@null"

Recuerda que la descripción de la imagen no debe comenzar con "imagen", "icono" u otra palabra similar. En la descripción de una casilla de verificación tampoco indiques su estado ("marcado" o "no marcado") pues el lector ya nos anuncia qué tipo de contenido es o su estado. 

1.3 Etiquetas de formularios

1.3.1 android:labelFor

Los campos de formulario deberían tener una etiqueta visible. La etiqueta debería asociarse al campo mediante android:labelFor, de una manera muy similar a cómo se hace en HTML:

<LinearLayout
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:orientation="vertical">
       <TextView
            …
            android:labelFor= "@+id/edit_text_email"
            android:text="Email"  />
       <EditText
            …
            android:id= "@+id/edit_text_email"
            android:hint= "miemail@gmail.com" />
</LinearLayout>

- Ejemplo de Android Accessibility-

Las etiquetas deben ser claras, concisas y únicas en cada ventana.

1.3.2 android:hint

El atributo android:hint que observamos en el ejemplo anterior es como el placeholder de HTML, es decir, el atributo con el que definimos el texto que aparece por defecto dentro del campo.

android:hint debería utilizarse solo para incluir información que ayude a rellenar el campo. No debe usarse para etiquetar el campo, a no ser que no se pueda usar android:labelFor (API +17) o que el campo no pueda tener una etiqueta visible.

La razón por la cual no debería usarse android:hint para etiquetar el campo es que, una vez que rellenamos el campo, ya no sabemos qué dato se pedía.

Con el lector de pantalla pasa lo mismo, una vez rellenado el campo, Talkback ya no anuncia el contenido del android:hint, solo anuncia el texto escrito dentro del campo.

Además, los textos incluidos por defecto dentro de los campos suelen tener problemas de contraste, pues se les da un color de texto muy claro para diferenciar el texto inicial del dato real insertado.

1.3.3 android:contentDescription

No deberías incluir el atributo android:contentDescription en los campos de formulario.

Definir un android:contentDescription en un EditText o TextView puede interferir con la capacidad de un servicio de accesibilidad para describir, navegar y también interaccionar con el texto que un usuario ingresa en el elemento.

1.3.4 Label flotante. TextInputLayout

Hemos indicado que la etiqueta del campo no debería estar dentro del mismo.

Lo que se implementa en algunos casos es que, una vez que empiezas a escribir, la etiqueta que está definida como android:hint se muestre como un label flotante sobre el campo. De este modo no perdemos el contexto de la información que estamos ingresando.

Animación de un campo de texto. La etiqueta Apellido está dentro del campo. Al escribir el apellido, la etiqueta se sitúa encima del campo.

- Animación de "Floating labels are problematic" de Adam Silver-

Este efecto se implementa con TextInputLayout:

<android.support.design.widget.TextInputLayout
  android:layout_width="match_parent"
  android:layout_height="wrap_content">
  <android.support.design.widget.TextInputEditText
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:hint="@string/form_username"/>
</android.support.design.widget.TextInputLayout>

- Ejemplo de "TextInputLayout" de Android Developers -

En el artículo "Floating labels are problematic" Adam Silver explica todos los inconvenientes que  tiene el uso de estas etiquetas flotantes. Sin embargo, por cada uno de estos problemas (tamaño, contraste, …) Matt D. Smith ofrece una solución de diseño en su artículo "Are Float Labels Really That Problematic After All?".

Aunque solucionáramos todos los problemas de diseño como nos indica Matt D. Smith, persistiría nuestro problema con el lector de pantalla: TalkBack no lee el atributo android:hint (aunque visualmente esté presente), solo leerá el texto introducido dentro del campo, y por tanto perdemos el contexto de la información que debemos introducir.

Ted de :last:children, en su artículo "Accessible Android Inputs with Material Design", propone solucionar este problema de la siguiente manera:

<android.support.design.widget.TextInputLayout 
  android:labelFor="@+id/username" 
  android:contentDescription= "@string/username_hint" 
  android:accessibilityLiveRegion= "polite"> 
  <EditText 
       android:id="@+id/username" 
       android:hint= "@string/username_hint" 
       …/> 
</android.support.design.widget.TextInputLayout>

La propuesta tiene algún bug, según la versión de Android. Por ello, Webaim propone otra solución que no da problemas:

<android.support.design.widget.TextInputLayout
    android:id="@+id/forms_email_text_input_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="@dimen/layout_padding"
    android:labelFor="@+id/forms_email_edit_box"
    android:accessibilityLiveRegion="polite"
    android:hint="@string/edit_text_email_label"
    app:errorTextAppearance="@style/ErrorText"
    app:errorEnabled="true">

    <android.support.design.widget.TextInputEditText
        android:id="@+id/forms_email_edit_box"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="textEmailAddress"/>
</android.support.design.widget.TextInputLayout>

1.3.5 Otras consideraciones

Otras consideraciones relacionadas con los formularios son:

  • Facilita completar el formulario:
    • con la preselección de valores por defecto;
    • con la opción de autocompletado (AutoCompleteTextView);
    • sin interferir en la función corta/pega del sistema.
  • Identifica los campos obligatorios o que requieren formatos obligatorios.
  • Da información precisa sobre los errores.
  • Todo control que permite introducir información debe ser compatible con el mecanismo de dictado por voz de la plataforma. Esta función es de gran ayuda para las personas que tienen un ritmo más lento de escritura y para las personas a las que les resulta imposible introducir texto por teclado o pantalla táctil. Sin embargo, recuerda que la entrada por voz no puede ser el único método de entrada.

1.4 Notificaciones (android:accessibilityLiveRegion)

Las notificaciones (de validación de formulario o cualquier otra) deben ser percibidas por todos los usuarios, para ello es importante que no ofrezcas la información por un solo canal.

La información que se ofrece por un canal (visual, sonoro o háptico) debe ser redundante también en otro canal:

  • Las notificaciones debe ser anunciadas por el lector de pantalla.
  • Los vídeos deben tener subtítulos y audiodescripción.
  • Si ofreces una señal visual (un destello, un cambio de color, etc.) para indicar, por ejemplo, un cambio de estado o una notificación, debes ofrecer esa información también por otro canal, por ejemplo, una vibración y/o un pitido.
  • Si ofreces información por el canal auditivo, como un pitido, debe estar acompañada por un alternativa en el canal visual y/o háptico.
  • Si ofreces información por el canal háptico, como una vibración, debe estar acompañada por un alternativa en el canal sonoro  y/o visual.

Para que el contenido que cambia o aparece en pantalla sea anunciado por el lector de pantalla, usamos android:accessibilityLiveRegion. Hemos visto un ejemplo en el apartado anterior (1.3.4), al hablar de las etiquetas flotantes.

Es similar al atributo aria-live que usamos en HTML, y tiene los mismos valores: none, polite, assertive. Debería usarse assertive solo para notificaciones realmente importantes, ya que el lector de pantalla interrumpirá la lectura para anunciarlas. Resulta muy molesto que el lector anuncie determinados cambios, como por ejemplo los de un banner publicitario.

Ten en cuenta que:

  • si es un error de validación de formulario que muestras escrito, puedes necesitar mover allí el foco (requestFocus()).
  • si usas AlertDialog para mostrar mensajes de error, estos y sus funciones asociadas ya serán accesibles.
  • si usas una ventana modal, utiliza ListPopupWindow o PopupWindow, y setModal(true), para que solo el contenido de la ventana modal sea enfocable por TalkBack.
  • puedes hacer que TalkBack diga algo con View.announceForAccessibility("[el mensaje que quieres que diga]");. También hay métodos para detectar qué servicios de accesibilidad, como TalkBack, están activos en el dispositivo.

1.5 Foco y agrupaciones de elementos

1.5.1 Foco de navegación y foco de accesibilidad

No es lo mismo el foco de navegación que el foco de accesibilidad.

El foco de navegación es el foco por las vistas que requieren el input del usuario (botones, enlaces, campos de formulario), es decir, si tienes conectado un teclado, todos los elementos interactivos que cogerían el foco con el tabulador.

El foco de accesibilidad (o "traversal") es el foco de los lectores de pantalla, es decir, todos los elementos que cogerán el foco cuando hagas flicks (deslizamientos de izquierda a derecha, o al revés, para avanzar o retroceder de elemento). En este caso, el foco no lo cogen solo los elementos clicables o con los que puedes interactuar, sino también otros, como las imágenes, los textos, etc.

Para controlar que una vista recibe el foco de navegación se usa android:focusable, que para entendernos sería como el tabindex en HTML. Tenemos también los métodos relacionados: setFocusable(), requestFocus(), isFocusabled())

El foco tiene que seguir un orden natural, de izquierda a derecha y de arriba abajo, normalmente acorde con el orden visual. El foco de navegación se modifica con android:nextFocusForward, android:nextFocusDown; android:nextFocusLeft, android:nextFocusUp y android:nextFocusRight.

<LinearLayout
  …>
  <EditText
       android:id="@+id/edit"
       android:nextFocusDown= "@+id/text"
       … />
  <TextView
       android:id="@+id/text"
       android:focusable="true"
       android:text="este  texto coge el foco"
       android:nextFocusUp="@id/edit"
  … />
</LinearLayout>

Desde API+22 contamos con la posibilidad de modificar el foco de accesibilidad con: android:accessibilityTraversalAfter y android:accessibilityTraversalBefore.

Ten en cuenta que aquellos elementos que son decorativos no deberían coger el foco.

1.5.2 Agrupar los elementos para controlar la granularidad del foco (android:focusable)

Podemos usar android:focusable para controlar la granularidad del foco, organizando el contenido relacionado en grupos, de tal manera que se anuncien reflejando sus agrupaciones naturales. De esta manera el usuario de lector de pantalla no necesitará hacer tantos flicks ni esperar tanto para encontrar la información deseada.

Imaginemos una lista de canciones y autores. En vez de que cada flick llegue por separado a la canción o el autor, podemos hacer que TalkBack nos los lea como una unidad:

<RelativeLayout
  android:id="@+id/song_data_container"
  …
  android:focusable="true">
  <TextView
       android:id="@+id/song_title"
       …
       android:text= "@string/song_title"  />
  <TextView
       android:id="@+id/singer"
       …
       android:text="@string/singer" />
…
</RelativeLayout>

- Ejemplo de "Accessibility", Android Developers -

Cuando tenemos grupos pequeños o simples de contenido es una buena idea tratarlos como una unidad de información, agrupándolos como en el ejemplo anterior en un contenedor enfocable.

El agrupamiento reduce la cantidad de flicks del usuario y optimiza la salida de voz. Pero hay que encontrar un equilibrio, sino leerá demasiada información de golpe.

En Android Developers se incluyen otros casos, por ejemplo aplicados a la tablas, en las que puedes asignar el foco a una fila para que la lea como una unidad. Si no incluyes android:focusable="true", cada flick leerá una celda; pero si las agrupas, leerá seguido el contenido de toda la fila, por ejemplo producto y precio.

<LinearLayout
     ...
     orientation="vertical">
     <RelativeLayout
          ...
          android:focusable="true">
          <TextView ... />
          <TextView ... />
     </RelativeLayout>
     <RelativeLayout
          ...
          android:focusable="true">
          <TextView ... />
          <TextView ... />
     </RelativeLayout>
     <RelativeLayout
          ...
          android:focusable="true">
          <TextView ... />
          <TextView ... />
     </RelativeLayout>
</LinearLayout> 

- Ejemplo de "Accessibility", Android Developers -

Si alguna vez nos encontramos con listas (RecyclerView) que no se verbalizan correctamente, en las que TalkBack intenta vocalizar la lista entera, usar focusable="true" forzará a leer los elementos uno a uno.

1.5.3 Grupos accionables lógicos (android:clicable)

En una aplicación sueles tener grupos de elementos accionables, como un icono y su texto. Si tienes un item no accionable y no tiene predecesores accionables, TalkBack solo lo leerá si le das el foco.

En el siguiente ejemplo tenemos un item accionable huérfano que, aunque visualmente será un gran botón, al acceder con TalkBack será en realidad dos elementos.

<FrameLayout
      … >
      <View  android:clicable="true"/>
      <TextView  android:text="Aceptar"/>
      <ImageView  android:src="@drawable/image"/>
</FrameLayout>

- ejemplo incorrecto -

Sin embargo, si haces clicable el FrameLayout tendrás un único grupo accionable y como tal será anunciado por el lector de pantalla:

<FrameLayout
     android:clicable="true"
     … >
     <TextView  android:text="Aceptar"/>
     <ImageView  android:src="@drawable/image"
     ...
     />
</FrameLayout>
  

- ejemplo correcto -

El siguiente es un ejemplo de algo que NO debe hacerse:

<LinearLayout 
     android:clicable="true"  
     …>
     <Button
        android:id="@+id/button1"
        android:text="Aceptar"
        ... />
</LinearLayout>

- ejemplo incorrecto -

En este ejemplo tenemos dos elementos clicables en la jerarquía, el botón y su padre, lo cual crea confusión y dificulta, por ejemplo, el acceso con Switch Access.

1.5.4 android:importantForAccessibility

Tenemos este atributo desde API16. Es como una aria-hidden pero al revés: si es ="no" será ignorado por el lector de pantalla.

En el siguiente ejemplo se usa para definir una imagen como decorativa:

<ImageView
    android:importantForAccessibility="no"
    … />

Con android:importantForAccessibility="yes" puedes forzar a que un elemento sea expuesto a TalkBack y por tanto reciba el foco de accesibilidad.

El valor por defecto es "auto", en cuyo caso es el sistema quien decide: un Button será por defecto ="yes" y un LinearLayout por defecto será ="no".

También admite el valor "NoHideDescendants", en este caso indicas que ni la vista ni sus hijos son importantes para la accesibilidad. Esto oculta todos los elementos de una vista a la vez y es muy útil en elementos personalizados.

1.6 Tamaño de los elementos

Es importante que los controles de la interfaz tengan un tamaño adecuado para una interacción táctil, especialmente para las personas con problemas motores o de visión.

En Android se recomienda un tamaño mínimo de 48x48dp.

<ImageButton
     ...
     android:minWidth="48dp"
     android:minHeight="48dp" />

To ensure balanced information density and usability, touch targets should be at least 48 x 48 dp. In most cases, there should be 8dp or more space between them.

Size elements at least 48dp high and wide to ensure a physical size of about 9mm regardless of screen size. The recommended target size for touchscreen objects is 7-10mm.

Un icono de 40 por 40 píxeles con un área clicable de 48x48. Otro icono de 24x24 con un área clicable de 48 por 48 píxeles.

- En Google, Material Design. Accessibility -

Como se observa, el tamaño hace referencia no a la imagen en sí, sino al área en la que se puede clicar. Se puede usar un icono más pequeño pero con un padding que asegure un área clicable del tamaño adecuado.

También se puede ampliar el área clicable con TouchDelegate (ver ejemplo: "Android change touch area of View by TouchDelegate", Mohit Sharma)

Las WCAG 2.1 incluirán un nuevo criterio que obliga a que los elementos de interacción tengan un tamaño mínimo de 44x44px CSS. Sin embargo, animan a que tengan un tamaño mayor, especialmente sin son relevantes, se usan con frecuencia o son difíciles de alcanzar. Ten en cuenta que muchos usuarios, especialmente los más jóvenes, interactúan con el pulgar que es más ancho.

Un dedo índice abarca 57 píxeles. Un pulgar 72 píxeles.

- Anchuras medias del índice y el pulgar -

En otras referencias podemos encontrar los tamaños expresados en mm, por ejemplo, en la "Metodología para Evaluar la Accesibilidad de Aplicaciones Nativas" de Ilunion, donde el tamaño mínimo son 35 mm2 y la separación mínima 2 mm.

1.7 Tamaño del texto

El tamaño del texto se indica con android:textSize. El tamaño de la fuente se puede especificar en dp, sp, pt, px, mm o in.

La diferencia entre dp (density-independent pixels) y sp (scale-independent pixels) es que la fuente definida con sp escala según el tamaño de fuente especificado por el usuario, que hemos visto que puede modificarlo en los ajustes de accesibilidad del sistema.

Por tanto, la unidad de medida que debemos usar es sp.

<TextView 
     android:id="@+id/textView4" 
     android:layout_width= "wrap_content" 
     android:layout_height= "wrap_content" 
     android:text="Ejemplo" 
     android:textSize="26sp" /> 

Android también tiene unos estilos con un tamaño de fuente predefinido: Small: 14sp; Medium: 18sp; Large: 22sp. Estos también pueden usarse porque respetarán las preferencias del usuario:

<TextView 
     android:id="@+id/textView1" 
     style= "@android:style/TextAppearance.Small" 
     android:layout_width= "wrap_content" 
     android:layout_height= "wrap_content"
     android:text="Sample  Text - Small" />  
  <TextView 
     android:id="@+id/textView2" 
     style= "@android:style/TextAppearance.Medium"  
     android:layout_width= "wrap_content" 
     android:layout_height= "wrap_content" 
    android:text="Sample  Text  - Medium" /> 
  <TextView 
     android:id="@+id/textView3" 
     style= "@android:style/TextAppearance.Large" 
     android:layout_width= "wrap_content" 
     android:layout_height= "wrap_content" 
    android:text="Sample  Text  - Large" /> 

Igual que en HTML tenemos CSS, en Android se tienen temas y estilos para conseguir un estilo homogéneo y coherente para toda la app. Puedes personalizar estos tamaños por defecto como explica muy bien Juan Ardissone en el artículo Android – Styles & Themes

El tamaño mínimo legible es de 12sp, que debería evitarse o dejarse para texto insignificante. Se debería usar como mínimo 14sp.

El texto por defecto de la app debería ser igual o superior al tamaño por defecto del sistema, siempre que la tipografía utilizada sea similar a la tipografía por defecto.

La tipografía estándar en Android es Roboto:

Texto con tipografía roboto con diferente tamaño y estilo.

- Tipografía Roboto -

Puedes consultar todas las características de Roboto en "Typography" Material Design. Accessibility, Google.

Además de tener en cuenta que el tamaño de la app debe ser legible y debe crecer según las preferencias del usuario, comprueba con el tamaño de fuente grande que:

  • los interlineados y la distancia entre párrafos siguen siendo los adecuados para que el texto sea legible. El interlineado debe ser al menos 1,5 el tamaño de fuente; y la distancia entre párrafos al menos 1,5 mayor que el interlineado.
  • el texto cabe en su contenedor sin que quede cortado.
En la siguiente app, con una configuración del sistema de texto grande, el texto de los botones naranjas queda cortado.

App Ortodoncis con tamaño de texto grande. Hay tres botones cuyo texto queda cortado.

- Error: texto grande que no cabe en su contenedor -

En la app de LinkedIn, con una configuración del sistema de texto grande, se observa que en el primer item de contenido la distancia entre párrafos es insuficiente y el texto queda superpuesto:

App LinkedIn con texto grande. Dos párrafos están tan juntos verticalmente que se superponen.

- Error: interlineado incorrecto con texto grande -

También deberías tener en cuenta que, si el contenedor podría albergar el texto en otro idioma, quepa también en dicho idioma.

Por último, evita las imágenes de texto, cuyo texto el usuario no podrá personalizar según sus preferencias.

1.8 Color

El color del texto (android:textColor) debe tener suficiente contraste con el color del fondo (android:background). Este es también un requisito importante en web, y quizás más en móvil, no solo para las personas con problemas visuales, cognitivos o de lectura, también para la mayoría de nosotros. En el móvil solemos tener reflejos o solemos configurar el brillo bajo para ahorrar batería.

El ratio de contraste mínimo, según las WCAG 2.0, debería ser:

  • texto pequeño (equivalente a menos de 18pt o 14pt en negrita): ratio 4,5:1 en el nivel AA y 7:1 en el nivel AAA;
  • texto grande: ratio 3:1 en el nivel AA y 4,5:1 en el nivel AAA.

La metodología para evaluar apps de Ilunion es muy concreta en cuanto a la evaluación del contraste en base al tamaño y la tipografía, y creo que sería muy recomendable seguir sus especificaciones (consultar " Metodología para Evaluar la Accesibilidad de Aplicaciones Nativas" (PDF) de Ilunion", 1.4.3 Contraste de color)

También es importante no transmitir información solo con el color:

Incorrecto

App con un listado de diagnósticos realizados al módem. Unos tienen al lado un icono redondo rojo y otros un icono redondo verde.

- Información que se transmite solo con el color -

En el ejemplo anterior, si alguien no puede distinguir el color de los círculos, no podrá saber el estado de los componentes. Se podría haber usado, de forma complementaria al color, iconos con formas diferentes (círculo verde y cuadrado rojo) con una leyenda.

Correcto

App con listado de estacionamientos. Unos tienen un cuadrado gris con el texto 'cerrado'; y otros un cuadrado amarillo con el texto 'casi lleno'.

- Información que NO se transmite solo por el color -

En este otro ejemplo, aunque no podamos distinguir el amarillo del gris, se ofrece complementariamente un texto que nos indica el estado del parking. Ahora ya solo sería necesario que ese texto cumpliera con el contraste de color.

Hemos comentado al inicio que en Android tenemos distintas opciones relacionadas con el color en el menú de Accesibilidad, como Invertir colores o Texto de alto contraste.

No es necesario que ofrezcamos este tipo de opciones en nuestra aplicación. Lo que sí es importante es no interferir con ellas y comprobar que funcionan correctamente en nuestra app, que todo el contenido textual se presenta siguiendo las personalizaciones de color del usuario.

1.9 Alternativas para el canal de entrada

Las personas con discapacidad motora es probable que:

  • no puedan realizar determinados movimientos,
  • no puedan realizarlos con precisión,
  • no puedan aplicar fuerza,
  • no pueda realizar varios gestos simultáneos.

Por ello, la interacción debe ser sencilla o dar una alternativa a los gestos complejos multitáctiles. Tampoco deben colisionar con los gestos predefinidos de los producto de apoyo como TalkBack.

Las WCAG 2.1 incluirán un nuevo criterio que hace referencia también a este requisito (ver "WCAG 2.1, medida provisional hasta las WCAG 3.0", 2.5.1 Pointer Gestures).

Por otro lado, tampoco puedes presuponer que los usuarios utilizarán un método de entrada concreto, así que evita dar instrucciones del tipo "Toca dos veces", sino otras más abstractas, como "Activa el elemento".

1.10 Rol, nombre, valor y estado. Custom Views

Nuestra app y un producto de apoyo como es el lector de pantalla TalkBack se comunican a través de la API de accesibilidad.

El usuario interactúa con la app através de la API de accesibilidad.

- Esquema de interacción con la API de accesibilidad -

La app informa del evento que ha ocurrido, el objeto que lo ha causado y sus propiedades. Por tanto, las acciones de los usuarios y las propiedades de nuestros componentes son expuestas a la API de accesibilidad y a través de esta al producto de apoyo, que a su vez trasladará la información al usuario.

Por cada componente anunciará:

  • Rol, es decir, qué tipo de componente es: un botón, un texto, …
  • Nombre, etiqueta o contenido textual, como hemos visto por ejemplo en el apartado sobre cómo etiquetar imágenes o sobre cómo etiquetar campos de formulario.
  • Estado, es decir, en qué situación se encuentra gracias siempre a sus propiedades, no a su aspecto visual: marcado (android:checked="true"), deshabilitado (android:enabled="false"), etc.
  • Valor, como el texto que contiene un campo de texto.

De esta forma, solo por utilizar un componente estándar e indicar sus propiedades, apenas tendremos que hacer nada más, será accesible sin ningún esfuerzo adicional. Solo tendremos que asegurarnos de que está correctamente etiquetado, porque ya expondrá correctamente su rol, etiqueta, estado y valor.

Android ofrece un completo modelo de componentes para construir la interfaz, basado en las clases View y ViewGroup, para las que la plataforma incluye gran variedad de subclases:

  • widgets en el caso de View: Button, TextView, EditText, etc.
  • layouts en el caso de ViewGroup: LinearLayout, FrameLayout, etc.

Se pueden consultar todos con un ejemplo en Standard Controls, Xamarin.

Úsalos siempre que puedas.

Cabe en este punto indicar que la clase WebView, que permite visualizar páginas web, es un tanto especial. En este caso tendremos que: permitir el JavaScript (mWebView.getSettings.setJavaScriptEnabled(true);) y asegurarnos de que la página que se muestra sea accesible (cumpla con las WCAG 2.0).

Si en HTML quisiéramos simular que una imagen es un checkbox, podríamos hacerlo (no digo que deberíamos) y podríamos hacerlo accesible: incluiríamos tabindex="0" para que cogiera el foco; le pondríamos role="checkbox" para que fuera anunciado como un checkbox; le añadiríamos un aria-label  para etiquetarlo; le pondríamos aria-checked="true" para que anunciara que está seleccionado; controlaríamos los eventos para cambiar su estado dinámicamente cada vez que el usuario lo pulsará en el acceso con ratón y con teclado, etc.

Mucho trabajo pero posible.

En Android ocurre lo mismo. Si creas componentes personalizados tendrás que definir manualmente toda la información y funcionalidad que lo haga accesible.

Puedes consultar la guía de cómo lograr construir Custom Views accesibles paso a paso en:
Building Accessible Custom Views, Android Developers,

Las principales tareas que incluye son:

  1. Handling directional controller clicks
  2. Implementing accessibility API methods
  3. Sending accessibility events
  4. Populating accessibility events
  5. Providing a customized accessibility context
  6. Handling custom touch events

Las principales clases que se utilizan son: AccessibilityEvent, AccessibilityNodeInfo, AccessibilityNodeInfoCompat, View.AccessibilityDelegate, AccessibilityDelegateCompat, ExploreByTouchHelper

Otra cosa diferentes es el tema de implementar tu propio servicio de accesibilidad.

A finales de año (2017) hubo mucho revuelo porque Google amenazó con eliminar de Google Play todas las apps que solicitaban permisos de accesibilidad para tareas que no tenían nada que ver con la accesibilidad. De momento, a día de hoy, solo se pide que añadan una descripción al servicio de accesibilidad para explicar por qué lo necesitan.

Los servicios de accesibilidad se encuentran en Ajustes > Accesibilidad. Por defecto tendrás TalkBack, Accesibilidad mediante interruptores, etc. pero también los de otras apps que te hayas instalado, pues se pueden crear y distribuir servicios propios.

Por ejemplo, Voice Access o  Accessibility Scanner (que reseñé en Accessibility Scanner, evaluar la accesibilidad de una app de Android) se instalan como un servicio de accesibilidad. Por ejemplo, el antivirus AVG instala un servicio de accesibilidad que permite alertar de las amenazas con una alarma sonora.

Para saber cómo construir tu propio servicio de accesibilidad se puede consultar Building Accessibility Services, Android

1.11 Fácil y consistente

Las personas con una discapacidad cognitiva pueden tener mayor dificultad para comprender o aprender el funcionamiento de tu app, pero todos vamos a agradecer que:

  • sea simple, clara, intuitiva y consistente;
  • no tenga términos enrevesados o instrucciones complejas;
  • no tenga navegaciones excesivamente largas y retorcidas;
  • se sepa siempre en qué vista estás y cómo desplazarte a la vista que deseas alcanzar;
  • se resalten los elementos más importantes;
  • tener que desplazarse lo menos posible para completar cada acción.

Una buena práctica es seguir las guías de estilo de cada plataforma para que el aspecto sea homogéneo con el resto del sistema operativo y la curva de aprendizaje sea mínimo.

Aquí también podríamos hablar del título, que es leído por TalkBack, y que se define en AndroidManifest.xml mediante android:label.

1.12 Principales errores

En la página "Valoración de accesibilidad de Apps" del Centro de Investigación, Desarrollo y Aplicación Tiflotécnica (CIDAT) se pueden consultar revisiones de accesibilidad de diversas apps. Si lees unas cuantas, podrás concluir que al final los errores son recurrentes y que están relacionados con el incumplimiento de las buenas prácticas que hemos repasado:

  • Elementos sin etiquetar o etiquetados incorrectamente.
  • Elementos que no son visualizados en pantalla pero son verbalizados por Talkback.
  • Advertencias que no son verbalizadas de forma automática.
  • Banners que se verbalizan continuamente.
  • Botones, enlaces, pestañas, etc. que no se identifican como tales y que TalkBack anuncia como texto, sin que el usuario sea consciente de que son activables o de qué tienen una función.
  • Problemas de contraste de color.
  • Texto que, con la configuración de texto grande del sistema, se queda cortado dentro de su contenedor.
  • Problemas con el foco.
  • Listas inaccesibles.
  • Mapas inaccesibles.
  • Incorrecta agrupación de los elementos con una misma función, por ejemplo una imagen y dos líneas de texto que no son verbalizados como un enlace único sino como tres.
  • No se anuncia el cambio de estado de los elementos.
  • Problemas con los selectores de fecha y hora.
  • Elementos a los que no se puede acceder mediante TalkBack con flicks (deslizamiento de izquierda a derecha o al revés, para avanzar o retroceder de elemento), sino solo mediante la exploración táctil (deslizar el dedo por pantalla de tal manera que verbaliza lo que encuentra).

Parte 2. Aplicación de la norma EN 301 549 a las apps nativas de Android

Nota 09/2018:

En agosto de 2018 de actualizó la norma EN 301 549 para, por un lado, clarificar cómo se aplica a las páginas web y a las apps nativas para cumplir con la Directiva (UE) 2016/2102; y por otro, para equipararla a las WCAG 2.1, publicadas en junio de 2018.

A raíz de los cambios en la nueva versión de la norma, publiqué en septiembre un artículo específico sobre la aplicación de la EN 301 549 a las apps móviles, al que os remito directamente: Requisitos de accesibilidad de la EN 301 549 aplicables a las apps móviles nativas, obligatorios por ley a partir de 2021

Parte 3. Revisión y herramientas

A continuación incluyo un listado en orden alfabético de herramientas que pueden ser de utilidad para la revisión de la accesibilidad de la app.

Accessibility Checker [NetBeans IDE]

Es un plugin para el entorno de desarrollo NetBeans. Ofrece una lista con los errores y advertencias detectadas, así como información adicional para poder mejorar el producto final.

Pantalla de Attest Mobile. A la izquierda el resumen, a la derecha la descripción.

- Accessibility Checker [NetBeans IDE] (ver imagen más grande) -

Accessibility Scanner

Es un validador automático de accesibilidad para apps de Android que permite escanear cualquier aplicación que tengamos instalada en el móvil. Detecta problemas de contraste de color, elementos clicables demasiado pequeños, o elementos sin etiquetar.

La reseñé en el artículo Accessibility Scanner, evaluar la accesibilidad de una app de Android

AccessibilityService

Se ejecuta en segundo plano y devuelve información cuando se activan los eventos de accesibilidad. Es útil para el testeo manual.

Accessibility Test Framework

Esta API realiza diversas comprobaciones de accesibilidad.

Deque Universityfor Android

Esta no es una herramienta como las demás, no realiza validaciones. Es una app pensada para ayudarnos a comprender, mediante diferentes ejemplos, los problemas que encuentran los usuarios de TalkBack.

Espresso

Google liberó en 2013 Espresso, un framework para la automatización de pruebas funcionales. La API de Espresso está enfocada a utilizar el patrón ViewMatcher / ViewAction / ViewAssertion, que viene a ser una sintaxis en la que, utilizando el propio lenguaje, queda definida la acción a realizar sobre una vista/objeto y su correspondiente comprobación.

Tienes un ejemplo de cómo usarlo para comprobar las descripciones de los botones que se modifican dinámicamente en Accessibility Testing on Android de Kelly Shuster .

Espresso está muy bien explicado en “Espresso, haciendo pruebas funcionales en Android”, Guillermo Guerrero

forApp

Es un servicio en línea que comprueba automáticamente apps. Hay cientos evaluadas y puedes descargar los resultados. De momento es un servicio gratuito, en un futuro podrás analizar tu app. Las comprobaciones están relacionadas con las alternativas textuales o el foco.

Además, en cada informe se incluye una imagen con el orden del foco (en el siguiente pantallazo, en la columna izquierda).

Informe de forApp de la app MeowChat. Los tipos de error son: Alternative Text; Focus; Multi-touch. Por cada uno se indica el número de fallos, aciertos y advertencias, y una puntuación. En la columna izquierda un pantallazo de la app con números y flechas que indican el orden del foco .

- forApp. En la columna izquierda el orden del foco -

Lint

Integrada en Android Studio. Encuentra problemas como imágenes sin contentDescription o campos de formulario sin labelFor.

Un mensaje en Lint: Image without contentDescription.

- Lint. Imagen de Android Developers -

Node Tree Debugging

Se activa en la configuración de TalkBack y permite consultar el árbol de elementos tal y como se expone a la capa de accesibilidad. Consultar tutorial: Debugging Android Accessibility, de Midori Bowen

Robolectric

Es una librería de código abierto que permite ejecutar test en la propia máquina virtual de JAVA en vez de arrancar el emulador cada vez que ejecutamos el test.

Stetho

Se añade a las herramientas de desarrolladores de Chrome. Te conectas a la app y la depuras como si fuera una web.

UI Automator Viewer

Tiene un visor para inspeccionar la jerarquía de elementos tal y como se expone a la capa de accesibilidad y puedes crear pruebas basadas en determinada propiedad. UI Automator.

WorldSpace Attest

Es una app de Deque que, una vez instalada, aparecerá como un servicio más en Ajustes > Accesibilidad, y nos dará notificaciones de los problemas de accesibilidad detectados. De momento no está disponible para ser descargada desde España.

Se puede conectar con la aplicación escritorio para mostrar los resultados en el navegador:

Pantalla de Attest Mobile. A la izquierda el resumen, a la derecha la descripción.

- WorldSpace Attest -

Dos enlaces de interés:

Por último, no hay que olvidar que la forma más lógica y recomendable de testear, es no solo conociendo y activando las opciones de accesibilidad (TalkBack, Switch Access, etc.) o usando herramientas como las listadas, sino involucrando en las pruebas de revisión y calidad a usuarios con discapacidad.

Portada del libro Guia Aplicaciones moviles accesible. EN 301 549. Olga Carreras Montoto.

Aguía Aplicaciones móviles accesibles

Olga Carreras, 2023

Un guía divulgativa sobre la accesibilidad en aplicaciones móviles. Está dirigida a cualquier personas que quiera comprender qué es una aplicación móvil accesible y qué requisitos debe cumplir sin necesidad de tener conocimientos técnicos específicos.

En la guía explico todos los requisitos de la EN 301 549. También incluye un anexo con una lista de verificación.

Leer reseña

Descarga gratuita del libro "Guía Aplicaciones móviles accesible" en PDF accesible (10MB)

Referencias

* Imagen de portada original de Codelabs

Artículos relacionados

4 comentarios :
Padawan dijo...

Fantástico artículo. Muy completo e ilustrador. ¿Sabes donde podría encontrar información similar para las aplicaciones nativas de IOS? Aunque supongo que la mayoría de los criterios aplicarán igualmente para todos los sistemas operativos. Gracias.

Olga Carreras dijo...

Hola Raúl, todo lo dicho en el artículo se aplica a iOS, "el qué" es el mismo, lo que cambia es "el cómo".
https://www.apple.com/es/accessibility/iphone/vision/
https://developer.apple.com/accessibility/
https://developer.apple.com/accessibility/ios/

Padawan dijo...

Gracias por la rápida respuesta y por los enlaces. Un saludo.

Emilia dijo...

Hola Olga! Felicitaciones por este post sobre las Apps de Android, lo compartiré sin duda por mis redes. Abrazos desde Chile

Publicar un comentario