Guide d'intégration pour les OEM

Cette page explique comment traiter les entrées rotatives dans le VHAL, configurer votre build pour inclure le service rotatif et personnaliser l'expérience rotative dans toutes les applications. Pour les applications OEM préinstallées, telles qu'un lanceur fourni par l'OEM, consultez la section Bibliothèque d'UI pour voitures (car-ui-library).

VHAL

Un contrôleur rotatif permet d'effectuer les actions suivantes:

  • Déplacez l'élément vers le haut, le bas, la gauche et la droite.
  • Faites pivoter l'élément dans le sens des aiguilles d'une montre et dans le sens inverse.
  • Appuyez sur le bouton central.
  • Appuyez sur le bouton Retour.
  • Appuyez sur le bouton d'accueil.
  • Appuyez sur d'autres boutons, comme Téléphone et Multimédia.

Consultez hardware/interfaces/automotive/vehicle/2.0/types.hal pour en savoir plus sur les propriétés système et les int32Values correspondantes.

Le VHAL doit gérer les actions suivantes:

Coup de pouce

Lorsque l'utilisateur appuie sur le contrôleur rotatif vers la droite, le VHAL doit utiliser la propriété HW_KEY_INPUT avec le int32Values suivant pour envoyer un événement à Android:

  1. ACTION_DOWN
  2. KEYCODE_SYSTEM_NAVIGATION_RIGHT
  3. Affichage cible.

Lorsque l'utilisateur relâche le contrôleur rotatif, le VHAL doit utiliser la même propriété et le même code de touche avec ACTION_UP. Les mouvements dans d'autres directions doivent utiliser les codes de touche correspondants.

Il n'existe pas de codes de touche pour les diagonales, mais le VHAL peut combiner un événement horizontal et vertical pour produire une diagonale si le matériel est compatible avec les diagonales. Par exemple, un léger mouvement vers le haut et vers la gauche devrait produire:

  • HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_DOWN
  • HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_DOWN

Dans l'un ou l'autre ordre (et par la suite), relâcher le contrôleur rotatif doit produire:

  • HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_UP
  • HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_UP

L'utilisateur peut appuyer sur le contrôleur rotatif dans une direction perpendiculaire avant de le relâcher. Prenons l'exemple suivant:

Orientation perpendiculaire
Figure 1. Sens perpendiculaire

La séquence d'événements suivante devrait se produire:

  1. HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_DOWN
  2. HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_DOWN
  3. HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_UP
  4. HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_UP

Aucun événement de répétition ne doit être généré lorsque le contrôleur rotatif est maintenu dans une direction.

Faire pivoter

Lorsque l'utilisateur fait pivoter le contrôleur rotatif dans le sens des aiguilles d'une montre d'un cran (clic), le VHAL doit utiliser la propriété HW_ROTARY_INPUT avec le int32Values suivant pour envoyer un événement à Android:

  1. ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION
  2. Un (1) cran
  3. Affichage cible.

L'horodatage de l'événement doit être défini sur le temps écoulé en nanosecondes.

Une rotation d'un (1) cliquet dans le sens antihoraire doit générer le même événement, mais avec -1 pour le nombre de cliquets.

Si plusieurs cliquets de rotation dans la même direction se produisent rapidement, le VHAL doit combiner les cliquets en un seul événement afin de ne pas surcharger le système d'événements. Dans ce cas, le code temporel de l'événement doit correspondre au moment où le premier cran de rotation s'est produit. int32Values doit inclure le nombre de nanosecondes entre les cliquets de rotation consécutifs.

Par exemple, la séquence de rotations suivante:

  • À l'instant t0, l'utilisateur a fait pivoter un cran dans le sens antihoraire.
  • À l'heure t0 + 5 ns, l'utilisateur a fait pivoter un cliquet dans le sens antihoraire.
  • À l'heure t0 + 8 ns, l'utilisateur a fait pivoter un cran dans le sens antihoraire.

