Compatibilità degli input con schermi di grandi dimensioni

Sui dispositivi con schermi di grandi dimensioni, gli utenti interagiscono più spesso con le app utilizzando tastiera, mouse, trackpad, stilo o gamepad. Per consentire alla tua app di accettare input da dispositivi esterni, procedi nel seguente modo:

  • Testare il supporto di base della tastiera, ad esempio la navigazione da tastiera con tasti Tab e Freccia, Conferma di inserimento del testo con il tasto Invio e riproduzione/pausa della barra spaziatrice nelle app multimediali
  • Se possibile, aggiungi scorciatoie da tastiera standard. Ad esempio, premi Ctrl + Z per annullare e Ctrl + S per salvare.
  • Testa le interazioni di base con il mouse facendo clic con il tasto destro del mouse per il menu contestuale, le modifiche delle icone al passaggio del mouse e gli eventi di scorrimento della rotellina del mouse o del trackpad nelle visualizzazioni personalizzate
  • Testa dispositivi di input specifici per app, ad esempio uno stilo per app di disegno, controller di gioco per i giochi e controller MIDI per le app di musica
  • Prendi in considerazione il supporto avanzato dell'input che potrebbe far risaltare l'app in ambienti desktop; ad esempio, il touchpad come cross-fader per le app per DJ, l'acquisizione con il mouse per i giochi e numerose scorciatoie da tastiera per gli utenti che utilizzano la tastiera

Tastiera

La risposta dell'app all'input della tastiera contribuisce a offrire una buona esperienza su schermi grandi. Esistono tre tipi di input da tastiera: navigazione, sequenze di tasti e scorciatoie.

La navigazione da tastiera viene implementata raramente nelle app incentrate sul tocco, ma gli utenti si aspettano che sia in uso un'app e hanno le mani sulla tastiera. Inoltre, può essere essenziale per gli utenti con esigenze di accessibilità su telefoni, tablet, pieghevoli e desktop.

Per molte app è sufficiente utilizzare un semplice tasto freccia e una navigazione mediante schede, che viene gestita in gran parte automaticamente dal framework Android. Ad esempio, per impostazione predefinita è possibile attivare la visualizzazione di un elemento Button e la navigazione da tastiera in genere dovrebbe funzionare senza codice aggiuntivo. Per abilitare la navigazione da tastiera per le viste non attivabili per impostazione predefinita, gli sviluppatori dovrebbero contrassegnarle come attivabili, operazione che può essere eseguita in modo programmatico o in XML, come mostrato di seguito. Per ulteriori informazioni, consulta Gestione della messa a fuoco.

Kotlin

yourView.isFocusable = true

Java

yourView.setFocusable(true);

In alternativa, puoi impostare l'attributo focusable nel file di layout:

android:focusable="true"

Una volta attivato l'elemento attivo, il framework Android crea una mappatura di navigazione per tutte le viste attivabili in base alla loro posizione. Questo di solito funziona come previsto e non sono necessarie ulteriori azioni. Quando il mapping predefinito non è corretto per le esigenze di un'app, puoi eseguirne l'override come segue:

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);

È buona norma provare ad accedere a tutte le funzionalità dell'app prima di ogni release utilizzando soltanto la tastiera. Le azioni più comuni dovrebbero essere facilmente accessibili senza dover usare il mouse o il tocco.

Ricorda che il supporto della tastiera potrebbe essere essenziale per gli utenti con esigenze di accessibilità.

Sequenze di tasti

Per l'input di testo gestito da una tastiera virtuale sullo schermo (IME), ad esempio EditText, le app dovrebbero comportarsi come previsto sui dispositivi con schermi di grandi dimensioni senza alcun intervento aggiuntivo da parte dello sviluppatore. Per le sequenze di tasti che non possono essere previste dal framework, le app devono gestire autonomamente il comportamento. Questo vale in particolar modo per le app con visualizzazioni personalizzate.

Alcuni esempi sono le app di chat che utilizzano il tasto Invio per inviare un messaggio, le app multimediali che avviano e interrompono la riproduzione con la barra spaziatrice e i giochi che controllano il movimento con i tasti W, A, S e D.

