Compatibilité avec la saisie sur grand écran

Sur les appareils à grand écran, les utilisateurs interagissent souvent avec les applications à l'aide d'un clavier, d'une souris, d'un pavé tactile, d'un stylet ou d'une manette de jeu. Pour autoriser votre application à accepter les entrées provenant d'appareils externes, procédez comme suit :

  • Testez les fonctionnalités de base du clavier, comme la navigation via la touche de tabulation et des touches fléchées, la confirmation d'entrées de texte avec la touche Entrée, et l'utilisation de barre d'espace pour lire et mettre en pause le contenu dans les applications multimédias.
  • Ajoutez des raccourcis clavier standards, le cas échéant (par exemple, Ctrl+Z pour annuler et Ctrl+S pour enregistrer).
  • Testez les interactions de base de la souris telles que le clic droit pour afficher le menu contextuel, les modifications d'icône au passage de la souris, et l'utilisation de la molette ou du pavé tactile pour faire défiler les événements sur des vues personnalisées.
  • Testez les périphériques d'entrée spécifiques aux applications, comme le stylet pour dessiner des applications, des manettes de jeu et des télécommandes MIDI pour les applications musicales.
  • Envisagez de proposer des modes d'entrée avancés qui permettraient à l'application de se démarquer dans les environnements de bureau (par exemple, le pavé tactile comme fondu enchaîné pour les applications de DJ, la capture de souris pour les jeux et un large éventail de raccourcis clavier).

Clavier

La manière dont votre application réagit à la saisie au clavier contribue à une expérience de qualité sur grand écran. Il existe trois types de saisie au clavier : navigation, touches et raccourcis.

La navigation au clavier est rarement implémentée dans les applications centrées sur l'écran tactile, mais les utilisateurs s'y attendent lorsqu'ils utilisent une application et qu'ils ont un clavier à leur disposition. Elle peut également être essentielle pour les utilisateurs ayant des besoins d'accessibilité spécifiques sur les téléphones, les tablettes, les appareils pliables et les ordinateurs.

Pour de nombreuses applications, la navigation via les touches fléchées et la touche de tabulation suffit. Elle est en grande partie gérée automatiquement par le framework Android. Par exemple, une vue Button est sélectionnable par défaut, et la navigation au clavier devrait généralement fonctionner sans code supplémentaire. Afin d'activer la navigation au clavier pour les vues qui ne sont pas sélectionnables par défaut, les développeurs doivent les marquer comme telles, de manière programmatique ou au format XML, comme indiqué ci-dessous. Pour en savoir plus, consultez la section Focus Handling (Gestion des sélections).

Kotlin

yourView.isFocusable = true

Java

yourView.setFocusable(true);

Vous pouvez également définir l'attribut focusable dans le fichier de mise en page :

android:focusable="true"

Une fois la sélection activée, le framework Android crée un mappage de navigation de toutes les vues sélectionnables en fonction de leur position. Cela fonctionne généralement normalement. Aucun effort supplémentaire n'est donc nécessaire. Lorsque le mappage par défaut n'est pas adapté aux besoins d'une application, vous pouvez le remplacer comme suit :

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

Il est recommandé d'essayer d'accéder à toutes les fonctionnalités de votre application, avant sa compilation, à l'aide du clavier uniquement. Il devrait être facile d'accéder aux actions les plus courantes sans utiliser la souris ou la saisie tactile.

N'oubliez pas que le clavier peut être essentiel aux utilisateurs ayant des besoins d'accessibilité spécifiques.

Touches de clavier

Pour la saisie de texte qui serait gérée par un clavier virtuel à l'écran (IME) comme EditText, les applications devraient se comporter comme prévu sur les appareils à grand écran sans nécessiter d'efforts supplémentaires de la part du développeur. Pour les touches que le framework ne peut pas anticiper, les applications doivent gérer ce comportement elles-mêmes. Cela est particulièrement vrai pour les applications avec des vues personnalisées.

Il peut s'agir d'applications de chat qui utilisent la touche Entrée pour envoyer un message, d'applications multimédias qui lancent et arrêtent la lecture avec la barre d'espace, ou de jeux qui contrôlent le mouvement avec les touches w, a, s et d.

