Compatibilidade de entrada para Chromebooks

Os usuários de laptops costumam usar dispositivos de entrada diferentes de smartphones.

Quando são executados em Chromebooks, os apps para Android encontram-se em um ambiente para o qual não foram projetados, exibidos dentro de uma janela de um laptop com mouse, touchpad e teclado. Embora o Android seja compatível com esses dispositivos, eles raramente são implementados corretamente em apps. Para que esses apps funcionem, os Chromebooks usam um modo de compatibilidade válido para todos os apps por padrão.

Modo de compatibilidade

No modo de compatibilidade, seu app receberá eventos de maneira diferente da forma como eles são fornecidos por APIs do Android. Esse modo é útil para desenvolvedores que não querem implementar recursos específicos do Chromebook, mas querem que o app centrado em toque funcione.

O modo de compatibilidade apresenta os seguintes comportamentos:

  • A rolagem do touchpad pode imitar a rolagem na tela touchscreen com dois "dedos".
  • A rolagem da roda do mouse pode fazer o mesmo.
  • Todas as medições e eventos se comportam como se a janela do app fosse exibida em tela cheia. Métodos como getRawX e getRawY não retornam coordenadas de exibição e espaço, mas de janela e espaço.

Dependendo do nível de API segmentado pelo app, o modo de compatibilidade oferece mais ou menos desses tratamentos.

Usar android.hardware.type.pc

Se você quer otimizar seu app para ser executado em Chromebooks e fazer bom uso dos dispositivos de entrada, declare o seguinte no manifesto do app:

<uses-feature
        android:name="android.hardware.type.pc"
        android:required="false" />
    

Isso diz ao Android que você está segmentando computadores que normalmente são usados com teclado, mouse e touchpad. Essa declaração desativa o modo de compatibilidade e permite desenvolver um comportamento personalizado para mouse e touchpad.

Cuidado com DecorCaptionView

No modo de janela de forma livre, a barra de legenda dos apps faz parte da sua hierarquia de visualizações e está sob seu controle. Em geral, você não precisa dessa informação, mas há casos em que é necessário ter cuidado:

  • Não mexa em Window.getDecorView(). Se você quer adicionar visualizações de nível superior, adicione-as à visualização definida como Activity.setContentView().
  • Não espere que Activity.setContentView() esteja em (0, 0) do app. Esse é o lugar da barra de legenda.
  • Se possível, evite usar MotionEvent.getRawX() ou MotionEvent.getRawY(). Se você usá-los, combine-os com View.getLocationOnScreen() para transformar coordenadas em coordenadas de visualização e espaço.

Compatibilidade com dispositivos de entrada

Ao segmentar computadores por meio da sinalização android.hardware.type.pc, os seguintes eventos são exibidos:

Compatibilidade com mouse e touchpad

O mouse e o touchpad geram MotionEvents da mesma forma que os eventos de toque. Verifique MotionEvent.getSource() para distinguir entre SOURCE_MOUSE e SOURCE_TOUCHSCREEN.

  • Movimento do mouse/touchpad: gera eventos ACTION_HOVER_MOVE, que são processados em View.onGenericMotionEvent().
  • Botões do mouse/touchpad: enviam eventos ACTION_BUTTON_PRESS e ACTION_BUTTON_RELEASE para View.onGenericMotionEvent(). Você também pode verificar se há botões pressionados em todos os eventos do mouse/touchpad por meio de getButtonState().
  • Rolagem do touchpad: a rolagem com dois dedos no touchpad é relatada de maneira semelhante aos eventos de arrastar na tela touchscreen para permitir uma rolagem suave e cinética. Se você quer que os comportamentos da ação de arrastar na tela touchscreen e da ação de rolar no touchpad sejam diferentes, use getSource().
  • Rolagem da roda do mouse: a rolagem com a roda do mouse é relatada como eventos ACTION_SCROLL para View.onGenericMotionEvent().
  • Ação de clicar e arrastar com o mouse/touchpad: os eventos de clicar e arrastar são muito semelhantes aos eventos de arrastar na tela touchscreen. Use getButtonState() para distinguir a ação de clicar e arrastar de um evento de rolagem no touchpad. A ação de clicar e arrastar será sempre acompanhada por um botão, ao contrário da rolagem do touchpad.

Compatibilidade com clique com o botão direito do mouse

Para processar eventos de clique com o botão direito do mouse, conhecidos também como eventos de clique de contexto, basta configurar uma View.OnContextClickListener para sua visualização.

Kotlin

    yourView.setOnContextClickListener {
        //display context click options
        true
    }
    

Java

    yourView.setOnContextClickListener(new View.OnContextClickListener() {
    @Override
      public boolean onContextClick(View view) {
        //display context click options
        return true;
      }
    });
    

Esse método foi adicionado à API nível 23. Sendo assim, se você quer permitir a mesma funcionalidade em outros dispositivos que possam executar uma versão mais antiga do Android, use eventos de movimento genéricos, conforme mostrado acima.

