Développer des applications

Les documents suivants sont destinés aux développeurs d'applications.

Pour que votre application soit compatible avec le dispositif rotatif, vous DEVEZ:

  1. Placez un FocusParkingView dans la mise en page de l'activité correspondante.
  2. Assurez-vous que les vues sont (ou ne sont pas) sélectionnables.
  3. Utilisez des FocusArea pour encapsuler toutes les vues sélectionnables, à l'exception des FocusParkingView

Chacune de ces tâches est détaillée ci-dessous, une fois que vous avez configuré votre environnement pour développer des applications compatibles avec un dispositif rotatif.

Configurer un contrôleur rotatif

Avant de pouvoir développer des applications compatibles avec un dispositif rotatif, vous avez besoin d'un contrôleur rotatif ou un remplaçant. Vous disposez des options décrites ci-dessous.

Émulateur

source build/envsetup.sh && lunch car_x86_64-userdebug
m -j
emulator -wipe-data -no-snapshot -writable-system

Vous pouvez également utiliser aosp_car_x86_64-userdebug.

Pour accéder au contrôleur rotatif émulé, procédez comme suit:

  1. Appuyez sur les trois points au bas de la barre d'outils:

    Accéder au contrôleur rotatif émulé
    Figure 1. Accéder au contrôleur rotatif émulé
  2. Sélectionnez Car rotary (Rotaire de la voiture) dans la fenêtre des commandes avancées:

    <ph type="x-smartling-placeholder">
    </ph> Sélectionner le dispositif rotatif du véhicule
    Figure 2. Sélectionnez Rotaire du véhicule

Clavier USB

  • Branchez un clavier USB à votre appareil qui exécute Android Automotive OS (AAOS). Dans certains cas, cela empêche le clavier à l'écran d'apparaître.
  • Utilisez un build userdebug ou eng.
  • Activez le filtrage des événements clés:
    adb shell settings put secure android.car.ROTARY_KEY_EVENT_FILTER 1
    
  • Consultez le tableau ci-dessous pour trouver la clé correspondant à chaque action:
    Clé Action par dispositif rotatif
    Q Faire pivoter dans le sens inverse des aiguilles d'une montre
    E Faire pivoter dans le sens des aiguilles d'une montre
    A Déplacer vers la gauche
    D Déplacer vers la droite
    W Déplacer vers le haut
    S Déplacer vers le bas
    F ou virgule Bouton central
    R ou Échap Bouton Retour

Commandes ADB

Vous pouvez utiliser les commandes car_service pour injecter des événements de saisie par dispositif rotatif. Ces commandes peut s'exécuter sur des appareils équipés d'Android Automotive OS (AAOS) ou sur un émulateur.

Commandes car_service Saisie par dispositif rotatif
adb shell cmd car_service inject-rotary Faire pivoter dans le sens inverse des aiguilles d'une montre
adb shell cmd car_service inject-rotary -c true Faire pivoter dans le sens des aiguilles d'une montre
adb shell cmd car_service inject-rotary -dt 100 50 Faire pivoter plusieurs fois dans le sens inverse des aiguilles d'une montre (il y a 100 ms et 50 ms avant)
adb shell cmd car_service inject-key 282 Déplacer vers la gauche
adb shell cmd car_service inject-key 283 Déplacer vers la droite
adb shell cmd car_service inject-key 280 Déplacer vers le haut
adb shell cmd car_service inject-key 281 Déplacer vers le bas
adb shell cmd car_service inject-key 23 Clic sur le bouton central
adb shell input keyevent inject-key 4 Clic sur le bouton Retour

Contrôleur rotatif OEM

Lorsque le matériel du contrôleur rotatif est opérationnel, réaliste. Elle est particulièrement utile pour tester la rotation rapide.

FocusParkingView

FocusParkingView est une vue transparente dans la Bibliothèque Car UI (car-ui-library). RotaryService l'utilise pour prendre en charge la navigation avec le contrôleur rotatif. FocusParkingView doit être la première vue sélectionnable dans la mise en page. Il doit être placé en dehors de tous les éléments FocusArea. Chaque fenêtre doit en comporter une FocusParkingView Si vous utilisez déjà la mise en page car-ui-library de base, qui contient un FocusParkingView, vous n'avez pas besoin d'en ajouter un autre FocusParkingView Vous trouverez ci-dessous un exemple de FocusParkingView dans RotaryPlayground

<FrameLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="match_parent">
   <com.android.car.ui.FocusParkingView
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"/>
   <FrameLayout
       android:layout_width="match_parent"
       android:layout_height="match_parent"/>
</FrameLayout>