doit générer cet événement:

  • Propriété: HW_ROTARY_INPUT
  • Code temporel: t0
  • int32Values :
    1. ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION
    2. -3 (trois crans dans le sens inverse des aiguilles d'une montre).
    3. Affichage cible.
    4. 5 ns entre le premier et le deuxième cran.
    5. 3 ns entre le deuxième et le troisième cran.

Bouton central

Lorsque l'utilisateur appuie sur le bouton central, le VHAL doit utiliser la propriété HW_KEY_INPUT avec le int32Values suivant pour envoyer un événement à Android:

  1. ACTION_DOWN
  2. KEYCODE_DPAD_CENTER
  3. Affichage cible.

Lorsque l'utilisateur relâche le contrôleur rotatif, le VHAL doit utiliser la même propriété et le même code de touche avec ACTION_UP.

Ne générez pas d'événements de répétition lorsque le bouton central est maintenu enfoncé.

Bouton Retour

Lorsque l'utilisateur appuie sur le bouton "Retour", le VHAL doit utiliser la propriété HW_KEY_INPUT avec le int32Values suivant pour envoyer un événement à Android:

  1. ACTION_DOWN
  2. KEYCODE_BACK
  3. Affichage cible.

Lorsque l'utilisateur relâche le contrôleur rotatif, le VHAL doit utiliser la même propriété et le même code de touche avec ACTION_UP.

Aucun événement de répétition ne doit être généré tant que le bouton central est maintenu enfoncé.

Bouton Accueil

Gérez le bouton d'accueil comme vous le feriez avec le bouton Retour, mais avec KEYCODE_HOME au lieu de KEYCODE_BACK.

Autres boutons

Si le contrôleur rotatif inclut des boutons supplémentaires, le VHAL peut les gérer comme l'OEM le souhaite, car ils ne sont pas considérés comme faisant partie du dispositif rotatif du point de vue d'Android. Ils sont généralement gérés comme les boutons Retour et Accueil, mais avec des codes de touche différents. Exemples : KEYCODE_CALL ou KEYCODE_MUSIC.

Configuration de compilation

La navigation par dispositif rotatif est fournie par un service d'accessibilité appelé RotaryService. Pour inclure ce service dans l'image système de votre appareil, ajoutez la ligne suivante à votre fichier makefile:

PRODUCT_PACKAGES += CarRotaryController

Vous pouvez également inclure les packages suivants dans les builds de débogage:

  • RotaryPlayground Une application de référence pour les dispositifs rotatifs (voir RotaryPlayground).
  • RotaryIME Un IME rotatif de démonstration (voir Éditeurs de mode de saisie).
  • CarRotaryImeRRO Superposition de RotaryIME.

Le service rotatif est activé automatiquement au démarrage de l'appareil et lors d'un changement d'utilisateur. Cela permet à l'utilisateur d'utiliser le contrôleur rotatif lors de la configuration.

Si vous utilisez la même compilation pour les voitures avec et sans contrôleur rotatif, ajoutez CarRotaryController comme indiqué ci-dessus afin que le code nécessaire soit inclus dans la compilation. Pour empêcher le service rotatif d'être activé sur les voitures non rotatives, créez un RRO statique pour superposer la ressource de chaîne rotaryService dans packages/services/Car/service avec une chaîne vide. Vous utiliserez le même build, mais vous aurez des configurations de produits distinctes pour les appareils rotatifs et non rotatifs. Seul le dernier inclut la superposition.

Personnalisation

Les OEM peuvent personnaliser la logique de recherche du focus, la mise en surbrillance du focus et certains éléments supplémentaires via des superpositions de ressources aux emplacements suivants:

  • La bibliothèque car-ui se trouve dans packages/apps/Car/libs/car-ui-lib
  • RotaryService se trouve à packages/apps/Car/RotaryController
  • Core se trouve à frameworks/base/core

Historique des nudges

L'OEM peut configurer si chacun des deux types d'historique des nudges est activé ou non, et le cas échéant, la taille du cache et la règle d'expiration. Pour ce faire, remplacez différentes ressources de la bibliothèque d'UI de voiture.

Cache de l'historique de la mise au point

(Android 11 QPR3, Android 11 Car, Android 12)
Ce cache par FocusArea stocke la vue la plus récente mise au point dans le FocusArea afin qu'elle puisse être mise au point lorsque vous revenez au FocusArea. Vous pouvez configurer ce cache en superposant les ressources car-ui-library suivantes:

  • car_ui_focus_history_cache_type :
    1. La mise en cache est désactivée.
    2. Le cache expire au bout d'un certain temps (voir ci-dessous).
    3. Le cache n'expire jamais.
  • car_ui_focus_history_expiration_period_ms: nombre de millisecondes avant l'expiration du cache si le type de cache est défini sur deux (2) (voir ci-dessus).

Cache de l'historique de FocusArea

(Android 11 QPR3, Android 11 Car, Android 12)
Ce cache stocke un historique des incitations afin que les incitations dans la direction opposée puissent rétablir la sélection sur le même FocusArea. Ce cache peut être configuré en superposant les ressources car-ui-library suivantes:

  • car_ui_focus_area_history_cache_type :
    1. La mise en cache est désactivée.
    2. La mise en cache expire au bout d'un certain temps (voir ci-dessous).
    3. La mise en cache n'expire jamais.
  • car_ui_focus_area_history_expiration_period_ms: nombre de millisecondes avant l'expiration du cache si le type de cache est défini sur 2 (voir ci-dessus).
  • car_ui_clear_focus_area_history_when_rotating: indique si le cache doit être annulé lorsque l'utilisateur fait pivoter la manette.

Rotation

(Android 11 QPR3, Android 11 Car, Android 12)
L'OEM peut remplacer deux ressources entières dans RotaryService pour spécifier s'il existe une accélération, comme l'accélération de la souris, pour la rotation:

  • rotation_acceleration_3x_ms: intervalle de temps (en millisecondes) utilisé pour déterminer si Google doit accélérer la rotation du contrôleur pour un point d'arrêt de la rotation. Si l'intervalle entre ce cliquet et le cliquet de rotation précédent est inférieur à cette valeur, il sera traité comme trois cliquets de rotation. Définissez cette valeur sur 2147483647 pour désactiver l'accélération 3 fois.
  • rotation_acceleration_2x_ms: semblable à rotation_acceleration_3x_ms. Utilisé pour l'accélération x2. Définissez cette valeur sur 2147483647 pour désactiver l'accélération x2.

L'accélération fonctionne mieux lorsqu'il existe des codes temporels individuels pour chaque cran de rotation, comme requis par le VHAL. Si ces valeurs ne sont pas disponibles, RotaryService suppose que les crans de rotation sont espacés de manière uniforme.

/**
     * Property to feed H/W rotary events to android
     *
     * int32Values[0] : RotaryInputType identifying which rotary knob rotated
     * int32Values[1] : number of detents (clicks), positive for clockwise,
     *                  negative for counterclockwise
     * int32Values[2] : target display defined in VehicleDisplay. Events not
     *                  tied to specific display must be sent to
     *                  VehicleDisplay#MAIN.
     * int32values[3 .. 3 + abs(number of detents) - 2]:
     *                  nanosecond deltas between pairs of consecutive detents,
     *                  if the number of detents is > 1 or < -1
     *
     * VehiclePropValue.timestamp: when the rotation occurred. If the number of
     *                             detents is > 1 or < -1, this is when the
     *                             first detent of rotation occurred.
     *
     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
     * @data_enum RotaryInputType
     * @access VehiclePropertyAccess:READ
     */
    HW_ROTARY_INPUT = (
        0x0A20
        | VehiclePropertyGroup:SYSTEM
        | VehiclePropertyType:INT32_VEC
        | VehicleArea:GLOBAL),

Mise en surbrillance du focus

L'OEM peut remplacer la mise en surbrillance de l'élément sélectionné par défaut dans le framework Android et plusieurs ressources de mise en surbrillance de l'élément sélectionné dans la bibliothèque car-ui.

Mise en surbrillance du focus par défaut

Le framework Android fournit un surlignage de focus par défaut via l'attribut selectableItemBackground. Dans Theme.DeviceDefault, cet attribut fait référence à item_background.xml dans Core. L'OEM peut superposer item_background.xml pour modifier le drawable de mise en surbrillance de la mise au point par défaut.

Ce drawable doit généralement être un StateListDrawable, qui ajuste l'arrière-plan en fonction de différentes combinaisons d'états, y compris android:state_focused et android:state_pressed. Lorsque l'utilisateur utilise le contrôleur rotatif pour mettre au point une vue, android:state_focused est true, mais android:state_pressed est false. Si l'utilisateur appuie ensuite sur le bouton central de la manette rotative, android:state_focused et android:state_pressed sont tous deux définis sur true tant que l'utilisateur maintient le bouton enfoncé. Lorsque l'utilisateur relâche le bouton, seul android:state_focused reste true.

car-ui-library utilise un thème dérivé de Theme.DeviceDefault. Par conséquent, cette superposition affecte les applications qui utilisent cette bibliothèque et les applications qui utilisent un thème dérivé de Theme.DeviceDefault. Cela n'aura aucune incidence sur les applications qui utilisent un thème sans rapport, comme Theme.Material.

Ressources de mise en surbrillance de l'interface utilisateur de la voiture

L'OEM peut remplacer plusieurs ressources de la bibliothèque d'UI pour voiture afin de contrôler l'apparence de la mise en surbrillance de l'élément sélectionné dans les vues avec une mise en surbrillance de l'élément sélectionné non rectangulaire (par exemple, ronde ou en forme de pilule) et dans les applications qui utilisent un thème qui ne dérive pas de Theme.DeviceDefault. Ces ressources doivent être superposées afin que la mise en surbrillance de l'élément sélectionné soit cohérente avec le drawable de mise en surbrillance par défaut.

(Android 11 QPR3, Android 11 Car, Android 12)
Les ressources suivantes permettent d'indiquer quand une vue est sélectionnée, mais pas enfoncée:

  • car_ui_rotary_focus_fill_color: couleur de remplissage.
  • car_ui_rotary_focus_stroke_color: couleur du contour.
  • car_ui_rotary_focus_stroke_width: épaisseur du contour.

(Android 11 QPR3, Android 11 Car, Android 12)
Les ressources suivantes permettent d'indiquer quand une vue est mise au point et enfoncée:

  • car_ui_rotary_focus_pressed_fill_color: couleur de remplissage.
  • car_ui_rotary_focus_pressed_stroke_color: couleur du contour.
  • car_ui_rotary_focus_pressed_stroke_width: épaisseur du contour.

Parfois, une couleur d'arrière-plan unie est appliquée à un bouton pour attirer l'attention de l'utilisateur, comme dans l'exemple ci-dessous. Il peut être difficile de voir la sélection.

Bouton avec arrière-plan uni
Figure 2. Bouton avec arrière-plan uni

Dans ce cas, le développeur peut spécifier une mise en surbrillance personnalisée à l'aide de couleurs secondaires :
  • (Android 11 QPR3, Android 11 Car, Android 12)
    car_ui_rotary_focus_fill_secondary_color
    car_ui_rotary_focus_stroke_secondary_color
  • (Android 12)
    car_ui_rotary_focus_pressed_fill_secondary_color
    car_ui_rotary_focus_pressed_stroke_secondary_color

Toutes les couleurs peuvent être transparentes et l'une des dimensions peut être nulle si, par exemple, vous ne souhaitez qu'un remplissage ou qu'un contour.

Mise en surbrillance de la zone de mise au point

(Android 11 QPR3, Android 11 Car, Android 12)
FocusArea peut dessiner deux types de surbrillance lorsqu'un de ses descendants est mis au premier plan. Vous pouvez utiliser les deux en même temps, si vous le souhaitez. Cette fonctionnalité est désactivée par défaut dans AOSP, mais peut être activée en remplaçant les ressources de la bibliothèque d'interface utilisateur pour voitures:

  • car_ui_enable_focus_area_foreground_highlight: dessine un surlignage au-dessus de FocusArea et de ses descendants. Dans AOSP, ce drawable est un contour autour de FocusArea. Les OEM peuvent remplacer le drawable car_ui_focus_area_foreground_highlight.
  • car_ui_enable_focus_area_background_highlight: dessine un surlignage au-dessus de FocusArea, mais derrière ses descendants. Dans AOSP, ce drawable est un remplissage solide. Les OEM peuvent remplacer le drawable car_ui_focus_area_background_highlight.

Éditeurs de mode de saisie

Les éditeurs de mode de saisie (IME) sont des méthodes de saisie. (par exemple, un clavier à l'écran).

(Android 11 QPR3, Android 11 Car, Android 12)
L'OEM doit superposer la ressource de chaîne default_touch_input_method dans RotaryService pour spécifier le ComponentName de l'IME tactile. Par exemple, si l'OEM utilise l'IME fourni avec Android Automotive, il doit spécifier com.google.android.apps.automotive.inputmethod/.InputMethodService.

(Android 11 QPR3, Android 11 Car, Android 12)
Si l'OEM a créé un IME spécifiquement pour le dispositif rotatif, il doit spécifier son ComponentName dans la ressource rotary_input_method. Si cette ressource est superposée, l'IME spécifié est utilisé chaque fois que l'utilisateur interagit avec l'unité principale à l'aide du bouton de réglage, de la rotation et du bouton central du contrôleur rotatif. Lorsque l'utilisateur appuie sur l'écran, le IME précédent est utilisé. Le bouton Retour (et les autres boutons du contrôleur rotatif) n'ont aucun effet sur la sélection de l'IME. Si cette ressource n'est pas superposée, aucun changement d'IME ne se produit. Carboard n'est pas compatible avec les dispositifs rotatifs. L'utilisateur ne peut donc pas saisir de texte via le contrôleur rotatif si l'OEM n'a pas fourni d'IME rotatif.

RotaryIME est un IME rotatif de démonstration. Bien que de base, il suffit d'essayer le changement automatique de l'IME décrit ci-dessus. Le code source de RotaryIME se trouve dans packages/apps/Car/tests/RotaryIME/.

Rappels automatiques hors écran

Par défaut, lorsque l'utilisateur essaie de faire glisser l'élément en dehors du bord de l'écran, rien ne se passe. L'OEM peut configurer ce qui doit se passer pour chacune des quatre orientations en spécifiant n'importe quelle combinaison des éléments suivants:

  1. Action globale définie par AccessibilityService. Par exemple, GLOBAL_ACTION_BACK.
  2. Un code de clé, par exemple KEYCODE_BACK.
  3. Intent visant à lancer une activité représentée par une URL.

(Android 11 QPR3, Android 11 Car, Android 12)
Ces éléments sont spécifiés en superposant les ressources de tableau suivantes dans le RotaryService:

  • off_screen_nudge_global_actions: tableau d'actions globales à effectuer lorsque l'utilisateur appuie sur le bord supérieur, inférieur, gauche ou droit de l'écran. Aucune action globale n'est effectuée si l'élément concerné de ce tableau est -1.
  • off_screen_nudge_key_codes: tableau des codes de touche des événements de clic à injecter lorsque l'utilisateur pousse l'écran vers le haut, le bas, la gauche ou la droite. Aucun événement n'est injecté si l'élément pertinent de ce tableau est 0 (KEYCODE_UNKNOWN).
  • off_screen_nudge_intents: tableau d'intents permettant de lancer une activité lorsque l'utilisateur appuie sur le bord supérieur, inférieur, gauche ou droit de l'écran. Aucune activité n'est lancée si l'élément concerné de ce tableau est vide.

Autres configurations

Vous devez superposer les ressources RotaryService suivantes:

  • (Android 11 QPR3, Android 11 Car, Android 12)
    config_showHeadsUpNotificationOnBottom: valeur booléenne indiquant si les notifications d'alerte doivent s'afficher en bas plutôt qu'en haut. Cette valeur doit être identique à celle de la ressource booléenne config_showHeadsUpNotificationOnBottom dans frameworks/base/packages/CarSystemUI/res/values/config.xml.
  • (Android 11 QPR3, Android 11 Car, Android 12)
    notification_headsup_card_margin_horizontal: marges gauche et droite pour la fenêtre de notification d'alerte. Cette valeur doit être identique à celle de la ressource de dimension notification_headsup_card_margin_horizontal dans packages/apps/Car/Notification/res/values/dimens.xml.
  • (Android 12)
    excluded_application_overlay_window_titles: tableau des titres des fenêtres qui ne doivent pas être considérées comme des fenêtres superposées. Cela doit inclure les titres des fenêtres d'application qui représentent TaskViews ou TaskDisplayAreas. Par défaut, cette liste ne contient que "Maps".

Vous pouvez superposer la ressource RotaryService suivante:

  • (Android 11 QPR3, Android 11 Car, Android 12)
    long_press_ms: valeur entière représentant le nombre de millisecondes pendant lesquelles le bouton central doit être maintenu enfoncé pour déclencher un appui long. La valeur zéro indique que le délai avant expiration par défaut du système doit être utilisé. Il s'agit de la valeur par défaut.