Teclado

A entrada de teclado é importante em computadores e laptops. Ela também é extremamente necessária para acessibilidade.

Para realizar a ativação correta do foco de entrada, siga as adições de recursos normais, conforme descrito na API Android padrão:

  • Se você quer processar a entrada do teclado por conta própria, use as funções padrão por meio de KeyEvent.callback. Não há necessidade de processar a entrada de teclado dentro de um elemento TextEdit.
  • Se você quer editar textos por conta própria, use eventos onKeyDown, onKeyLongPress e onKeyUp, mas não onKeyPreIME, a menos que queira implementar toda a capacidade do ambiente do IME (editor de método de entrada, na sigla em inglês), o que não é recomendado.

Stylus

Uma stylus relata eventos de maneira semelhante a uma tela touchscreen por meio de View.onTouchEvent(). No entanto, os eventos da stylus contêm mais informações que devem ser consideradas:

  • MotionEvent.getToolType(). O tipo de ferramenta permite distinguir eventos TOOL_TYPE_FINGER de TOOL_TYPE_STYLUS. Ele também permite reconhecer o uso do lado da borracha de uma caneta, se existir, por meio de TOOL_TYPE_ERASER.
  • MotionEvent.getPressure(). Representa a pressão física aplicada à stylus, se compatível.
  • MotionEvent.AXIS_TILT/AXIS_ORIENTATION. Pode ser usado com MotionEvent.getAxisValue() para ler a inclinação física e a orientação da stylus, se compatível.

Pontos históricos

O Android agrupa os eventos de entrada a serem entregues uma vez por frame. No entanto, uma caneta stylus pode gerar relatórios em frequências muito mais altas (200 Hz, por exemplo, é bastante comum). Ao criar apps de desenho, é importante usar os pontos adquiridos a partir da API histórica:

  • MotionEvent.getHistoricalX()
  • MotionEvent.getHistoricalY()
  • MotionEvent.getHistoricalPressure()
  • MotionEvent.getHistoricalAxisValue()

Rejeição da palma da mão

O Chrome OS tenta reconhecer a palma da mão em repouso para que ela nunca seja relatada ao app. No entanto, isso nem sempre é possível. Um toque pode ser relatado antes de o SO reconhecê-lo como uma palma. Nesse caso, os toques serão cancelados relatando um evento ACTION_CANCEL.

Esse evento diz ao app que todos os toques são inválidos e que ele deve desfazer todas as interações resultantes. Por exemplo, no caso de apps de desenho, o app desenhará novas linhas temporariamente e as enviará para a tela somente quando a série de toques estiver claramente concluída. Se o toque for cancelado, essa linha temporária poderá ser facilmente removida.

Intent de anotação

O Chrome OS exibe uma lista de apps registrados para processar intents que contêm uma ação org.chromium.arc.intent.action.CREATE_NOTE e a categoria Intent.CATEGORY_DEFAULT (isto é, android.intent.category.DEFAULT), conforme exibido neste snippet de código:

  <intent-filter>
        <action android:name="org.chromium.arc.intent.action.CREATE_NOTE" />
        <category android:name="android.intent.category.DEFAULT" />
      </intent-filter>
    

O usuário poderá selecionar um app, que será iniciado mais tarde, quando um app para anotação for solicitado.

Quando o usuário pedir para criar uma nova nota, o app será iniciado com um intent que contém apenas a ação e a categoria mencionadas. O app deve criar uma nota vazia, em um modo no qual o usuário possa escrever usando uma stylus.

Quando o usuário pede para anotar um contexto de imagem (por exemplo, uma captura de tela ou imagem salva), o app é iniciado com um intent que contém a ação e categoria mencionadas, incluindo ClipData com um ou mais itens com URIs content://. O app deve criar uma nota que use a primeira imagem anexada como imagem de plano de fundo em um modo no qual o usuário possa desenhar nela usando uma stylus.

Testar sem stylus

  1. Alterne para o modo de desenvolvedor e torne o dispositivo gravável.
  2. Pressione Ctrl+Alt+F2 (seta para frente) para abrir o shell.
  3. Execute o comando sudo vi /etc/chrome_dev.conf.
  4. Adicione --ash-enable-palette a uma nova linha no final do arquivo.
  5. Pressione Ctrl+Alt+F1 (seta para trás) para retornar à IU.
  6. Saia e faça login novamente.

Agora, você verá os pontos de entrada da stylus. Na estante, toque no botão da caneta e selecione "Nova nota". Isso deve abrir uma nota de desenho em branco no aplicativo. Se você fizer uma captura de tela (da estante: botão da stylus > Capturar tela) ou fizer o download de uma imagem, verá a opção "Nota na imagem" na notificação. Isso deve abrir seu app com a imagem pronta para ser anotada.

Gamepads

Os Chromebooks são compatíveis com até quatro gamepads e seguem APIs Android padrão para relatá-los. Infelizmente, é comum que os gamepads não projetados para Android mostrem o mapeamento do botão direito.