Voici les raisons pour lesquelles vous avez besoin d'une FocusParkingView:

  1. Android n'efface pas automatiquement le curseur lorsqu'il est sélectionné dans une autre fenêtre. Si vous lorsque le curseur est désélectionné dans la fenêtre précédente, Android recentre une vue dans cette fenêtre, ce qui entraîne le focus de deux fenêtres simultanément. Ajouter un FocusParkingView à chaque fenêtre peut résoudre ce problème. Cette vue est transparente et la mise en surbrillance par défaut est désactivé, de sorte qu'il soit invisible à l'utilisateur, qu'il soit sélectionné ou non. Elle peut activer le focus de sorte que RotaryService puisse y placer le focus. pour supprimer la mise en surbrillance.
  2. S'il n'y a qu'un seul FocusArea dans la fenêtre actuelle, rotation du contrôleur dans FocusArea amène RotaryService à déplacer le curseur de la vue de droite vers la vue de gauche (et vice versa). Ajout de cette vue... à chaque fenêtre peut résoudre le problème. Lorsque RotaryService détermine le focus cible est un FocusParkingView, il peut déterminer qu'une enveloppe est sur le point se produit et, à ce stade, elle évite le contouring en ne déplaçant pas la mise au point.
  3. Lorsque le contrôleur rotatif lance une application, Android sélectionne la première vue sélectionnable, qui est toujours FocusParkingView. FocusParkingView détermine la vue optimale sur laquelle effectuer le focus, puis applique la mise au point.

Vues sélectionnables

RotaryService s'appuie sur le framework existants le concept de focalisation sur l'écran, remontant à l'époque où les téléphones avaient des claviers physiques et des pavés directionnels. L'attribut android:nextFocusForward existant a été redéfini pour le dispositif rotatif. (voir Personnalisation de l'élément FocusArea), mais android:nextFocusLeft, android:nextFocusRight, android:nextFocusUp et android:nextFocusDown ne le sont pas.

RotaryService se concentre uniquement sur les vues sélectionnables. Quelques vues, comme les Button, sont généralement sélectionnables. D'autres, comme les TextView et les ViewGroup, ne le sont généralement pas. Les vues cliquables sont automatiquement sélectionnables cliquables lorsqu'ils disposent d'un écouteur de clics. Si cette logique automatique permet d'obtenir vous n'avez pas besoin de la définir explicitement. Si la logique automatique ne obtenir la mise au point souhaitée, définissez l'attribut android:focusable sur true ou false, ou définissez par programmation la sélection de la vue avec View.setFocusable(boolean) Pour que RotaryService puisse se concentrer dessus, une vue DOIT doivent remplir les conditions suivantes:

  • Sélectionnable
  • Activé
  • Visible
  • avoir des valeurs non nulles pour la largeur et la hauteur ;

Si une vue ne remplit pas toutes ces conditions (par exemple, un bouton sélectionnable, mais désactivé), l'utilisateur ne peut pas utiliser le contrôle rotatif pour effectuer le focus dessus. Si vous souhaitez privilégier les vues désactivées, envisagez d'utiliser un état personnalisé plutôt que android:state_enabled pour contrôler la vue s'affiche sans indiquer qu'Android doit la considérer comme désactivée. Votre application peut informer pourquoi la vue est désactivée lorsqu'il appuie dessus. La section suivante explique comment procéder.

État personnalisé

Pour ajouter un état personnalisé:

  1. Ajouter un attribut personnalisé à votre vue. Par exemple, pour ajouter un état personnalisé state_rotary_enabled au Classe de vue CustomView, utilisez:
    <declare-styleable name="CustomView">
        <attr name="state_rotary_enabled" format="boolean" />
    </declare-styleable>
    
  2. Pour suivre cet état, ajoutez une variable d'instance à votre vue, ainsi que des méthodes d'accesseur:
    private boolean mRotaryEnabled;
    public boolean getRotaryEnabled() { return mRotaryEnabled; }
    public void setRotaryEnabled(boolean rotaryEnabled) {
        mRotaryEnabled = rotaryEnabled;
    }
    
  3. Pour lire la valeur de votre attribut lors de la création de la vue:
    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomView);
    mRotaryEnabled = a.getBoolean(R.styleable.CustomView_state_rotary_enabled);
    
  4. Dans votre classe de vue, remplacez la méthode onCreateDrawableState(), puis ajouter l'état personnalisé, le cas échéant. Par exemple:
    @Override
    protected int[] onCreateDrawableState(int extraSpace) {
        if (mRotaryEnabled) extraSpace++;
        int[] drawableState = super.onCreateDrawableState(extraSpace);
        if (mRotaryEnabled) {
            mergeDrawableStates(drawableState, { R.attr.state_rotary_enabled });
        }
        return drawableState;
    }
    
  5. Faites en sorte que le gestionnaire de clics de votre vue fonctionne différemment en fonction de son état. Par exemple, le gestionnaire de clics risque de ne rien faire ou d'afficher un toast lorsque mRotaryEnabled est false.
  6. Pour que le bouton apparaisse désactivé, utilisez le drawable d'arrière-plan de votre vue app:state_rotary_enabled au lieu de android:state_enabled. Si vous ne l'avez pas encore fait, vous devrez ajouter:
    xmlns:app="http://schemas.android.com/apk/res-auto"
    
  7. Si votre vue est désactivée dans l'une des mises en page, remplacez android:enabled="false" par app:state_rotary_enabled="false", puis ajoutez l'espace de noms app. comme indiqué ci-dessus.
  8. Si votre vue est désactivée de manière programmatique, remplacez les appels à setEnabled(). avec des appels à setRotaryEnabled().