La maggior parte delle app ignora il callback onKeyUp() e aggiunge il comportamento previsto per ogni codice chiave ricevuto, come mostrato di seguito:

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);
    }
}

Si verifica un evento onKeyUp al rilascio di una chiave. L'utilizzo di questo callback impedisce alle app di elaborare più eventi onKeyDown se un tasto viene tenuto premuto o rilasciato lentamente. I giochi e le app che vogliono sapere quando viene premuto un tasto o che si aspettano che gli utenti tengano premuti i tasti della tastiera possono cercare l'evento onKeyDown() e gestire autonomamente gli eventi onKeyDown ripetuti.

Per maggiori informazioni su come fornire supporto per la tastiera, vedi Gestire le azioni da tastiera.

Scorciatoie

Le scorciatoie comuni basate su Ctrl, Alt e Maiusc sono previste quando si utilizza una tastiera hardware. Se non vengono implementate in un'app, l'esperienza può risultare frustrante per gli utenti. Gli utenti esperti apprezzano le scorciatoie per le attività specifiche delle app usate di frequente. Le scorciatoie rendono un'app più facile da usare e la distinguono da quelle che non le hanno.

Alcune scorciatoie comuni includono Ctrl + S (salva), Ctrl + Z (annulla) e Ctrl + Maiusc + Z (ripeti). Per un esempio di scorciatoie più avanzate, consulta l'elenco dei tasti di scelta rapida per VLC Media Player.

Le scorciatoie possono essere implementate utilizzando dispatchKeyShortcutEvent(). In questo modo intercetta tutte le combinazioni di meta-chiave (Alt, Ctrl e Maiusc) per un determinato codice chiave. Per verificare la presenza di una meta-chiave specifica, utilizza KeyEvent.isCtrlPressed(), KeyEvent.isShiftPressed(), KeyEvent.isAltPressed() o KeyEvent.hasModifiers().

La separazione del codice della scorciatoia da altre operazioni di gestione della sequenza di tasti (come onKeyUp() e onKeyDown()) può semplificare la manutenzione del codice e consente l'accettazione predefinita delle meta-chiavi senza dover implementare manualmente in ogni caso controlli delle meta-chiavi. Consentire tutte le combinazioni di meta-chiave può anche essere più pratico per gli utenti che sono abituati a layout di tastiera e sistemi operativi diversi.

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);
}

Puoi anche implementare le scorciatoie in onKeyUp() controllando KeyEvent.isCtrlPressed(), KeyEvent.isShiftPressed() o KeyEvent.isAltPressed() come indicato sopra. Questo può essere più facile da gestire se il meta-comportamento è più una modifica del comportamento di un'app che di una scorciatoia. Ad esempio, quando W significa "cammina avanti" e Maiusc + W significa "corri avanti".

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);
}

Stilo

Molti dispositivi con schermi di grandi dimensioni sono dotati di uno stilo e le app Android lo gestiscono come input touchscreen. Alcuni dispositivi potrebbero anche avere una tabella da disegno USB o Bluetooth, come la Wacom Intuos. Le app Android possono ricevere input Bluetooth, ma non funzionano con un input USB.

Un evento con lo stilo viene segnalato come evento touchscreen tramite View.onTouchEvent() o View.onGenericMotionEvent() e contiene un MotionEvent.getSource() di tipo SOURCE_STYLUS.

MotionEvent conterrà anche dati aggiuntivi:

Punti storici

Android raggruppa gli eventi di input e li pubblica una volta per frame. Uno stilo può segnalare eventi a frequenze molto più elevate rispetto al display. Durante la creazione di app di disegno, è importante verificare la presenza di eventi che potrebbero essere nel passato recente utilizzando le API getHistorical:

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

Rifiuto del palmo

Quando gli utenti disegnano, scrivono o interagiscono con la tua app usando uno stilo, a volte toccano lo schermo con il palmo delle mani. L'evento di tocco (impostato su ACTION_DOWN o ACTION_POINTER_DOWN) può essere segnalato alla tua app prima che il sistema riconosca e ignori il tocco involontario con il palmo.

