Guide d'intégration pour les OEM

Cet article décrit comment traiter les entrées rotatives dans le VHAL, configurer votre build pour inclure le service rotatif et comment personnaliser l'expérience rotative dans toutes les applications. Pour les applications OEM préinstallées, telles qu'un lanceur fourni par OEM, consultez Car UI Library (car-ui-library) .

VHAL

Un contrôleur rotatif prend en charge les actions suivantes :

  • Déplacez-vous vers le haut, le bas, la gauche et la droite.
  • Tournez dans le sens des aiguilles d'une montre et dans le sens inverse des aiguilles d'une montre.
  • Appuyez sur le bouton central.
  • Appuyer sur le bouton précédent.
  • Appuyez sur le bouton Accueil.
  • Appuyez sur d'autres boutons, tels que Téléphone et Média.

Voir hardware/interfaces/automotive/vehicle/2.0/types.hal pour la documentation sur les propriétés du système et int32Values ​​correspondantes.

Le VHAL doit gérer ces actions :

Coup de coude

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

  1. ACTION_DOWN
  2. KEYCODE_SYSTEM_NAVIGATION_RIGHT
  3. Affichage de la cible.

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

Il n'y a pas de codes clés pour les diagonales, mais le VHAL peut combiner un événement horizontal et vertical pour produire une diagonale si le matériel prend en charge les diagonales. Par exemple, un déplacement 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 les deux ordres (et ensuite), le relâchement du contrôleur rotatif devrait produire :

  • HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_UP
  • HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_UP

L'utilisateur peut pousser le contrôleur rotatif dans une direction perpendiculaire avant de le relâcher. Par exemple, le scénario suivant :

Direction perpendiculaire
Figure 1. Direction perpendiculaire

Cela devrait générer la séquence d'événements suivante :

  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 répété ne doit être généré lorsque le contrôleur rotatif est maintenu dans une direction.

Tourner

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

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

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

Une rotation d'un (1) cran dans le sens inverse des aiguilles d'une montre devrait générer le même événement mais avec -1 pour le nombre de crans.

Si plusieurs détentes de rotation dans le même sens se produisent en succession rapide, le VHAL doit combiner les détentes en un seul événement afin de ne pas surcharger le système avec des événements. Dans ce cas, l’horodatage de l’événement doit correspondre au moment où le premier arrêt de rotation s’est produit. Les int32Values ​​doivent inclure le nombre de nanosecondes entre les arrêts de rotation consécutifs.