Zone ciblée

Utilisez FocusAreas pour partitionner les vues sélectionnables en blocs afin de faciliter la navigation. plus facile et d’être cohérent avec les autres applications. Par exemple, si votre application dispose d'une barre d'outils, celle-ci doit se trouver dans un FocusArea distinct du reste de votre application. Barres d'onglets et les autres éléments de navigation doivent également être séparés du reste de l'application. Listes volumineuses doivent généralement avoir leur propre FocusArea. Si ce n'est pas le cas, ils doivent alterner toute la liste pour accéder à certaines vues.

FocusArea est une sous-classe de LinearLayout dans la bibliothèque car-ui-library. Lorsque cette fonctionnalité est activée, FocusArea trace une mise en surbrillance lorsque l'une de ses descendants est ciblé. Pour en savoir plus, consultez Personnalisation de la sélection de mise en surbrillance :

Lors de la création d'un bloc de navigation dans le fichier de mise en page, si vous prévoyez d'utiliser un LinearLayout en tant que conteneur pour ce bloc, utilisez plutôt FocusArea. Sinon, encapsulez le bloc dans une FocusArea.

N'imbriquez PAS un FocusArea dans un autre FocusArea. Cela entraîne un comportement de navigation non défini. Assurez-vous que toutes les vues sélectionnables sont imbriquées dans une FocusArea.

Un exemple de FocusArea dans RotaryPlayground est affiché ci-dessous:

<com.android.car.ui.FocusArea
       android:layout_margin="16dp"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:orientation="vertical">
       <EditText
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:singleLine="true">
       </EditText>
   </com.android.car.ui.FocusArea>

FocusArea fonctionne comme suit:

  1. Lors de la gestion des actions de rotation et de déplacement, RotaryService recherche des instances de FocusArea dans la hiérarchie des vues.
  2. Lors de la réception d'un événement de rotation, RotaryService déplace le curseur vers un autre Vue pouvant être sélectionnée dans le même FocusArea.
  3. Lors de la réception d'un événement de rappel, RotaryService déplace le curseur vers une autre vue qui peut s'activer dans un autre élément FocusArea (généralement adjacent)

Si vous n'incluez aucun FocusAreas dans votre mise en page, la vue racine est traitée en tant que zone d'action implicite. L'utilisateur ne parvient pas à naviguer dans l'application. Au lieu de cela, ils faire pivoter toutes les vues sélectionnables, ce qui peut convenir pour les boîtes de dialogue.

Personnalisation de FocusArea

Vous pouvez utiliser deux attributs d'affichage standards pour personnaliser la navigation par dispositif rotatif:

  • android:nextFocusForward permet aux développeurs d'applications de spécifier la rotation dans un domaine donné. Il s'agit du même attribut utilisé pour contrôler l'ordre de tabulation pour la navigation au clavier. N'utilisez PAS cet attribut pour créer une boucle. Utilisez plutôt app:wrapAround (voir ci-dessous) pour créer une boucle.
  • android:focusedByDefault permet aux développeurs d'applications de spécifier le par défaut dans la fenêtre. N'utilisez PAS cet attribut. app:defaultFocus (voir ci-dessous) dans le même FocusArea.

