En los dispositivos con Sistema operativo Chrome, muchos usuarios interactúan con apps mediante un teclado, un mouse, un panel táctil, una pluma stylus o un control de juegos. Si bien esos dispositivos de entrada también se usan en teléfonos Android, no son tan habituales y, con frecuencia, los desarrolladores los pasan por alto.
Los desarrolladores que deseen que su app funcione bien con entradas en el Sistema operativo Chrome y otros dispositivos con pantallas grandes de Android deben verificar las siguientes optimizaciones:
Agregar y probar la compatibilidad básica del teclado, como la navegación con teclado mediante las teclas de flecha y tabulación, la tecla Intro para confirmar la entrada de texto, y la tecla Espacio para reproducir y pausar contenido en apps multimedia.
Agregar combinaciones de teclas estándares cuando corresponda (por ejemplo, Ctrl + Z para deshacer o Ctrl + S para guardar).
Probar las interacciones básicas del mouse en la manera de clic con el botón derecho para el menú contextual, cambios del ícono cuando se coloca el cursor, y los eventos de desplazamiento de la rueda del mouse y del panel táctil en las vistas personalizadas.
Probar dispositivos de entrada específicos de la app, como la pluma stylus para dibujar apps, controles para juegos y controles MIDI para apps de música.
Considerar la compatibilidad con entradas avanzadas que podrían permitir que la app se destaque en entornos de escritorio: el panel táctil como reproducción sin pausa para apps de DJ, la captura del mouse para juegos y las combinaciones de teclas extensas para los usuarios avanzados.
Teclado
La manera en que la app responde a la entrada del teclado contribuye a una buena experiencia de escritorio. Existen tres tipos de entrada de teclado: navegación, combinaciones de teclas y accesos directos.
Navegación
La navegación con teclado casi nunca se implementa en apps centradas en pantallas táctiles, pero los usuarios la esperan cuando usan una app y tienen el teclado en las manos. También puede ser fundamental para los usuarios con necesidades de accesibilidad en teléfonos y dispositivos de escritorio.
En muchas apps, solo se necesita una tecla de flecha simple y la navegación de pestañas, que se gestiona automáticamente en el framework de Android. Por ejemplo, se puede enfocar, de forma predeterminada, una vista de un objeto Button
, y la navegación del teclado suele funcionar sin ningún código adicional. Para habilitar la navegación del teclado en las vistas que no se pueden enfocar de forma predeterminada, los desarrolladores deben marcarlas como enfocables. Esto se puede hacer de manera programática o en formato XML, como se muestra a continuación. Consulta la documentación de Control de enfoque para obtener más información.
Kotlin
yourView.isFocusable = true
Java
yourView.setFocusable(true);
También puedes establecer el atributo focusable
en el archivo del diseño:
android:focusable="true"
Una vez que se habilite el enfoque, el marco de trabajo de Android creará una asignación de navegación para todas las vistas enfocables según su posición. Por lo general, funciona como se espera, y no se necesita ningún trabajo adicional. Cuando la asignación predeterminada no es correcta para las necesidades de una app, se puede anular de la siguiente manera:
Kotlin
// Arrow keys yourView.nextFocusLeftId = R.id.view_to_left yourView.nextFocusRightId = R.id.view_to_right yourView.nextFocusTopId = R.id.view_above yourView.nextFocusBottomId = R.id.view_below // Tab key yourView.nextFocusForwardId = R.id.next_view
Java
// Arrow keys yourView.setNextFocusLeftId(R.id.view_to_left); yourView.setNextFocusRightId(R.id.view_to_left); yourView.setNextFocusTopId(R.id.view_to_left); yourView.setNextFocusBottomId(R.id.view_to_left); // Tab key yourView.setNextFocusForwardId(R.id.next_view);
Te recomendamos que intentes acceder, solo con el teclado, a todas las funciones de la app antes de cada lanzamiento. Debería ser fácil acceder a las acciones más habituales sin usar el mouse.
Recuerda que la compatibilidad con el teclado puede ser fundamental para los usuarios con necesidades de accesibilidad.
Combinación de teclas
Para la entrada de texto que se controlaría con un teclado virtual en pantalla (IME), como un objeto EditText
, las apps deben comportarse como se espera en el Sistema operativo Chrome, sin acciones adicionales por parte del desarrollador. En el caso de que el framework no pueda anticipar las combinaciones de teclas, las apps deberán controlar el comportamiento por sí mismas, en especial, las que tiene vistas personalizadas.
Algunos ejemplos son las apps de chat que usan la tecla Intro para enviar un mensaje, las apps de música que inician y detienen la reproducción con la tecla Espacio, y los juegos que controlan el movimiento con las teclas w, a, s y d.
La mayoría de las apps anulan el evento onKeyUp y agregan el comportamiento esperado para cada código de clave recibido, como se muestra a continuación.
Kotlin
override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean { return when (keyCode) { KeyEvent.KEYCODE_ENTER -> { sendChatMessage() true } KeyEvent.KEYCODE_SPACE -> { playOrPauseMedia() true } else -> super.onKeyUp(keyCode, event) } }
Java
@Override public boolean onKeyUp(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_ENTER) { sendMessage(); return true; } else if (KeyEvent.KEYCODE_SPACE){ playOrPauseMedia(); return true; } else { return super.onKeyUp(keyCode, event); } }
Usar el evento onKeyUp
evita que las apps reciban varios eventos si la tecla se mantiene presionada o se suelta lentamente. Los juegos y las apps que esperan que los usuarios mantengan presionadas las teclas pueden buscar el evento onKeyDown.
Cuando agregues compatibilidad con el teclado, sigue la documentación de control del teclado de Android.
Accesos directos
En los entornos de escritorio, se esperan accesos directos habituales basados en Ctrl, Alt y Mayúsculas. Si una app no las implementa, la experiencia puede ser frustrante y perjudicial para los usuarios. Los usuarios avanzados también valoran los accesos directos para las tareas específicas de la app que se usan con frecuencia. Los accesos directos facilitan el uso de una app y la diferencian de aquellas que no tienen accesos directos.
Algunos accesos directos habituales incluyen Ctrl + S (guardar), Ctrl + Z (deshacer) y Ctrl + Mayúsculas + Z (rehacer). Para ver un ejemplo de accesos directos más avanzados, consulta la lista de teclas de acceso directo de VLC Media Player.
Los accesos directos se pueden implementar con el objeto dispatchKeyShortcutEvent, que intercepta todas las combinaciones de teclas meta (Alt, Ctrl y Mayúsculas) para un código de clave determinado. Para verificar una tecla meta específica, usa los objetos KeyEvent.isCtrlPressed(), KeyEvent.isShiftPressed(), KeyEvent.isAltPressed() o KeyEvent.hasModifiers().
Separar el código de acceso directo de otros controles de combinaciones de teclas (como los eventos onKeyUp
o onKeyDown
) puede facilitar el mantenimiento del código y mantener la aceptación predeterminada de las teclas meta sin tener que implementar, de forma manual, las comprobaciones de las claves meta en cada caso.
Permitir todas las combinaciones de teclas meta también puede ser más conveniente para los usuarios que están acostumbrados a diferentes diseños de teclado y sistemas operativos.
Kotlin
override fun dispatchKeyShortcutEvent(event: KeyEvent): Boolean { return when (event.keyCode) { KeyEvent.KEYCODE_O -> { openFile() // Ctrl+O, Shift+O, Alt+O true } KeyEvent.KEYCODE_Z-> { if (event.isCtrlPressed) { if (event.isShiftPressed) { redoLastAction() // Ctrl+Shift+Z pressed true } else { undoLastAction() // Ctrl+Z pressed true } } } else -> { return super.dispatchKeyShortcutEvent(event) } } }
Java
@Override public boolean dispatchKeyShortcutEvent(KeyEvent event) { if (event.getKeyCode() == KeyEvent.KEYCODE_O) { openFile(); // Ctrl+O, Shift+O, Alt+O return true; } else if(event.getKeyCode() == KeyEvent.KEYCODE_Z) { if (event.isCtrlPressed()) { if (event.isShiftPressed()) { redoLastAction(); return true; } else { undoLastAction(); return true; } } } return super.dispatchKeyShortcutEvent(event); }
También puedes implementar accesos directos en el objeto onKeyUp
si verificas los elementos KeyEvent.isCtrlPressed(), KeyEvent.isShiftPressed() o KeyEvent.isAltPressed() de la misma manera que se explicó anteriormente. Se puede mantener, de forma más fácil, si el comportamiento meta es más una modificación del comportamiento de una app que un acceso directo. Por ejemplo, cuando W significa "caminar hacia adelante" y Mayúscula + W significa "correr hacia adelante".
Kotlin
override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean { return when(keyCode) { KeyEvent.KEYCODE_W-> { if (event.isShiftPressed) { if (event.isCtrlPressed) { flyForward() // Ctrl+Shift+W pressed true } else { runForward() // Shift+W pressed true } } else { walkForward() // W pressed true } } else -> super.onKeyUp(keyCode, event) } }
Java
@Override public boolean onKeyUp(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_W) { if (event.isShiftPressed()) { if (event.isCtrlPressed()) { flyForward(); // Ctrl+Shift+W pressed return true; } else { runForward(); // Shift+W pressed return true; } } else { walkForward(); return true; } } return super.onKeyUp(keyCode, event); }
Compatibilidad con mouse y panel táctil
El Sistema operativo Chrome controla automáticamente la mayoría de los eventos del mouse y del panel táctil para que actúen como eventos táctiles en un teléfono Android. Esto incluye el desplazamiento con la rueda del mouse o con dos dedos en el panel táctil. Por lo general, la mayoría de las apps solo necesitan controlar tres eventos centrados en entornos de escritorio: hacer clic con el botón derecho, colocar el cursor sobre un elemento, y arrastrar y soltar.
Hacer clic con botón derecho
Cualquier acción que permita que una app muestre un menú contextual, como mantener presionado un elemento de la lista, también debe responder a eventos de clic con el botón derecho. Para controlar eventos de clic con el botón derecho, las apps deben registrar un objeto View.OnContextClickListener
.
Para obtener detalles sobre cómo crear un menú contextual, consulta la documentación de menús contextuales de Android.
Kotlin
yourView.setOnContextClickListener { showContextMenu() true }
Java
yourView.setOnContextClickListener(v -> { showContextMenu(); return true; });
Colocar el cursor sobre un elemento
Los desarrolladores pueden lograr que los diseños de sus apps se sientan optimizados y más fáciles de usar si se controlan los eventos de desplazamiento, en especial, las vistas personalizadas. Los dos ejemplos más comunes son los siguientes:
- Cambiar el ícono del puntero del mouse para indicarles a los usuarios si un elemento tiene un comportamiento interactivo, como elementos que se pueden editar o en los que se puede hacer clic
- Agregar comentarios visuales a los elementos en una lista o una cuadrícula grande cuando el puntero se coloca sobre ellos
Kotlin
// Change the icon to a "hand" pointer on hover, // Highlight the view by changing the background. yourView.setOnHoverListener { view, _ -> addVisualHighlighting(true) view.pointerIcon = PointerIcon.getSystemIcon(view.context, PointerIcon.TYPE_HAND) false // listener did not consume the event. }
Java
yourView.setOnHoverListener((view, event) -> { addVisualHighlighting(true); view.setPointerIcon(PointerIcon .getSystemIcon(view.getContext(), PointerIcon.TYPE_HAND)); return true; });
Arrastrar y soltar
En un entorno Multiventana, los usuarios esperan poder arrastrar y soltar elementos entre apps. Esto se aplica a dispositivos con el Sistema operativo Chrome, así como a tablets, teléfonos y dispositivos plegables en modo de pantalla dividida.
Los desarrolladores deben considerar si es probable que los usuarios arrastren elementos a su app. Entre algunos ejemplos comunes, se incluyen: los editores de fotos que se espera que reciban imágenes, los reproductores de audio que se espera que reciban archivos de audio y los programas de dibujo que se espera que reciban fotos.
Para agregar compatibilidad con la función de arrastrar y soltar, sigue la documentación de Arrastrar y soltar de Android y consulta esta entrada de blog del Sistema operativo Chrome.
Consideraciones especiales para el Sistema operativo Chrome
- Para administrar archivos desde la app de Archivos del Sistema operativo Chrome, busca el tipo de MIME
application/x-arc-uri-list
. - Recuerda solicitar permiso a través del objeto
requestDragAndDropPermissions
para acceder a los elementos que se arrastren desde la app. - Un elemento debe tener la marca
View.DRAG_FLAG_GLOBAL
para poder arrastrarlo a otras aplicaciones.
Compatibilidad con puntero avanzado
Las apps que realizan un control avanzado de la entrada del mouse y del panel táctil deben seguir la documentación de Android para el elemento View.onGenericMotionEvent() y usar el objeto MotionEvent.getSource()
a fin de distinguir entre los parámetros SOURCE_MOUSE y SOURCE_TOUCHSCREEN.
Examina el objeto MotionEvent
para implementar el comportamiento requerido:
- El movimiento genera los eventos
ACTION_HOVER_MOVE
. - Los botones generan los eventos
ACTION_BUTTON_PRESS
yACTION_BUTTON_RELEASE
. También puedes verificar el estado actual de todos los botones del mouse y del panel táctil con el objetogetButtonState()
. - El desplazamiento de la rueda del mouse genera eventos
ACTION_SCROLL
.
Pluma stylus
Muchas Chromebooks incluyen una pluma stylus, y las apps para Android las controlan como entrada de pantalla táctil. Algunos dispositivos también pueden tener una tabla de dibujo con USB o Bluetooth, como Wacom Intuos. Las apps para Android pueden recibir entradas Bluetooth, pero no funcionarán con entrada USB.
Un evento de pluma stylus se informa como un evento de pantalla táctil a través de los objetos View.onTouchEvent() o View.onGenericMotionEvent(), y contiene un elemento MotionEvent.getSource()
del tipo SOURCE_STYLUS.
El objeto MotionEvent
también contendrá datos adicionales:
- El objeto MotionEvent.getToolType() mostrará los elementos TOOL_TYPE_FINGER, TOOL_TYPE_STYLUS o TOOL_TYPE_ERASER, según la herramienta que haga contacto con la plataforma
- El objeto MotionEvent.getPressure() informará la presión física aplicada a la pluma stylus, si es compatible
- El objeto MotionEvent.getAxisValue() con los elementos MotionEvent.AXIS_TILT y MotionEvent.AXIS_ORIENTATION, que se pueden usar para leer la orientación y la inclinación física, si es compatible
Puntos históricos
Android agrupa eventos de entrada y los entrega una vez por fotograma. Una pluma stylus puede informar eventos con frecuencias mucho más altas que la pantalla. Cuando creas apps de dibujo, es importante verificar los eventos que pueden estar en el pasado reciente mediante las API de getHistorical
:
MotionEvent.getHistoricalX()
MotionEvent.getHistoricalY()
MotionEvent.getHistoricalPressure()
MotionEvent.getHistoricalAxisValue()
Rechazo de la palma
El Sistema operativo Chrome intenta reconocer cuando la palma de un usuario está apoyada en la pantalla táctil. Sin embargo, no siempre es posible. Con frecuencia, un evento táctil se puede informar a la app antes de que el SO la reconozca como una palma. En ese caso, se cancelarán los toques informando un evento ACTION_CANCEL
.
Ese evento le indica a la app que ciertos toques no son válidos y que debe deshacer todas las interacciones que se produzcan con ellos. Por ejemplo, una app de dibujo podría dibujar líneas nuevas temporalmente en cuanto se las recibe para brindar la latencia más baja, pero solo las confirmará, de manera permanente, en el recuadro una vez que la serie táctil haya finalizado de manera correcta. Si los eventos táctiles se cancelan mientras tanto, las líneas temporales se pueden borrar con facilidad.
Apps para tomar notas
El Sistema operativo Chrome tiene un intent especial que les muestra a los usuarios apps registradas para tomar notas. A fin de registrar una app como una app para tomar notas, agrega lo siguiente al manifiesto de Android:
<intent-filter>
<action android:name="org.chromium.arc.intent.action.CREATE_NOTE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
Cuando se registra una app, el usuario puede seleccionarla como la predeterminada para tomar notas. Cuando se solicita una nota nueva, la app debe crear una nota vacía y lista para la entrada de la pluma stylus. Cuando el usuario desea escribir en una imagen (como una captura de pantalla o una imagen descargada), la app se inicia con el objeto ClipData
que contiene uno o más elementos con URI de content://
. La app debe crear una nota que use la primera imagen adjunta como imagen de fondo y que ingrese un modo en el que el usuario pueda dibujarla con una pluma stylus.
Cómo probar intents para tomar notas sin una pluma stylus
A fin de probar si una app responde correctamente a los intents para tomar notas sin una pluma stylus activa, usa el siguiente método a fin de mostrar las opciones para tomar notas:
- Cambia al modo de desarrollo y haz que se pueda escribir en el dispositivo.
- Presiona Ctrl + Alt + F2 para abrir una terminal.
- Ejecuta el comando
sudo vi /etc/chrome_dev.conf
. - Presiona
i
para editar y agregar el elemento--ash-enable-palette
a una nueva línea al final del archivo. - Para guardar, presiona Esc, escribe :, w, q y presiona Intro.
- Presiona Ctrl + Alt + F1 para volver a la IU normal del Sistema operativo Chrome.
- Sal y vuelve a acceder.
Ahora debería haber un menú de la pluma stylus en la biblioteca:
- Presiona el botón de la pluma stylus en la biblioteca y elige Nueva nota. Se debería abrir una nota de dibujo en blanco.
- Toma una captura de pantalla. En la biblioteca, selecciona el botón de la pluma stylus > Captura de pantalla o descarga una imagen. En la notificación, debería estar la opción "Escribir en la imagen". Se debería iniciar la app con la imagen lista para poder escribirla.
Controles para juegos
Las Chromebooks admiten hasta cuatro controles para juegos. Los desarrolladores deben usar las API estándar de controles para juegos de Android a fin de manejarlos.
Los botones se asignan a valores comunes después de una asignación común. Lamentablemente, no todos los fabricantes de controles para juegos siguen las mismas convenciones de asignación. Puedes proporcionar una experiencia mucho mejor si permites que los usuarios seleccionen diferentes asignaciones populares para controles.
Modo de traducción de entrada
El Sistema operativo Chrome habilita un modo de traducción de entrada de forma predeterminada. En la mayoría de las apps para Android, ese modo ayuda a que funcionen como se espera en un entorno de escritorio. Algunos ejemplos incluyen la habilitación automática del desplazamiento con dos dedos en el panel táctil, el desplazamiento de la rueda del mouse y la asignación de coordenadas de pantalla sin procesar a las coordenadas de la ventana. Por lo general, los desarrolladores de apps no necesitan implementar ninguno de esos comportamientos.
Si una app implementa un comportamiento de entrada personalizado (por ejemplo, definir una acción personalizada de pellizcar con dos dedos en el panel táctil) o si esas traducciones de entrada no proporcionan los eventos de entrada que espera la app, puedes inhabilitar el modo de traducción de entrada agregando la siguiente etiqueta al manifiesto de Android:
<uses-feature
android:name="android.hardware.type.pc"
android:required="false" />