La plupart des applications ignorent le rappel onKeyUp() et ajoutent le comportement attendu pour chaque code clavier reçu, comme indiqué ci-dessous :

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

Un événement onKeyUp se produit lorsqu'une touche est libérée. L'utilisation de ce rappel évite aux applications de devoir traiter plusieurs événements onKeyDown si une clé est maintenue enfoncée ou si elle est libérée lentement. Les jeux et les applications qui souhaitent savoir à quel moment une touche est activée ou sur lesquels les utilisateurs doivent appuyer sur des touches du clavier peuvent rechercher l'événement onKeyDown() et gérer les événements onKeyDown répétés eux-mêmes.

Pour en savoir plus sur la compatibilité des claviers, consultez Handle keyboard actions (Gérer les actions du clavier).

Raccourcis

Les raccourcis Ctrl, Alt et Maj courants sont attendus lorsque vous utilisez un clavier physique. Si une application ne les implémente pas, l'expérience peut être frustrante pour les utilisateurs. Les utilisateurs avancés apprécient également les raccourcis pour les tâches fréquentes spécifiques aux applications. Les raccourcis contribuent à la facilité d'utilisation d'une application et la différencient de celles qui n'en ont pas.

Les raccourcis les plus courants sont Ctrl+S (Enregistrer), Ctrl+Z (Annuler) et Ctrl+Maj+Z (Répéter). Pour obtenir un exemple de raccourcis plus avancés, consultez la liste des touches de raccourci VLC Media Player.

Les raccourcis peuvent être mis en œuvre à l'aide de dispatchKeyShortcutEvent(). Toutes les combinaisons de méta-touches (Alt, Ctrl et Maj) sont alors interceptées pour un code clavier donné. Pour rechercher une méta-touche spécifique, utilisez KeyEvent.isCtrlPressed(), KeyEvent.isShiftPressed(), KeyEvent.isAltPressed() ou KeyEvent.hasModifiers().

La séparation du code de raccourci des autres méthodes de saisie au clavier (onKeyUp() et onKeyDown(), par exemple) facilite la maintenance du code et permet l'acceptation par défaut des méta-touches sans avoir à implémenter manuellement les vérifications des méta-touches dans tous les cas. L'autorisation de toutes les combinaisons de méta-touches est parfois également plus pratique pour les utilisateurs habitués à différentes configurations de clavier et systèmes d'exploitation.

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

Vous pouvez également implémenter des raccourcis dans onKeyUp() en recherchant KeyEvent.isCtrlPressed(), KeyEvent.isShiftPressed() ou KeyEvent.isAltPressed() comme ci-dessus. Cette approche est parfois plus facile à gérer si le méta-comportement correspond davantage à une modification d'un comportement d'application qu'à un raccourci (par exemple, lorsque "W" signifie "avancer en marchant" et "Maj+W" signifie "avancer en courant").

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

Stylet

De nombreux appareils à grand écran sont équipés d'un stylet, que les applications Android gèrent comme la saisie tactile. Certains appareils peuvent également disposer d'une table de dessin USB ou Bluetooth, comme Wacom Intuos. Les applications Android peuvent recevoir une entrée Bluetooth, mais ne fonctionnent pas avec les entrées USB.

Un événement de stylet est signalé comme événement tactile via View.onTouchEvent() ou View.onGenericMotionEvent(), et contient un objet MotionEvent.getSource() de type SOURCE_STYLUS.

MotionEvent contient également des données supplémentaires :

Points historiques

Android regroupe les événements d'entrée et les distribue une fois par frame. Un stylet peut signaler des événements avec une fréquence beaucoup plus élevée que l'écran. Lors de la création d'applications de dessin, il est important de rechercher les événements récents à l'aide des API getHistorical :

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

Refus de la paume de la main

Lorsque les utilisateurs dessinent, écrivent ou interagissent avec votre application à l'aide d'un stylet, ils touchent parfois l'écran avec la paume de leur main. L'événement tactile (défini sur ACTION_DOWN ou ACTION_POINTER_DOWN) peut être signalé à votre application avant que le système ne le reconnaisse et n'ignore la pression involontaire via la paume de la main.