FocusArea définit également certains attributs pour personnaliser la navigation par dispositif rotatif. Ces attributs ne permettent pas de personnaliser des zones d'action implicites.

  1. (Android 11 QPR3, Android 11 Car, Android 12)
    app:defaultFocus permet de spécifier l'ID d'une vue descendante sélectionnable, à mettre en évidence lorsque l'utilisateur rappels automatiques concernant ce FocusArea.
  2. (Android 11 QPR3, Android 11 Car, Android 12)
    app:defaultFocusOverridesHistory peut être définie sur true pour que la vue spécifiée ci-dessus soit mise en évidence, même si avec pour indiquer qu'une autre vue de ce FocusArea était sélectionnée.
  3. (Android 12)
    Utiliser app:nudgeLeftShortcut, app:nudgeRightShortcut, app:nudgeUpShortcut et app:nudgeDownShortcut pour spécifier l'ID d'une vue descendante sélectionnable, à mettre en surbrillance lorsque la des encouragements de l’utilisateur dans une direction donnée. Pour en savoir plus, consultez le contenu de raccourcis rapides ci-dessous.

    (Android 11 QPR3, Android 11 Car, obsolète dans Android 12) app:nudgeShortcut et app:nudgeShortcutDirection n'acceptaient qu'un seul raccourci de rappel automatique.

  4. (Android 11 QPR3, Android 11 Car, Android 12)
    Pour activer la rotation afin d'encapsuler le FocusArea, app:wrapAround peut être défini sur true. Cette méthode est généralement utilisée lorsque les vues sont organisées cercle ou ovale.
  5. (Android 11 QPR3, Android 11 Car, Android 12)
    Pour ajuster la marge intérieure de la mise en surbrillance dans ce FocusArea, utilisez app:highlightPaddingStart, app:highlightPaddingEnd, app:highlightPaddingTop, app:highlightPaddingBottom, app:highlightPaddingHorizontal et app:highlightPaddingVertical.
  6. (Android 11 QPR3, Android 11 Car, Android 12)
    Pour ajuster les limites perçues de ce FocusArea afin de trouver une cible de rappel, utiliser app:startBoundOffset, app:endBoundOffset, app:topBoundOffset, app:bottomBoundOffset, app:horizontalBoundOffset et app:verticalBoundOffset.
  7. (Android 11 QPR3, Android 11 Car, Android 12)
    Pour spécifier explicitement l'identifiant FocusArea (ou zones) adjacentes dans un itinéraire donné, utilisez app:nudgeLeft, app:nudgeRight, app:nudgeUp et app:nudgeDown Utilisez cette option lorsque la recherche géométrique utilisée par défaut n'a pas trouvé la cible souhaitée.

Les rappels automatiques permettent généralement de passer d'une section FocusAreas à une autre. Mais avec les raccourcis de rappel, parfois d'abord naviguer dans un FocusArea afin que l'utilisateur puisse avoir besoin pour basculer deux fois vers l'élément FocusArea suivant. Les raccourcis de type "Décaler" sont utiles Lorsqu'un FocusArea contient une longue liste suivie d'un Bouton d'action flottant, comme dans l'exemple ci-dessous:

Raccourci (décaler)
Figure 3. Raccourci "Décaler"

Sans le raccourci de rappel automatique, l'utilisateur devrait faire défiler la liste entière pour atteindre le bouton d'action flottant.

Sélectionner la personnalisation de la sélection

Comme indiqué ci-dessus, RotaryService s'appuie sur le concept existant de sélection d'affichage. Lorsque l'utilisateur effectue une rotation et des encouragements, RotaryService déplace le curseur, une vue et une autre. Dans Android, lorsqu'une vue est sélectionnée, si elle:

  • A défini sa propre mise en surbrillance du curseur, Android la dessine dans la vue.
  • Ne spécifie pas de mise en surbrillance du curseur et celle par défaut n'est pas désactivée, Android affiche la mise en surbrillance par défaut de la vue.

En général, les applications conçues pour l'écran tactile n'affichent pas les zones de surbrillance appropriées.

La mise en surbrillance par défaut est fournie par le framework Android et peut être remplacée par l'OEM. Les développeurs d'applications la reçoivent lorsque le thème qu'ils utilisent est dérivé de Theme.DeviceDefault

Pour une expérience utilisateur cohérente, utilisez autant que possible la mise en surbrillance par défaut. Si vous avez besoin d'une mise en surbrillance personnalisée (par exemple, ronde ou en forme de pilule), ou si vous à l'aide d'un thème non dérivé de Theme.DeviceDefault, utilisez la bibliothèque car-ui-library. pour spécifier votre propre mise en surbrillance pour chaque vue.