Android annulla gli eventi di tocco con il palmo inviando un MotionEvent. Se la tua app riceve ACTION_CANCEL, annulla il gesto. Se la tua app riceve ACTION_POINTER_UP, controlla se è impostato FLAG_CANCELED. In tal caso, annulla il gesto.

Non controllare solo per FLAG_CANCELED. A partire da Android 13, per praticità, il sistema imposta FLAG_CANCELED per gli eventi ACTION_CANCEL, al contrario delle versioni precedenti.

Android 12

Su Android 12 (livello API 32) e versioni precedenti, il rilevamento del rifiuto del palmo è possibile solo per gli eventi di tocco a puntatore singolo. Se l'unico puntatore è il tocco con il palmo, il sistema annulla l'evento impostando ACTION_CANCEL sull'oggetto evento di movimento. Se gli altri puntatori sono abbassati, il sistema imposta ACTION_POINTER_UP, che non è sufficiente per rilevare il rifiuto del palmo.

Android 13

Su Android 13 (livello API 33) e versioni successive, se il tocco è l'unico puntatore, il sistema annulla l'evento impostando ACTION_CANCEL e FLAG_CANCELED sull'oggetto evento di movimento. Se gli altri puntatori sono rivolti verso il basso, il sistema imposta ACTION_POINTER_UP e FLAG_CANCELED.

Ogni volta che la tua app riceve un evento di movimento con ACTION_POINTER_UP, controlla la presenza di FLAG_CANCELED per determinare se l'evento indica il rifiuto del palmo (o l'annullamento di un altro evento).

App per creare note

ChromeOS ha uno scopo speciale per mostrare agli utenti le app per scrivere note. Per registrare un'app come app per scrivere note, aggiungi quanto segue al file manifest Android:

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

Quando un'app è registrata, l'utente può selezionarla come app predefinita per scrivere note. Quando viene richiesta una nuova nota, l'app deve crearne una vuota pronta per l'inserimento dello stilo. Quando l'utente vuole aggiungere annotazioni a un'immagine (ad esempio uno screenshot o un'immagine scaricata), l'app si avvia con ClipData contenente uno o più elementi con URI content://. L'app deve creare una nota che utilizza la prima immagine allegata come immagine di sfondo e attivare una modalità in cui l'utente possa disegnare sullo schermo con uno stilo.

Testare gli intent di creazione di note senza stilo

Per verificare se un'app risponde correttamente agli intent per la creazione di note senza uno stilo attivo, utilizza il seguente metodo per visualizzare le opzioni per la creazione di note su ChromeOS:

  1. Passa alla modalità sviluppatore e rendi il dispositivo scrivibile
  2. Premi Ctrl + Alt + F2 per aprire un terminale
  3. Esegui il comando sudo vi /etc/chrome_dev.conf
  4. Premi i per modificare e aggiungere --ash-enable-palette a una nuova riga alla fine del file
  5. Salva premendo Esc e poi digitando :, w, q e premendo Invio
  6. Premi Ctrl + Alt + F1 per tornare alla normale UI di ChromeOS
  7. Esci e accedi di nuovo

A questo punto, nella barra delle app dovrebbe essere presente un menu con lo stilo:

  • Tocca il pulsante dello stilo nella barra delle app e scegli Nuova nota. Dovrebbe aprirsi una nota di disegno vuota.
  • Fai uno screenshot. Dalla barra delle app, seleziona pulsante stilo > Acquisisci schermata o scarica un'immagine. Nella notifica dovrebbe essere presente l'opzione "Annota l'immagine". L'app dovrebbe essere avviata con l'immagine pronta per essere annotata.

Supporto per mouse e touchpad

In genere, la maggior parte delle app deve gestire solo tre eventi incentrati sugli schermi di grandi dimensioni: clic con il tasto destro del mouse, passaggio del mouse e trascinamento.

Clic destro

Tutte le azioni che comportano la visualizzazione di un menu contestuale da parte di un'app, come toccare e tenere premuto su un elemento dell'elenco, dovrebbero anche reagire agli eventi di clic con il tasto destro del mouse. Per gestire gli eventi di clic con il tasto destro del mouse, le app devono registrare un View.OnContextClickListener. Per maggiori dettagli sulla creazione di un menu contestuale, consulta Creazione di menu contestuali.

Kotlin

yourView.setOnContextClickListener {
  showContextMenu()
  true
}

Java

yourView.setOnContextClickListener(v -> {
    showContextMenu();
    return true;
});

Passaggio

Gli sviluppatori possono rendere i layout delle loro app più curati e più facili da usare gestendo gli eventi di passaggio del mouse. Ciò è particolarmente vero per le visualizzazioni personalizzate. I due esempi più comuni sono:

  • Indicare agli utenti se un elemento ha un comportamento interattivo, come selezionabile o modificabile, modificando l'icona del puntatore del mouse
  • Aggiunta di feedback visivi agli elementi di un elenco o una griglia di grandi dimensioni quando il puntatore vi passa sopra

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;
});