Android annule les événements tactiles de la paume de la main en envoyant un MotionEvent. Si votre application reçoit ACTION_CANCEL, annulez le geste. Si votre application reçoit une erreur ACTION_POINTER_UP, vérifiez si FLAG_CANCELED est défini. Si c'est le cas, annulez le geste.

Ne recherchez pas uniquement FLAG_CANCELED. Depuis Android 13, pour plus de commodité, le système définit FLAG_CANCELED pour les événements ACTION_CANCEL, ce qui n'est pas le cas des versions précédentes.

Android 12

Sur Android 12 (niveau d'API 32) et versions antérieures, la détection du refus de la paume de la main n'est possible que pour les événements tactiles à un seul pointeur. Si une pression via la paume de la main est le seul pointeur, le système annule l'événement en définissant ACTION_CANCEL sur l'objet d'événement de mouvement. Si les autres pointeurs impliquent une pression, le système définit ACTION_POINTER_UP, ce qui est insuffisant pour détecter le refus de la paume de la main.

Android 13

Sur Android 13 (niveau d'API 33) ou version ultérieure, si une pression via la paume de la main est le seul pointeur, le système annule l'événement en définissant ACTION_CANCEL et FLAG_CANCELED sur l'objet d'événement de mouvement. Si les autres pointeurs impliquent une pression, le système définit ACTION_POINTER_UP et FLAG_CANCELED.

Chaque fois que votre application reçoit un événement de mouvement avec ACTION_POINTER_UP, recherchez FLAG_CANCELED pour déterminer si l'événement indique un refus de la paume de la main (ou une autre annulation d'événement).

Applications de prise de notes

ChromeOS utilise un intent spécial qui présente aux utilisateurs les applications de prise de notes inscrites en tant que telles. Pour inscrire une application en tant qu'application de prise de notes, ajoutez le code suivant au fichier manifeste Android :

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

Lorsqu'une application est inscrite, l'utilisateur peut la sélectionner comme application de prise de notes par défaut. Lorsqu'une nouvelle note est demandée, l'application doit créer une note vide prête à être saisie par le stylet. Lorsque l'utilisateur souhaite annoter une image (par exemple, une capture d'écran ou une image téléchargée), l'application se lance avec ClipData et contient un ou plusieurs éléments avec des URI content://. L'application doit créer une note qui utilise la première image jointe comme image d'arrière-plan et passer dans un mode permettant à l'utilisateur de dessiner à l'écran avec un stylet.

Tester les intents de prise de notes sans stylet

Pour vérifier si une application répond correctement aux intents de prise de notes sans stylet actif, utilisez la méthode suivante afin d'afficher les options de prise de notes sur ChromeOS :

  1. Activez le mode développeur et rendez l'appareil accessible en écriture.
  2. Appuyez sur Ctrl+Alt+F2 pour ouvrir un terminal.
  3. Exécutez la commande sudo vi /etc/chrome_dev.conf.
  4. Appuyez sur i pour effectuer des modifications, puis ajoutez --ash-enable-palette à une nouvelle ligne à la fin du fichier
  5. Pour enregistrer, appuyez sur Échap, puis saisissez :, w, q et appuyez sur Entrée.
  6. Appuyez sur Ctrl+Alt+F1 pour revenir à l'interface utilisateur ChromeOS standard.
  7. Déconnectez-vous, puis reconnectez-vous.

Un menu de stylet devrait maintenant s'afficher sur l'étagère :

  • Appuyez sur le bouton du stylet situé sur l'étagère, puis sélectionnez Nouvelle note. Une note de dessin vide devrait s'afficher.
  • Prenez une capture d'écran. À partir de l'étagère, sélectionnez Bouton du stylet > Capturer l'écran ou téléchargez une image. L'option "Annoter l'image" devrait s'afficher dans la notification. Celle-ci devrait lancer l'application avec l'image prête à être annotée.

Compatibilité avec la souris et le pavé tactile

La plupart des applications ne doivent généralement gérer que trois événements axés sur les grands écrans : effectuer un clic droit, pointer le curseur et glisser-déposer.

Effectuer un clic droit

Toutes les actions qui entraînent l'affichage d'un menu contextuel par une application, comme l'appui prolongé sur un élément de la liste, doivent également réagir aux événements de clic droit. Pour gérer ces événements, les applications doivent enregistrer un élément View.OnContextClickListener. Pour découvrir comment créer un menu contextuel, consultez Creating Contextual Menus (Créer des menus contextuels).