Pour spécifier une mise en surbrillance personnalisée d'une vue, modifiez le drawable d'arrière-plan ou de premier plan de la vue en un drawable qui diffère lorsque la vue est sélectionnée. En général, vous devez remplacer en arrière-plan. Le drawable suivant, s'il est utilisé comme arrière-plan d'une vue carrée, produit une mise en surbrillance circulaire:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
   <item android:state_focused="true" android:state_pressed="true">
      <shape android:shape="oval">
         <solid android:color="@color/car_ui_rotary_focus_pressed_fill_color"/>
         <stroke
            android:width="@dimen/car_ui_rotary_focus_pressed_stroke_width"
            android:color="@color/car_ui_rotary_focus_pressed_stroke_color"/>
      </shape>
   </item>
   <item android:state_focused="true">
      <shape android:shape="oval">
         <solid android:color="@color/car_ui_rotary_focus_fill_color"/>
         <stroke
            android:width="@dimen/car_ui_rotary_focus_stroke_width"
            android:color="@color/car_ui_rotary_focus_stroke_color"/>
      </shape>
   </item>
   <item>
      <ripple...>
         ...
      </ripple>
   </item>
</selector>

(Android 11 QPR3, Android 11 Car, Android 12) Bold (Références de ressources en gras) dans l'exemple ci-dessus, pour identifier les ressources définies par la bibliothèque car-ui-library. L'OEM les remplace par des valeurs cohérentes avec la mise en surbrillance par défaut qu'elles spécifient. Cela garantit que la couleur de mise en surbrillance du focus, l'épaisseur du trait, etc., ne changent pas lorsque l'utilisateur passe d'une vue à l'autre avec un focus personnalisé ; et une vue avec la mise en surbrillance par défaut. Le dernier élément est une ondulation utilisée pour le toucher. Les valeurs par défaut utilisées pour les ressources en gras s'affichent comme suit:

Valeurs par défaut pour les ressources en gras
Figure 4. Valeurs par défaut pour les ressources en gras

De plus, une mise en surbrillance personnalisée est appelée lorsque le bouton couleur d'arrière-plan pour attirer l'attention de l'utilisateur, comme dans l'exemple ci-dessous. Cela peut rendre mise en surbrillance difficile à voir. Dans ce cas, spécifiez une mise en surbrillance personnalisée à l'aide de couleurs secondaires:

Couleur d&#39;arrière-plan unie
  • (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

Exemple :

Concentré, pas appuyé Concentré, appuyé
Concentré, pas appuyé Concentré, pressé

Défilement par dispositif rotatif

Si votre application utilise des RecyclerView, vous DEVEZ utiliser CarUiRecyclerView à la place. Cela garantit que votre UI est cohérente avec d'autres, car la personnalisation d'un OEM s'applique à tous les CarUiRecyclerView.

Si tous les éléments de votre liste sont sélectionnables, vous n'avez rien d'autre à faire. La navigation par dispositif rotatif déplace le curseur entre les éléments de la liste et celle-ci défile pour que l'élément sélectionné soit visible.

(Android 11 QPR3, Android 11 Car, Android 12)
S'il y a à la fois des éléments sélectionnables et non sélectionnables ou si tous les éléments ne sont pas sélectionnables, vous pouvez activer le défilement par dispositif rotatif, l'utilisateur d'utiliser le contrôleur rotatif pour faire défiler progressivement la liste sans l'ignorer. éléments non sélectionnables. Pour activer le défilement par dispositif rotatif, définissez app:rotaryScrollEnabled à true.

(Android 11 QPR3, Android 11 Car, Android 12)
Vous pouvez activer le défilement rotatif vue déroulante, y compris avCarUiRecyclerView, avec setRotaryScrollEnabled() dans CarUiUtils. Dans ce cas, vous devez:

  • Faites en sorte que la vue déroulante soit sélectionnable lorsqu'aucun de ses les vues descendantes sélectionnables sont visibles,
  • Désactivez la mise en surbrillance par défaut du focus sur la vue déroulante en appelant setDefaultFocusHighlightEnabled(false) afin que la vue déroulante ne semble pas être sélectionné,
  • Assurez-vous que la vue déroulante est sélectionnée avant ses descendants en appelant setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS)
  • Écoutez les MotionEvents avec SOURCE_ROTARY_ENCODER et au choix AXIS_VSCROLL ou AXIS_HSCROLL pour indiquer la distance à faire défiler et (à travers le panneau).

Lorsque le défilement par dispositif rotatif est activé sur une CarUiRecyclerView et que l'utilisateur effectue une rotation à une zone où aucune vue sélectionnable n'est présente, la barre de défilement passe du gris au bleu, comme si pour indiquer que la barre de défilement est active. Vous pouvez implémenter un effet similaire si vous le souhaitez.