Par exemple, la séquence de rotations suivante :

  • Au temps t0, l'utilisateur a tourné d'un cran dans le sens inverse des aiguilles d'une montre.
  • Au temps t0 + 5 ns, l'utilisateur a tourné d'un cran dans le sens inverse des aiguilles d'une montre.
  • Au temps t0 + 8 ns, l'utilisateur a tourné d'un cran dans le sens inverse des aiguilles d'une montre.

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

  • Propriété : HW_ROTARY_INPUT
  • Horodatage : t0
  • int32Values :
    1. ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION
    2. -3 (trois crans dans le sens inverse des aiguilles d'une montre).
    3. Affichage de la 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 Centre, le VHAL doit utiliser la propriété HW_KEY_INPUT avec les int32Values ​​suivantes pour envoyer un événement à Android :

  1. ACTION_DOWN
  2. KEYCODE_DPAD_CENTER
  3. Affichage de la cible.

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

Ne générez pas d'événements répétés 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 les int32Values ​​suivantes pour envoyer un événement à Android :

  1. ACTION_DOWN
  2. KEYCODE_BACK
  3. Affichage de la cible.

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

Aucun événement répété ne doit être généré lorsque le bouton central est maintenu enfoncé.

Bouton d'accueil

Gérez le bouton 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 comprend des boutons supplémentaires, le VHAL peut les gérer comme le souhaite l'OEM, car ils ne sont pas considérés comme faisant partie du bouton rotatif du point de vue d'Android. Ceux-ci sont généralement gérés comme les boutons Retour et Accueil, mais avec des codes clés différents. Par exemple, KEYCODE_CALL ou KEYCODE_MUSIC .

Configuration de construction

La navigation rotative 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 makefile :

PRODUCT_PACKAGES += CarRotaryController

Vous souhaiterez peut-être également inclure les packages suivants dans les versions de débogage :

Le service rotatif est activé automatiquement au démarrage de l'appareil et lorsqu'un changement d'utilisateur se produit. Cela garantit que l'utilisateur peut utiliser le contrôleur rotatif pendant la configuration.

Si vous utilisez la même version 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 version. Pour empêcher l'activation du service rotatif 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 la même version, mais disposerez de configurations de produit distinctes, pour les appareils rotatifs et non rotatifs. Seule cette dernière inclut la superposition.

Personnalisation

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

  • car-ui-library se trouve dans packages/apps/Car/libs/car-ui-lib
  • RotaryService se trouve dans packages/apps/Car/RotaryController
  • Core est situé dans frameworks/base/core

Historique des coups de pouce

L'OEM peut configurer si chacun des deux types d'historique de nudge est activé et, si tel est le cas, la taille du cache et la stratégie d'expiration. Tout cela se fait en remplaçant diverses ressources de la bibliothèque automobile.

Cache de l'historique de mise au point

( Android 11 QPR3, Android 11 Voiture, Android 12 )
Ce cache par FocusArea stocke la vue la plus récemment focalisée dans la FocusArea afin qu'elle puisse être focalisée lors du retour vers la FocusArea . Ce cache peut être configuré en superposant les ressources car-ui-library suivantes :

  • car_ui_focus_history_cache_type :
    1. Le cache est désactivé.
    2. Le cache expirera après un certain temps (voir ci-dessous).
    3. Le cache n'expirera jamais.
  • car_ui_focus_history_expiration_period_ms : combien de millisecondes avant l'expiration du cache si le type de cache est défini sur deux (2) (voir ci-dessus).

Cache historique FocusArea

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

  • car_ui_focus_area_history_cache_type :
    1. Le cache est désactivé.
    2. Le cache expire après un certain temps (voir ci-dessous).
    3. Le cache n'expire jamais.
  • car_ui_focus_area_history_expiration_period_ms : Combien 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 : s'il faut vider le cache lorsque l'utilisateur fait pivoter le contrôleur.

Rotation

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

  • rotation_acceleration_3x_ms : intervalle de temps (en millisecondes) utilisé pour décider si Google doit accélérer la rotation du contrôleur pour un arrêt de rotation. Si l'intervalle entre ce cran et le cran de rotation précédent est inférieur à cette valeur, il sera traité comme trois crans de rotation. Réglez-le sur 2147483647 pour désactiver l’accélération 3×.
  • rotation_acceleration_2x_ms : similaire à rotation_acceleration_3x_ms . Utilisé pour une accélération 2×. Réglez-le sur 2147483647 pour désactiver l’accélération 2×.

L'accélération fonctionne mieux lorsqu'il existe des horodatages individuels pour chaque arrêt de rotation, comme l'exige le VHAL. Si ceux-ci ne sont pas disponibles, le RotaryService suppose que les crans de rotation sont régulièrement espacés.

/**
     * 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),

Point culminant de la mise au point

L'OEM peut remplacer la mise en évidence du focus par défaut dans le cadre Android et plusieurs ressources de mise en évidence du focus dans la bibliothèque car-ui.

Mise au point par défaut

Le framework Android fournit une mise en évidence du 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 la mise en évidence du focus par défaut.

Ce dessinable doit généralement être un StateListDrawable , qui ajuste l'arrière-plan en fonction de différentes combinaisons d'états, notamment android:state_focused et android:state_pressed . Lorsque l'utilisateur utilise le contrôleur rotatif pour focaliser une vue, android:state_focused sera true , mais android:state_pressed sera false . Si l'utilisateur appuie ensuite sur le bouton central du contrôleur rotatif, android:state_focused et android:state_pressed seront tous true tant que l'utilisateur maintiendra le bouton enfoncé. Lorsque l'utilisateur relâche le bouton, seul android:state_focused restera 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 n'importe quel thème dérivé de Theme.DeviceDefault . Cela n'affectera pas les applications qui utilisent un thème sans rapport, tel que Theme.Material .

Focus sur les ressources de la bibliothèque car-ui

L'OEM peut remplacer plusieurs ressources de la bibliothèque d'interface utilisateur automobile pour contrôler l'apparence de la mise en évidence du focus sur les vues avec une mise en évidence non rectangulaire (telle que ronde ou en forme de pilule) et dans les applications qui utilisent un thème qui ne dérive pas du Theme.DeviceDefault . Theme.DeviceDefault . Ces ressources doivent être superposées afin que la mise en évidence du focus soit cohérente avec la mise en évidence du focus par défaut .

( Android 11 QPR3, Android 11 Voiture, Android 12 )
Les ressources suivantes sont utilisées pour indiquer quand une vue est ciblée mais n'est 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 : Epaisseur du contour.

( Android 11 QPR3, Android 11 Voiture, Android 12 )
Les ressources suivantes sont utilisées pour indiquer quand une vue est ciblée 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 : Epaisseur du contour.

Parfois, un bouton reçoit une couleur d'arrière-plan unie pour le porter à l'attention de l'utilisateur, comme dans l'exemple présenté. Cela peut rendre la mise au point difficile à voir.

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

Dans cette situation, le développeur peut spécifier une surbrillance personnalisée à l'aide de couleurs secondaires :
  • ( Android 11 QPR3, Android 11 Voiture, Android 12 )
    car_ui_rotary_focus_fill_secondary_color
    car_ui_rotary_focus_stroke_secondary_color
  • ( Androïde 12 )
    car_ui_rotary_focus_pressed_fill_secondary_color
    car_ui_rotary_focus_pressed_stroke_secondary_color

N'importe quelle couleur peut être transparente et chaque dimension peut être nulle si, par exemple, vous souhaitez uniquement un remplissage ou uniquement un contour.

Point culminant de la zone Focus

( Android 11 QPR3, Android 11 Voiture, Android 12 )
FocusArea peut dessiner deux types de surbrillance lorsqu'un de ses descendants est focalisé. Les deux peuvent être utilisés conjointement, 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 car-ui-library :

  • car_ui_enable_focus_area_foreground_highlight : dessinez un surbrillance au-dessus de FocusArea et de ses descendants. Dans AOSP, ce dessinable est un contour autour de FocusArea . Les OEM peuvent remplacer le dessin car_ui_focus_area_foreground_highlight .
  • car_ui_enable_focus_area_background_highlight : dessinez un surbrillance au-dessus de la FocusArea mais derrière ses descendants. En AOSP, ce dessinable est un remplissage solide. Les OEM peuvent remplacer le dessin car_ui_focus_area_background_highlight .

Éditeurs de méthodes de saisie

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

( Android 11 QPR3, Android 11 Voiture, 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 le constructeur OEM utilise l'IME fourni avec Android Automotive, il doit spécifier com.google.android.apps.automotive.inputmethod/.InputMethodService .

( Android 11 QPR3, Android 11 Voiture, Android 12 )
Si l'OEM a créé un IME spécifiquement pour le 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 via le déplacement, la rotation et le bouton central du contrôleur rotatif. Lorsque l'utilisateur touche l'écran, l'IME précédent sera utilisé. Le bouton Retour (et les autres boutons du contrôleur rotatif) n'ont aucun effet sur la sélection IME. Si cette ressource n’est pas superposée, aucune commutation IME ne se produit. Carboard ne prend pas en charge la rotation, 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 basique, il suffit d'essayer la commutation IME automatique décrite ci-dessus. Le code source de RotaryIME se trouve dans packages/apps/Car/tests/RotaryIME/ .

Coups de pouce hors écran

Par défaut, lorsque l'utilisateur tente de repousser le bord de l'écran, rien ne se passe. L'OEM peut configurer ce qui doit se produire pour chacune des quatre directions en spécifiant n'importe quelle combinaison de :

  1. Une action globale définie par AccessibilityService . Par exemple, GLOBAL_ACTION_BACK .
  2. Un code clé, tel que KEYCODE_BACK .
  3. Intention de lancer une activité représentée sous forme d'URL.

( Android 11 QPR3, Android 11 Voiture, Android 12 )
Celles-ci sont spécifiées en superposant les ressources de tableau suivantes dans le RotaryService :

  • off_screen_nudge_global_actions : Tableau d'actions globales à effectuer lorsque l'utilisateur déplace le bord de l'écran vers le haut, le bas, la gauche ou la droite. Aucune action globale n'est effectuée si l'élément pertinent de ce tableau est -1.
  • off_screen_nudge_key_codes : tableau de codes clés d'événements de clic à injecter lorsque l'utilisateur pousse vers le haut, le bas, la gauche ou la droite hors du bord de l'écran. Aucun événement n'est injecté si l'élément pertinent de ce tableau est 0 ( KEYCODE_UNKNOWN ).
  • off_screen_nudge_intents : Tableau d'intentions pour lancer une activité lorsque l'utilisateur pousse vers le haut, le bas, la gauche ou la droite du bord 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 Voiture, Android 12 )
    config_showHeadsUpNotificationOnBottom : valeur booléenne indiquant si les notifications tête haute doivent être affichées en bas plutôt qu'en haut. Cela doit avoir la même valeur que la ressource booléenne config_showHeadsUpNotificationOnBottom dans frameworks/base/packages/CarSystemUI/res/values/config.xml
  • ( Android 11 QPR3, Android 11 Voiture, Android 12 )
    notification_headsup_card_margin_horizontal : Marges gauche et droite pour la fenêtre de notification tête haute. Cela doit avoir la même valeur que la ressource dimen notification_headsup_card_margin_horizontal dans packages/apps/Car/Notification/res/values/dimens.xml
  • ( Androïde 12 )
    excluded_application_overlay_window_titles : Un tableau de titres de 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 contient uniquement des « Cartes ».

Vous pouvez superposer la ressource RotaryService suivante :

  • ( Android 11 QPR3, Android 11 Voiture, 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. Zéro indique que le délai d'attente d'appui long par défaut du système doit être utilisé. Ceci est la valeur par défault.