Kotlin

yourView.setOnContextClickListener {
  showContextMenu()
  true
}

Java

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

Pointer le curseur

Pour rendre leurs mises en page d'application plus fluides et plus faciles à utiliser, les développeurs peuvent gérer les événements de pointage. Cela est particulièrement vrai pour les vues personnalisées. Voici les deux exemples les plus courants :

  • Modifier l'icône du pointeur de la souris pour indiquer aux utilisateurs si un élément a un comportement interactif, par exemple s'il est cliquable ou modifiable
  • Ajouter un retour visuel aux éléments d'une longue liste ou grille lorsque le pointeur passe dessus

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

Glisser-déposer

Dans un environnement multifenêtre, les utilisateurs s'attendent à pouvoir glisser-déposer des éléments entre les applications. Cela est le cas pour les ordinateurs, les tablettes, les téléphones et les pliables en mode écran partagé.

Les développeurs doivent déterminer si les utilisateurs sont susceptibles de faire glisser des éléments dans leur application. Voici quelques exemples courants de cas d'utilisation : les éditeurs de photos qui reçoivent des photos, les lecteurs audio qui reçoivent des fichiers audio et les programmes de dessin qui reçoivent des photos.

Pour permettre de glisser-déposer des éléments, consultez la documentation Android sur la fonctionnalité Glisser-déposer, et consultez cet article du blog ChromeOS.

Remarques concernant ChromeOS

  • N'oubliez pas de demander l'autorisation via requestDragAndDropPermissions pour permettre l'accès des éléments que l'utilisateur fait glisser depuis l'extérieur de l'application.
  • Un élément doit être associé à l'indicateur View.DRAG_FLAG_GLOBAL pour pouvoir être glissé vers d'autres applications.

Compatibilité avancée avec les pointeurs

Les applications qui gèrent les commandes avancées de la souris et du pavé tactile doivent respecter la documentation Android concernant View.onGenericMotionEvent() et utiliser MotionEvent.getSource() pour faire la distinction entre SOURCE_MOUSE et SOURCE_TOUCHSCREEN.

Examinez MotionEvent pour mettre en œuvre le comportement requis :

  • Le mouvement génère des événements ACTION_HOVER_MOVE.
  • Les boutons génèrent des événements ACTION_BUTTON_PRESS et ACTION_BUTTON_RELEASE. Vous pouvez également vérifier l'état actuel de tous les boutons de la souris ou du pavé tactile avec getButtonState().
  • Le défilement de la molette de la souris génère des événements ACTION_SCROLL.

Manettes de jeu

Certains appareils Android à grand écran acceptent jusqu'à quatre manettes de jeu. Les développeurs doivent utiliser les API de manette de jeu Android standards pour les gérer (consultez Support game controllers [Prendre en charge les manettes de jeu]).

Les boutons sont mis en correspondance avec des valeurs communes suivant un mappage commun. Malheureusement, tous les fabricants de manettes de jeu ne suivent pas les mêmes conventions de mappage. Vous offrirez une bien meilleure expérience si vous autorisez les utilisateurs à sélectionner différents mappages de manettes populaires. Pour en savoir plus, consultez la section Process gamepad button presses (Traiter les pressions sur les boutons d'une manette de jeu).

Mode de conversion d'entrée

ChromeOS offre un mode de conversion d'entrée par défaut. Pour la plupart des applications Android, ce mode permet aux applications de fonctionner comme prévu dans un environnement de bureau. Par exemple, il permet l'activation automatique du défilement à deux doigts sur le pavé tactile, le défilement de la molette de la souris et le mappage des coordonnées brutes de l'écran avec les coordonnées de la fenêtre. En règle générale, les développeurs d'applications n'ont pas besoin d'implémenter ces comportements eux-mêmes.

Si une application met en œuvre un comportement de saisie personnalisé, par exemple si vous définissez une action personnalisée de pincement avec deux doigts sur le pavé tactile, ou si ces conversions d'entrée ne fournissent pas les événements d'entrée attendus par l'application, vous pouvez désactiver la conversion d'entrée en ajoutant la balise suivante au fichier manifeste Android :

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

Ressources supplémentaires