Les MotionEvents sont identiques à ceux générés par une molette sur une souris, à l'exception de la source.

Mode de manipulation directe

Normalement, les encouragements et la rotation parcourent l'interface utilisateur, tandis que le bouton central prendre des mesures, même si ce n'est pas toujours le cas. Par exemple, si un utilisateur souhaite ajuster le le volume de l'alarme, il peut utiliser le contrôleur rotatif pour accéder au curseur de volume, appuyer sur le bouton central, faites pivoter la télécommande pour régler le volume de l'alarme, puis appuyez sur le bouton "Retour" pour revenir à la navigation. C'est ce que l'on appelle le mode de manipulation directe (DM). Dans ce le contrôleur rotatif permet d'interagir directement avec la vue au lieu de naviguer.

Vous disposez de deux méthodes pour implémenter la gestion des données. Si vous avez uniquement besoin de gérer la rotation et la vue que vous souhaitez de manipulation répond à ACTION_SCROLL_FORWARD et ACTION_SCROLL_BACKWARD AccessibilityEvents de manière appropriée, utilisez le mécanisme simple. Sinon, utilisez le mécanisme avancé.

Le mécanisme simple est la seule option dans les fenêtres système ; les applications peuvent utiliser l'un ou l'autre de ces mécanismes.

Mécanisme simple

(Android 11 QPR3, Android 11 Car, Android 12)
Votre application doit appeler DirectManipulationHelper.setSupportsRotateDirectly(View view, boolean enable) RotaryService détecte quand l'utilisateur est en mode MP et passe en mode MP lorsqu'il appuie sur le bouton central lorsqu'une vue est sélectionnée. En mode MP, les rotations ACTION_SCROLL_FORWARD ou ACTION_SCROLL_BACKWARD, et quitte le mode MP lorsque l'utilisateur appuie sur le bouton Retour. Le mécanisme simple active ou désactive la vue lorsque vous activez ou quittez le mode MP.

Pour indiquer visuellement que l'utilisateur est en mode MP, faites en sorte que votre vue soit différente. lorsque cette option est sélectionnée. Par exemple, modifiez l'arrière-plan lorsque android:state_selected est true.

Mécanisme avancé

L'application détermine quand RotaryService passe en mode MP ou le quitte. Pour une expérience utilisateur, le fait d'appuyer sur le bouton central alors que la vue DM est activée doit passer en mode MP et le bouton Retour doit quitter le mode MP. Si vous n'utilisez pas le bouton central et/ou le rappel automatique, il peut s'agir d'autres moyens de quitter le mode MP. Pour les applications telles que Maps, un bouton représentant Vous pouvez utiliser le MP pour passer en mode MP.

Pour prendre en charge le mode MP avancé, une vue:

  1. (Android 11 QPR3, Android 11 Car, Android 12) DOIT écouter un KEYCODE_DPAD_CENTER pour passer en mode MP et écouter l'événement KEYCODE_BACK pour quitter le mode MP, en appelant DirectManipulationHelper.enableDirectManipulationMode() dans chaque cas. Pour écouter ces événements, effectuez l'une des opérations suivantes: <ph type="x-smartling-placeholder">
      </ph>
    • Enregistrez un OnKeyListener.
    • ou
    • Étendez la vue, puis remplacez sa méthode dispatchKeyEvent().
  2. DEVRAIT écouter les événements de rappel automatique (KEYCODE_DPAD_UP, KEYCODE_DPAD_DOWN, KEYCODE_DPAD_LEFT ou KEYCODE_DPAD_RIGHT) si la vue doit gérer les rappels automatiques.
  3. DEVRAIT écouter MotionEvent et obtenir le nombre de rotations dans AXIS_SCROLL si la vue souhaite gérer la rotation. Pour ce faire, vous disposez de différentes méthodes: <ph type="x-smartling-placeholder">
      </ph>
    1. Enregistrez un OnGenericMotionListener.
    2. Étendez la vue et ignorez sa méthode dispatchTouchEvent().
  4. Pour éviter d'être bloqué en mode DM, vous DEVEZ quitter le mode DM lorsque le fragment ou l'activité de la vue appartient n'est pas interactive.
  5. DEVRAIT fournir un indicateur visuel indiquant que la vue est en mode MP.

Vous trouverez ci-dessous un exemple d'une vue personnalisée qui utilise le mode MP pour effectuer un panoramique et un zoom sur une carte:

/** Whether this view is in DM mode. */
private boolean mInDirectManipulationMode;

