Em dispositivos Chrome OS, muitos usuários interagem com apps usando um teclado, mouse, trackpad, stylus ou gamepad. Embora esses dispositivos de entrada também sejam usados em smartphones Android, eles não são tão comuns e geralmente são ignorados por desenvolvedores.
Os desenvolvedores que quiserem que o app funcione bem com entradas no Chrome OS e outros dispositivos Android compatíveis com telas grandes precisam analisar as seguintes otimizações:
Adicione e teste a compatibilidade básica do teclado, como a navegação pelo teclado por meio das teclas de seta e de Tab, Enter para confirmar a entrada de texto e Espaço para reproduzir/pausar em apps de mídia.
Adicione atalhos de teclado padrão, quando for o caso, por exemplo, Ctrl + Z para desfazer, Ctrl + S para salvar.
Teste interações básicas do mouse com o botão direito para acessar o menu de contexto, alterações de ícone ao passar o cursor e eventos de rolagem do mouse/trackpad em visualizações personalizadas.
Teste dispositivos de entrada específicos do app, como a stylus para apps de desenho, controles de jogos e controles de MIDI para apps de música.
Considere a compatibilidade avançada de entrada que pode destacar o app em ambientes de computador: touchpad como um modificador para apps de DJ, captura de mouse para jogos e atalhos de teclado adicionais para usuários avançados.
Teclado
A maneira como seu app responde à entrada do teclado contribui para uma boa experiência em computadores. Existem três tipos de entrada de teclado: navegação, pressionamentos de tecla e atalhos.
Navegação
A navegação pelo teclado raramente é implementada em apps voltados para o toque, mas os usuários esperam isso quando estão usando um app e estão com as mãos no teclado. Também pode ser essencial para usuários com necessidades de acessibilidade em smartphones e computadores.
Para muitos apps, a navegação simples pelas teclas de seta e Tab é o suficiente e
é gerenciada automaticamente pelo framework do Android. Por exemplo, uma visualização de
um Button
é focalizável por padrão e a navegação pelo teclado geralmente
funciona sem nenhum código adicional. Para ativar a navegação pelo teclado para
visualizações que não são focalizáveis por padrão, os desenvolvedores precisam marcá-las como
focalizáveis. Isso pode ser feito de maneira programática ou em XML, conforme mostrado abaixo. Consulte a documentação de
Processamento de foco
para mais informações.
Kotlin
yourView.isFocusable = true
Java
yourView.setFocusable(true);
Como alternativa, você pode definir o atributo focusable
no arquivo de layout:
android:focusable="true"
Depois que o foco é ativado, o framework do Android cria um mapeamento de navegação para todas as visualizações focalizáveis com base na posição delas. Isso geralmente funciona conforme o esperado, e não é necessário realizar qualquer outra ação. Quando o mapeamento padrão não está correto para as necessidades de um app, ele pode ser substituído da seguinte maneira:
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);
É recomendável tentar acessar todas as funcionalidades do app antes de cada lançamento, usando apenas o teclado. Facilite o acesso às ações mais comuns sem o mouse ou a entrada de toque.
Lembre-se de que a compatibilidade com o teclado pode ser essencial para usuários com necessidades de acessibilidade.
Pressionamentos de tecla
Para entrada de texto que seria processada por um teclado virtual na tela
(IME) como um EditText
,
os apps devem se comportar como esperado no Chrome OS sem trabalho adicional do
desenvolvedor. Para pressionamentos de tecla que não podem ser previstos pelo framework, os apps
precisarão lidar com o comportamento. Isso ocorre especialmente em apps
com visualizações personalizadas.
Alguns exemplos são apps de chat que usam a tecla Enter para enviar uma mensagem, apps de mídia que iniciam/interrompem a reprodução com a tecla de espaço e jogos que controlam o movimento com as teclas w, a, s e d.
A maioria dos apps modifica o evento onKeyUp e adiciona o comportamento esperado para cada código de tecla recebido, conforme mostrado abaixo.
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); } }
O uso de onKeyUp
impede que os apps recebam vários eventos se uma chave for mantida
pressionada ou liberada lentamente. Jogos e apps que precisam da funcionalidade de manter as teclas de teclado pressionadas
podem procurar o evento
onKeyDown.
Ao adicionar compatibilidade com teclado, siga a documentação de processamento do teclado do Android.
Atalhos
Os atalhos comuns Ctrl, Alt e Shift são esperados em ambientes de computador. Se um app não os implementar, a experiência dos usuários poderá ser frustrante e interrompida. Além disso, atalhos para tarefas específicas usadas com frequência agradam usuários avançados. Os atalhos facilitam o uso e a diferenciação de apps que não têm atalhos.
Alguns atalhos comuns incluem Ctrl + S (salvar), Ctrl + Z (desfazer) e Ctrl + Shift + Z (refazer). Para ver um exemplo de alguns atalhos mais avançados, consulte a lista de teclas de atalho do player de mídia VLC (link em inglês).
Os atalhos podem ser implementados usando dispatchKeyShortcutEvent. Isso intercepta todas as combinações de tecla meta (Alt, Ctrl e Shift) para um determinado código de tecla. Para verificar se há uma tecla meta específica, use KeyEvent.isCtrlPressed(), KeyEvent.isShiftPressed(), KeyEvent.isAltPressed() ou KeyEvent.hasModifiers().
A separação do código de atalho de outro processo de pressionamento de tecla (como onKeyUp
ou
onKeyDown
) pode facilitar a manutenção do código e mantém a aceitação
padrão das teclas meta sem ter que implementar manualmente as verificações de tecla meta em todos os casos.
Permitir todas as combinações de tecla meta também pode ser mais conveniente para usuários acostumados com diferentes layouts de teclado e sistemas operacionais.
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); }
Você também pode implementar atalhos em onKeyUp
pela verificação de
KeyEvent.isCtrlPressed(),
KeyEvent.isShiftPressed()
ou KeyEvent.isAltPressed()
como explicado acima. Isso pode ser mais fácil de manter se o comportamento meta
for mais uma modificação em um comportamento do app do que um atalho. Por exemplo, quando
W significa "avançar" e Shift + W significa "avançar correndo".
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); }
Compatibilidade com mouse e touchpad
O Chrome OS processa automaticamente a maioria dos eventos do mouse e do trackpad para que eles funcionem como eventos de toque em um smartphone Android. Isso inclui rolagem com dois dedos no touchpad/roda do mouse. Geralmente, a maioria dos apps geralmente precisa processar apenas três eventos voltados para computadores: clicar com o botão direito do mouse, passar o cursor e arrastar e soltar.
Clicar com o botão direito
Todas as ações que fazem com que um app mostre um menu de contexto, como manter pressionado um
item de lista, também precisam reagir a eventos de clique com o botão direito do mouse. Para gerenciar eventos de clique com o botão direito do mouse,
os apps precisam registrar um
View.OnContextClickListener
.
Para detalhes sobre como criar um menu de contexto, consulte a
documentação do menu de contexto do Android
Kotlin
yourView.setOnContextClickListener { showContextMenu() true }
Java
yourView.setOnContextClickListener(v -> { showContextMenu(); return true; });
Passar cursor
Os desenvolvedores podem fazer com que seus layouts de apps pareçam bem-acabados e fáceis de usar pelo processamento de eventos de passar o cursor. Isso é especialmente verdadeiro para visualizações personalizadas. Os dois exemplos mais comuns são:
- indicar aos usuários se um elemento tem comportamento interativo, clicável ou editável, mudando o ícone do ponteiro do mouse;
- adicionar feedback visual a itens em uma grade ou lista grande quando o ponteiro do mouse estiver sobre eles.
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; });
Arrastar e soltar
Em um ambiente de várias janelas, os usuários esperam poder arrastar e soltar itens entre apps. Isso é válido para dispositivos Chrome OS, bem como tablets, smartphones e dispositivos dobráveis no modo de tela dividida.
Os desenvolvedores precisam considerar se os usuários arrastarão itens para o app. Alguns exemplos comuns incluem: editores de fotos provavelmente receberão fotos, players de áudio receberão arquivos de áudio e programas de desenho receberão imagens.
Para adicionar compatibilidade ao recurso de arrastar e soltar, siga a documentação do recurso de arrastar e soltar do Android e confira esta postagem do blog do Chrome OS (em inglês).
Considerações especiais para o Chrome OS
- Para processar arquivos no app Arquivos do Chrome OS, procure o tipo MIME
application/x-arc-uri-list
. - Lembre-se de solicitar permissão usando
requestDragAndDropPermissions
para acessar itens arrastados de fora do app. - Um item precisa ter a sinalização
View.DRAG_FLAG_GLOBAL
para ser arrastado para outros apps.
Compatibilidade avançada com ponteiro
Os apps que fazem o processamento avançado da entrada do mouse e do touchpad precisam seguir a
documentação do Android para
View.onGenericMotionEvent()
e usar MotionEvent.getSource()
para distinguir entre
SOURCE_MOUSE e
SOURCE_TOUCHSCREEN.
Examine o MotionEvent
para implementar o comportamento necessário:
- O movimento gera eventos de
ACTION_HOVER_MOVE
. - Os botões geram eventos de
ACTION_BUTTON_PRESS
eACTION_BUTTON_RELEASE
. Também é possível verificar o estado atual de todos os botões do mouse/trackpad usandogetButtonState()
. - A rolagem da roda do mouse gera eventos
ACTION_SCROLL
.
Stylus
Muitos Chromebooks vêm com uma stylus, e os apps Android gerenciam isso como entrada touchscreen. Alguns dispositivos também podem ter uma prancheta de desenho USB ou Bluetooth, como o Wacom Intuos (em inglês). Os apps para Android podem receber entradas por Bluetooth, mas não funcionam com a entrada USB.
Um evento da stylus é relatado como um evento de touchscreen via
View.onTouchEvent()
ou View.onGenericMotionEvent()
e
contém um
MotionEvent.getSource()
do tipo SOURCE_STYLUS.
O MotionEvent
também conterá dados adicionais:
- MotionEvent.getToolType() retornará TOOL_TYPE_FINGER, TOOL_TYPE_STYLUS ou TOOL_TYPE_ERASER, dependendo da ferramenta que fez o contato com a superfície.
- MotionEvent.get Pressure() informará a pressão física aplicada à stylus, se compatível.
- MotionEvent.getAxisValue() com MotionEvent.AXIS_TILT e MotionEvent.AXIS_ORIENTATION que podem ser usados para ler a inclinação física e a orientação, se compatíveis.
Pontos históricos
O Android agrupa eventos de entrada e os envia uma vez por frame. Uma stylus
pode relatar eventos em frequências muito maiores do que a tela. Ao criar
apps de desenho, é importante verificar eventos que podem estar no passado recente
usando as APIs getHistorical
:
MotionEvent.getHistoricalX()
MotionEvent.getHistoricalY()
MotionEvent.getHistoricalPressure()
MotionEvent.getHistoricalAxisValue()
Rejeição da palma da mão
O Chrome OS tenta reconhecer quando a palma da mão de um usuário está apoiada na tela touchscreen. No entanto, isso nem sempre é possível. Às vezes, um evento de toque pode
ser relatado ao app antes que o SO o reconheça como uma palma. Nesse caso,
os toques serão cancelados relatando um evento de ACTION_CANCEL
.
Esse evento informa ao app que determinados toques são inválidos e que é necessário desfazer todas as interações causadas por eles. Por exemplo, um app de desenho pode desenhar temporariamente novas linhas assim que elas forem recebidas para fornecer a menor latência, mas só as confirmará permanentemente na tela quando a série de toques estiver claramente concluída. Se os eventos de toque forem cancelados, as linhas temporárias poderão ser facilmente apagadas.
Apps de anotações
O Chrome OS tem uma intent especial que exibe apps de anotações registrados para os usuários. Para registrar um app como de anotações, adicione o seguinte ao manifesto do Android:
<intent-filter>
<action android:name="org.chromium.arc.intent.action.CREATE_NOTE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
Quando um app é registrado, o usuário pode selecioná-lo como o app de anotações
padrão. Quando uma nova anotação for solicitada, o app precisará criar uma nota vazia pronta
para entrada da stylus. Quando o usuário quiser anotar uma imagem (como uma captura de tela
ou imagem salva), o app será iniciado com ClipData
contendo um
ou mais itens com URIs content://
. O app precisa criar uma nota que use
a primeira imagem anexada como uma imagem de plano de fundo e entrar em um modo em que o usuário pode
desenhar com uma stylus.
Testar intents de anotações sem stylus
Para testar se um app responde corretamente a intents de anotação sem uma stylus ativa, use o seguinte método para exibir as opções de anotação:
- Alterne para o modo de desenvolvedor e torne o dispositivo gravável.
- Pressione Ctrl + Alt + F2 para abrir um terminal.
- Execute o comando
sudo vi /etc/chrome_dev.conf
. - Pressione
i
para editar e adicionar--ash-enable-palette
a uma nova linha no final do arquivo. - Salve pressionando Esc e digitando :, w, q e pressionando Enter.
- Pressione Ctrl + Alt + F1 para retornar à IU normal do Chrome OS.
- Saia e faça login novamente.
Agora você verá um menu da stylus na estante:
- Toque no botão da stylus na estante e escolha Nova nota. Isso deve abrir uma nota de desenho em branco.
- Faça uma captura de tela. Na estante, selecione botão de stylus > Capturar tela ou faça o download de uma imagem. Deve haver a opção "Anotar imagem" na notificação. Isso deve iniciar o app com a imagem pronta para ser anotada.
Controles de jogos
Os Chromebooks são compatíveis com até quatro controles de jogos. Os desenvolvedores precisam usar as APIs de controle de jogos padrão do Android para processar esses controles.
Os botões são mapeados para valores comuns após um mapeamento comum. Infelizmente, nem todos os fabricantes de controles de jogos seguem as mesmas convenções de mapeamento. Você pode fornecer uma experiência muito melhor se permitir que os usuários selecionem mapeamentos de controles mais usados.
Modo de tradução de entrada
O Chrome OS ativa um modo de tradução de entrada por padrão. Para a maioria dos apps Android, esse modo os ajuda a funcionar como esperado em um ambiente de computador. Alguns exemplos incluem ativar automaticamente a rolagem com dois dedos no touchpad, a rolagem da roda do mouse e o mapeamento de coordenadas de exibição brutas para coordenadas de janela. Geralmente, os desenvolvedores de apps não precisam implementar nenhum desses comportamentos.
Se um app implementar um comportamento de entrada personalizado, por exemplo, definir uma ação personalizada de gesto de pinça com dois dedos ou se essas traduções de entrada não fornecerem os eventos de entrada esperados pelo app, você poderá desativar o modo de tradução de entrada adicionando a seguinte tag ao manifesto do Android:
<uses-feature
android:name="android.hardware.type.pc"
android:required="false" />