Trascina

In un ambiente multi-finestra, gli utenti si aspettano di poter trascinare elementi da un'app all'altra. Questo vale sia per i computer, sia per i tablet, i telefoni e i pieghevoli in modalità schermo diviso.

Gli sviluppatori dovrebbero valutare la probabilità che gli utenti trascinino elementi nell'app. Alcuni esempi comuni sono: gli editor di foto devono ricevere foto, i lettori audio devono ricevere file audio e i programmi di disegno dovrebbero ricevere foto.

Per aggiungere il supporto del trascinamento, segui la documentazione di Android relativa al trascinamento e dai un'occhiata a questo post del blog di ChromeOS.

Considerazioni speciali per ChromeOS

  • Ricorda di richiedere l'autorizzazione tramite requestDragAndDropPermissions per accedere agli elementi trascinati dall'esterno dell'app
  • Un elemento deve avere il flag View.DRAG_FLAG_GLOBAL per essere trascinato fuori in altre applicazioni

Supporto puntatore avanzato

Le app che eseguono la gestione avanzata dell'input tramite mouse e touchpad devono seguire la documentazione di Android per View.onGenericMotionEvent() e utilizzare MotionEvent.getSource() per distinguere tra SOURCE_MOUSE e SOURCE_TOUCHSCREEN.

Esamina il MotionEvent per implementare il comportamento richiesto:

  • Il movimento genera ACTION_HOVER_MOVE eventi.
  • I pulsanti generano eventi ACTION_BUTTON_PRESS e ACTION_BUTTON_RELEASE. Puoi anche controllare lo stato corrente di tutti i pulsanti del mouse/del trackpad utilizzando getButtonState().
  • Lo scorrimento con la rotellina del mouse genera ACTION_SCROLL eventi.

Controller di gioco

Alcuni dispositivi Android con schermi grandi supportano fino a quattro controller di gioco. Gli sviluppatori devono utilizzare le API standard per i controller di gioco per Android per gestirle (vedi Supporto per i controller di gioco).

I pulsanti sono associati a valori comuni seguendo una mappatura comune. Purtroppo, non tutti i produttori di controller di gioco seguono le stesse convenzioni di mappatura. Puoi offrire un'esperienza di gran lunga migliore se consenti agli utenti di selezionare diverse mappature dei controller più comuni. Per ulteriori informazioni, consulta Pressione dei pulsanti del gamepad.

Modalità di traduzione dell'input

ChromeOS attiva una modalità di traduzione dell'input per impostazione predefinita. Per la maggior parte delle app Android, questa modalità consente alle app di funzionare come previsto in un ambiente desktop. Alcuni esempi includono l'attivazione automatica dello scorrimento con due dita sul touchpad, lo scorrimento con la rotellina del mouse e la mappatura delle coordinate del display non elaborate alle coordinate della finestra. In genere, gli sviluppatori di app non devono implementare nessuno di questi comportamenti.

Se un'app implementa un comportamento di input personalizzato, ad esempio definisce un'azione personalizzata di pizzicatura del touchpad con due dita, o queste traduzioni di input non forniscono gli eventi di input previsti dall'app, puoi disattivare la modalità di traduzione dell'input aggiungendo il seguente tag al file manifest Android:

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

Risorse aggiuntive