/** Initializes the view. Called by the constructors. */ private void init() { setOnKeyListener((view, keyCode, keyEvent) -> { boolean isActionUp = keyEvent.getAction() == KeyEvent.ACTION_UP; switch (keyCode) { // Always consume KEYCODE_DPAD_CENTER and KEYCODE_BACK events. case KeyEvent.KEYCODE_DPAD_CENTER: if (!mInDirectManipulationMode && isActionUp) { mInDirectManipulationMode = true; DirectManipulationHelper.enableDirectManipulationMode(this, true); setSelected(true); // visually indicate DM mode } return true; case KeyEvent.KEYCODE_BACK: if (mInDirectManipulationMode && isActionUp) { mInDirectManipulationMode = false; DirectManipulationHelper.enableDirectManipulationMode(this, false); setSelected(false); } return true; // Consume controller nudge events only when in DM mode. // When in DM mode, nudges pan the map. case KeyEvent.KEYCODE_DPAD_UP: if (!mInDirectManipulationMode) return false; if (isActionUp) pan(0f, -10f); return true; case KeyEvent.KEYCODE_DPAD_DOWN: if (!mInDirectManipulationMode) return false; if (isActionUp) pan(0f, 10f); return true; case KeyEvent.KEYCODE_DPAD_LEFT: if (!mInDirectManipulationMode) return false; if (isActionUp) pan(-10f, 0f); return true; case KeyEvent.KEYCODE_DPAD_RIGHT: if (!mInDirectManipulationMode) return false; if (isActionUp) pan(10f, 0f); return true; // Don't consume other key events. default: return false; } });
// When in DM mode, rotation zooms the map. setOnGenericMotionListener(((view, motionEvent) -> { if (!mInDirectManipulationMode) return false; float scroll = motionEvent.getAxisValue(MotionEvent.AXIS_SCROLL); zoom(10 * scroll); return true; })); }
@Override public void onPause() { if (mInDirectManipulationMode) { // To ensure that the user doesn't get stuck in DM mode, disable DM mode // when the fragment is not interactive (e.g., a dialog shows up). mInDirectManipulationMode = false; DirectManipulationHelper.enableDirectManipulationMode(this, false); } super.onPause(); }

Vous trouverez d'autres exemples dans le Projet RotaryPlayground.

ActivityView

Lorsque vous utilisez une ActivityView:

  • ActivityView ne doit pas être sélectionnable.
  • (Android 11 QPR3, Android 11 Car, obsolète dans Android 11)
    Le contenu de ActivityView DOIT contenir un FocusParkingView en tant que première vue sélectionnable, et son app:shouldRestoreFocus L'attribut DOIT être false.
  • Le contenu de ActivityView ne doit pas comporter android:focusByDefault vues.

Pour l'utilisateur, les ActivityViews ne devraient avoir aucun effet sur la navigation, à l'exception de cette sélection. zones ne peuvent pas s'étendre sur des ActivityViews. En d'autres termes, vous ne pouvez pas avoir un seul domaine d'action qui comporte du contenu à l'intérieur et à l'extérieur d'un ActivityView. Si vous n'ajoutez pas des FocusAreas vers votre ActivityView, la racine de la hiérarchie des vues dans le ActivityView est considéré comme une zone de mise au point implicite.

Boutons qui fonctionnent lorsqu'ils sont enfoncés

La plupart des boutons déclenchent des actions lorsque l'utilisateur clique dessus. Certains boutons fonctionnent quand ils sont enfoncés. Par exemple, les boutons Avance rapide et Retour arrière fonctionnent généralement lorsqu'ils sont enfoncés. Pour que ces boutons compatibles avec le dispositif rotatif, écouter KEYCODE_DPAD_CENTER KeyEvents comme suit:

mButton.setOnKeyListener((v, keyCode, event) ->
{
    if (keyCode != KEYCODE_DPAD_CENTER) {
        return false;
    }
    if (event.getAction() == ACTION_DOWN) {
        mButton.setPressed(true);
        mHandler.post(mRunnable);
    } else {
        mButton.setPressed(false);
        mHandler.removeCallbacks(mRunnable);
    }
    return true;
});

mRunnable effectue une action (comme un retour arrière) et se programme s'exécuter après un certain délai.

Mode Écran tactile

Les utilisateurs peuvent utiliser un contrôleur rotatif pour interagir avec l'unité principale d'une voiture de deux manières : soit à l'aide du contrôleur rotatif, soit en touchant l'écran. Lorsque vous utilisez le contrôleur rotatif, l'une des vues sélectionnables est mise en surbrillance. Lorsque l'utilisateur appuie sur l'écran, la mise en surbrillance n'est pas sélectionnée s'affiche. L'utilisateur peut passer d'un mode de saisie à l'autre à tout moment:

  • Rotatif → toucher Lorsque l'utilisateur touche l'écran, la mise en surbrillance disparaît.
  • Appuyez sur → dispositif rotatif. Lorsque l'utilisateur pousse l'utilisateur, le fait pivoter ou appuie sur le bouton central, le surligner du texte sélectionné.

Les boutons "Retour" et "Accueil" n'ont aucun effet sur le mode de saisie.

Des superpositions rotatives sur le concept actuel d'Android mode tactile. Vous pouvez utiliser View.isInTouchMode() pour déterminer le mode de saisie utilisé par l'utilisateur. Vous pouvez utiliser OnTouchModeChangeListener pour écouter les changements. Cela permet de personnaliser votre interface utilisateur pour l'état actuel d'entrée utilisateur, évitez d'apporter des modifications majeures, car elles peuvent déconcentrer.

Dépannage

Dans une application conçue pour l'écran tactile, il est courant d'avoir des vues sélectionnables imbriquées. Par exemple, il peut y avoir un FrameLayout autour d'un ImageButton, qui sont toutes deux sélectionnables. Cela ne nuit pas au toucher, mais peut nuire l'expérience utilisateur pour le contrôleur rotatif, car l'utilisateur doit faire pivoter le contrôleur deux fois la vue interactive suivante. Pour une expérience utilisateur de qualité, Google vous recommande d'effectuer l'une des opérations suivantes : la vue extérieure ou la vue intérieure sélectionnable, mais pas les deux.

Si un bouton ou un commutateur perd sa focus lorsqu'on appuie sur le contrôleur rotatif, l'un des ces conditions peuvent s'appliquer:

  • Le bouton ou l'interrupteur est désactivé (brièvement ou indéfiniment) en raison de la d'un utilisateur. Dans les deux cas, il existe deux façons de résoudre ce problème: <ph type="x-smartling-placeholder">
      </ph>
    • Laissez l'état android:enabled défini sur true et utilisez une valeur personnalisée pour griser le bouton ou le commutateur, comme décrit dans État personnalisé.
    • Utiliser un conteneur pour entourer le bouton ou le commutateur et rendre le conteneur sélectionnable au lieu du bouton ou du commutateur. (L'écouteur de clics doit se trouver sur le conteneur.)
  • Le bouton ou l'interrupteur est en cours de remplacement. Par exemple, l'action effectuée lorsque le bouton est activé ou le bouton bascule peut déclencher l'actualisation des actions disponibles. entraînant le remplacement des nouveaux boutons par de nouveaux boutons. Il existe deux façons de résoudre ce problème: <ph type="x-smartling-placeholder">
      </ph>
    • Au lieu de créer un bouton ou un commutateur, définissez l'icône et/ou le texte bouton ou commutateur existant.
    • Comme indiqué ci-dessus, ajoutez un conteneur sélectionnable autour du bouton ou du commutateur.

RotaryPlayground

RotaryPlayground est une application de référence pour le dispositif rotatif. Utilisez-le pour apprendre à intégrer les fonctionnalités rotatives dans vos applications. RotaryPlayground est inclus dans les builds de l'émulateur et dans pour les appareils exécutant Android Automotive OS (AAOS).

  • Dépôt RotaryPlayground: packages/apps/Car/tests/RotaryPlayground/
  • Versions: Android 11 QPR3, Android 11 Car, et Android 12

L'application RotaryPlayground affiche les onglets suivants à gauche:

  • Fiches. Testez la navigation dans les zones d'action, en ignorant les éléments non sélectionnables. et la saisie de texte.
  • Manipulation directe : Tester les widgets compatibles avec les méthodes simples et avancées de manipulation directe. Cet onglet est destiné à la manipulation directe dans la fenêtre de l'application.
  • Manipulation de l'interface utilisateur système. Tester les widgets compatibles avec la manipulation directe dans les fenêtres système où seul le mode de manipulation directe simple est pris en charge.
  • Grille : Testez la navigation par dispositif rotatif en forme de Z avec défilement.
  • Notification. Testez les rappels automatiques pour recevoir et sortir des notifications prioritaires.
  • Faire défiler. Testez le défilement entre les éléments sélectionnables et non sélectionnables. contenus.
  • WebView : Testez la navigation entre les liens dans un WebView.
  • FocusArea personnalisé. Testez la personnalisation de FocusArea:
    • Enveloppez.
    • android:focusedByDefault et app:defaultFocus
    • .
    • Cibles de rappel explicites.
    • Décaler les raccourcis.
    • FocusArea sans vue sélectionnable.