Communitygithub.com

android/skills

Adaptez vos applications Android existantes de streaming vidéo, jeux et navigateurs web pour qu'elles s'exécutent en tant qu'applications stationnées sur Android Auto et Android Automotive OS.

Qu'est-ce que skills ?

Cette compétence guide les développeurs dans l'adaptation d'applications Android existantes (streaming vidéo, jeux, navigateurs web) pour qu'elles fonctionnent comme des applications stationnées sur les plateformes Android Auto et Android Automotive OS. Elle couvre la configuration du manifeste, les déclarations de fonctionnalités matérielles pour le Google Play Store, le mode de compatibilité, les options de navigation arrière, la gestion de l'orientation et de la continuité d'affichage, les encarts de barres système, les découpes d'écran irrégulières, la gestion du cycle de vie en cas de distraction du conducteur, les restrictions de lecture MediaSession via CarUxRestrictionsManager, l'audio en arrière-plan pendant la conduite et la protection des données sensibles des navigateurs. Elle est utile pour les développeurs qui migrent ou créent des applications pour voitures et souhaitent respecter les directives de qualité des applications pour voitures de Google. Ne pas utiliser pour les applications audio, les applications de navigation, les applications de communication ou les applications IoT destinées à être utilisées pendant la conduite.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/android/skills/tree/HEAD/cars/android-for-cars-parked-apps

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Adaptez vos applications Android existantes de streaming vidéo, jeux et navigateurs web pour qu'elles s'exécutent en tant qu'applications stationnées sur Android Auto et Android Automotive OS. Suivez ces étapes pour respecter les directives de qualité des applications pour voitures en vue de leur distribution sur Google Play.

Prérequis

  • Commencez avec une application Android adaptative existante dans l'une des catégories d'applications stationnées prises en charge : applications de streaming vidéo, jeux ou navigateurs web.

Glossaire

  • Applications stationnées : Les applications stationnées s'exécutent sur Android Auto et Android Automotive OS uniquement lorsque le véhicule est à l'arrêt. Les trois catégories stationnées sont la vidéo, les jeux et les navigateurs ; les autres catégories ne peuvent pas être publiées en tant qu'applications stationnées.
  • Android Auto : Android Auto est un système de projection alimenté par le téléphone. Les applications s'exécutent sur le téléphone de l'utilisateur et sont projetées sur l'écran de la voiture via une connexion filaire ou sans fil. Android Auto est une plateforme distincte d'Android Automotive OS.
  • Android Automotive OS : Android Automotive OS, ou AAOS, est une variante d'Android qui s'exécute directement sur le véhicule lui-même. Android Automotive OS est une plateforme distincte d'Android Auto.
  • Catégorie vidéo : Les applications vidéo diffusent des vidéos en streaming pendant que le véhicule est à l'arrêt. Généralement disponible sur Android Automotive OS ; non prise en charge sur Android Auto.
  • Catégorie jeux : Les applications de jeux permettent de jouer pendant que le véhicule est à l'arrêt. Généralement disponibles sur Android Automotive OS et Android Auto.
  • Catégorie navigateurs : Les navigateurs web permettent aux utilisateurs de naviguer sur le web pendant que le véhicule est à l'arrêt. Disponible en version bêta sur Android Automotive OS ; non prise en charge sur Android Auto.
  • Catégorie média : Ce n'est pas une catégorie stationnée. Les applications média lisent du contenu audio (musique, radio, livres audio, à l'exclusion de la vidéo) pendant la conduite ou à l'arrêt.
  • Plateforme Android for Cars : Android for Cars est un terme générique qui regroupe Android Auto et Android Automotive OS.
  • Catégories généralement disponibles : Autorisées sur les pistes de test interne, test fermé, test ouvert et production de Google Play pour une plateforme prise en charge.
  • Catégories bêta : Autorisées sur les pistes de test interne ou fermé ; les pistes de test ouvert et production nécessitent une acceptation dans un programme d'accès anticipé.
  • Audio pendant la conduite : Une fonctionnalité bêta sur Android Automotive OS qui permet aux applications vidéo de lire de l'audio lorsque le véhicule est en mouvement.
  • Directives de qualité des applications pour voitures : Lors de l'audit d'une application par rapport aux critères de niveau 3 (Prêt pour la voiture), niveau 2 (Optimisé pour la voiture) ou niveau 1 (Différencié pour la voiture), DOIT vérifier les directives de qualité des applications pour voitures.
  • Mode de compatibilité Android Automotive OS : Le mode de compatibilité (android.software.car.display_compatibility) est une fonctionnalité système sur certains véhicules fournissant une fonction de retour système, un rendu de zone sûre, une mise à l'échelle de la densité et un blocage opaque en mode conduite (déplacement des activités vers l'état Stopped). Le mode de compatibilité n'est pertinent que pour les applications qui prennent en charge Android Automotive OS ; il n'est pas pertinent pour les applications qui ne prennent en charge que Android Auto.

Exploration du code source

Recherchez dans le code source les fichiers AndroidManifest.xml (ou créez Assets/Plugins/Android/AndroidManifest.xml dans les projets Unity), res/xml/automotive_app_desc.xml, build.gradle, build.gradle.kts ou gradle/libs.versions.toml. Localisez les lecteurs vidéo existants, les classes MediaSession, les appels requestedOrientation et les gestionnaires WindowInsets. Sauf instruction contraire de l'utilisateur, demandez la permission avant d'ajouter des dépendances.

Étape 1 : Configurer le manifeste de l'application

Déclarez la catégorie de l'application, les plateformes cibles, les exigences de fonctionnalités matérielles et la configuration des activités dans AndroidManifest.xml.

1.1 : Identifier la catégorie de l'application

  • Applications vidéo : Les applications vidéo DOIVENT définir android:appCategory="video" sur <application> et NE DOIVENT PAS inclure app/src/main/res/xml/automotive_app_desc.xml avec uses name="video".
  • Jeux : Les jeux DOIVENT définir android:appCategory="game" sur <application>. Déclarez android.hardware.gamepad avec android:required="false" si l'application prend en charge la saisie par manette.
  • Navigateurs : Les navigateurs DOIVENT inclure <category android:name="android.intent.category.APP_BROWSER"/> dans le <intent-filter> MAIN d'une <activity> exportée (android:exported="true").

1.2 : Identifier les plateformes cibles et les fonctionnalités matérielles

  • Android Auto : Les applications ciblant Android Auto (Android 15+) DOIVENT ajouter <category android:name="android.intent.category.CAR_LAUNCHER"/> à un <intent-filter> dans le fichier AndroidManifest.xml. Ajoutez-le au <intent-filter> MAIN sauf si l'utilisateur spécifie un autre filtre d'intention. NE JAMAIS ajouter cette catégorie si l'application cible uniquement Android Automotive OS.
  • Android Automotive OS : Les applications ciblant Android Automotive OS DOIVENT déclarer <uses-feature android:name="android.hardware.type.automotive" android:required="false"/> ("false" pour les pistes mobiles ou multi-facteurs de forme ; "true" uniquement si l'application sera publiée sur la piste dédiée Automotive OS) dans le fichier AndroidManifest.xml. NE JAMAIS ajouter cette balise de fonctionnalité si l'application cible uniquement Android Auto.
  • Fonctionnalités matérielles non requises (DO-1) : Pour satisfaire les exigences de fonctionnalités de Google Play et DO-1, déclarez les fonctionnalités non prises en charge (android.hardware.wifi, android.hardware.screen.portrait, android.hardware.screen.landscape, android.hardware.camera) avec android:required="false", et supprimez android:required="true" sur les fonctionnalités absentes dans les voitures.
  • Continuité d'affichage (LS-C1) : Configurez android:configChanges pour screenSize, smallestScreenSize, orientation, screenLayout et density sur <activity> afin que le passage vers ou depuis un écran distant ne recrée pas l'activité ou ne fasse pas hoqueter la lecture.
  • Mode de compatibilité et distraction : La déclaration du mode de compatibilité est facultative et n'est pertinente que pour les applications qui prennent en charge Android Automotive OS. NE JAMAIS ajouter le mode de compatibilité pour les applications qui ne prennent en charge que Android Auto. L'ajout de android.hardware.type.automotive désactive le mode de compatibilité à moins que <meta-data android:name="android.software.car.display_compatibility" android:value="true"/> ne soit ajouté à <application>. Lorsqu'une application déclare android.software.car.display_compatibility dans AndroidManifest.xml, l'application DOIT vérifier PackageManager.hasSystemFeature("android.software.car.display_compatibility") au moment de l'exécution et masquer les boutons de retour ou de fermeture redondants dans l'application lorsque cela renvoie true. Les applications stationnées NE DOIVENT PAS inclure <meta-data android:name="distractionOptimized" android:value="true"/> sur une <activity> (DD-2, DD-3).

Étape 2 : Fournir la navigation arrière et la prise en charge de l'orientation

2.1 : Ajouter des boutons de retour et de fermeture dans l'application

Les véhicules Android Automotive OS ne sont pas tenus d'avoir un bouton de retour matériel ou logiciel ni une navigation par gestes (AN-1). Fournissez des contrôles de retour et de fermeture explicites dans l'interface utilisateur sur chaque écran non racine, y compris les écrans de détail et les lecteurs plein écran :

  • Si AndroidManifest.xml ne déclare pas android.software.car.display_compatibility : Affichez les contrôles de retour et de fermeture dans l'application de manière inconditionnelle.
  • Si AndroidManifest.xml déclare android.software.car.display_compatibility avec android:value="true" : Affichez les contrôles de retour et de fermeture dans l'application uniquement lorsque PackageManager.hasSystemFeature("android.software.car.display_compatibility") renvoie false.

2.2 : Protéger les demandes d'orientation au moment de l'exécution

Les écrans des véhicules ont des orientations fixes. Demander le mode paysage sur un écran de voiture fixé en portrait provoque des boîtes aux lettres ou des boucles de scintillement (DO-1). Supprimez les attributs android:screenOrientation codés en dur du manifeste et vérifiez PackageManager.FEATURE_SCREEN_LANDSCAPE et PackageManager.FEATURE_SCREEN_PORTRAIT avant de définir requestedOrientation.

Étape 3 : S'adapter aux barres système et aux découpes d'écran irrégulières

3.1 : Suivre les encarts de barres système contrôlables

Sur Android Automotive OS, les OEM sont autorisés à verrouiller les barres système visibles afin que les commandes de climatisation et du véhicule restent accessibles (AR-1). Suivez les encarts contrôlables avec OnControllableInsetsChangedListener, masquez uniquement les barres contrôlables et appliquez windowInsetsPadding pour les encarts statusBars, navigationBars et displayCutout non contrôlables.

3.2 : Rendre les découpes d'écran irrégulières en toute sécurité

Pour répondre au critère de niveau 1 AR-2 sur les écrans incurvés ou non rectangulaires, NE JAMAIS utiliser LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT (0) ou LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES (1). Configurez LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS (3) ou LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER (2) en utilisant le qualificateur de ressource car dans res/values-car-v30/integers.xml :

<integer name="windowLayoutInDisplayCutoutMode">3</integer>

<!— saut de ligne intentionnel —>

Protégez l'interface utilisateur interactive, les barres d'application et les listes défilables avec WindowInsets.safeDrawing.

Étape 4 : Répondre aux exigences de distraction du conducteur et de lecture multimédia

4.1 : Mettre en pause la lecture lors des transitions du cycle de vie et bloquer la reprise en conduite

Lorsqu'un véhicule commence à se déplacer, le système d'exploitation recouvre les activités stationnées avec une superposition de blocage et déclenche onPause (et onStop sur les véhicules en mode de compatibilité). Pour satisfaire DD-2, DD-3 et MC-1 :

  1. Mettez en pause la lecture sur ON_PAUSE ou ON_STOP en utilisant LifecycleEventEffect de androidx.lifecycle:lifecycle-runtime-compose.
  2. Exposez un MediaSession (androidx.media3:media3-session) avec les commandes de lecture, pause ou arrêt et les métadonnées des éléments (MC-1), et libérez-le dans onCleared.
  3. Ajoutez useLibrary("android.car") dans build.gradle.kts, enveloppez ExoPlayer dans ForwardingSimpleBasePlayer, écoutez CarUxRestrictionsManager, mettez en pause la lecture lorsque isRequiresDistractionOptimization devient true, et supprimez COMMAND_PLAY_PAUSE dans getState afin que les contrôles MediaSession externes ne puissent pas reprendre la lecture pendant la conduite :
@UnstableApi
class CarAwarePlayer(context: Context) :
    ForwardingSimpleBasePlayer(ExoPlayer.Builder(context).build()) {
    private var shouldPreventPlay = false
    private var pausedByUxRestrictions = false
    private lateinit var carUxRestrictionsManager: CarUxRestrictionsManager

    init {
        if (context.packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
            val car = Car.createCar(context)
            carUxRestrictionsManager =
                car.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE) as CarUxRestrictionsManager
            shouldPreventPlay =
                carUxRestrictionsManager.currentCarUxRestrictions.isRequiresDistractionOptimization
            invalidateState()

            carUxRestrictionsManager.registerListener { restrictions: CarUxRestrictions ->
                shouldPreventPlay = restrictions.isRequiresDistractionOptimization
                if (!shouldPreventPlay && pausedByUxRestrictions) {
                    handleSetPlayWhenReady(true)
                    invalidateState()
                } else if (shouldPreventPlay && isPlaying) {
                    pausedByUxRestrictions = true
                    handleSetPlayWhenReady(false)
                    invalidateState()
                }
            }
        }
    }

    override fun getState(): State {
        val state = super.getState()
        return state.buildUpon()
            .setAvailableCommands(
                state.availableCommands.buildUpon()
                    .removeIf(COMMAND_PLAY_PAUSE, shouldPreventPlay)
                    .build()
            )
            .build()
    }

    override fun handleRelease(): ListenableFuture<*> {
        if (::carUxRestrictionsManager.isInitialized) {
            carUxRestrictionsManager.unregisterListener()
        }
        return super.handleRelease()
    }
}

<!— saut de ligne intentionnel —>

4.2 : Prendre en charge l'audio en arrière-plan pendant la conduite (fonctionnalité bêta facultative)

Comme il s'agit d'une fonctionnalité bêta facultative, NE JAMAIS implémenter cette fonctionnalité à moins que l'utilisateur ne le demande. Pour implémenter la fonctionnalité :

  1. Déclarez <uses-feature android:name="com.android.car.background_audio_while_driving" android:required="false" /> dans AndroidManifest.xml, ainsi que les permissions FOREGROUND_SERVICE et FOREGROUND_SERVICE_MEDIA_PLAYBACK.
  2. Vérifiez la prise en charge de la fonctionnalité par le véhicule au moment de l'exécution avec CarFeatures.isFeatureEnabled(context, CarFeatures.FEATURE_BACKGROUND_AUDIO_WHILE_DRIVING) de androidx.car.app:app. Ne définissez shouldPreventPlay que lorsque !isBackgroundAudioWhileDrivingSupported && restrictions.isRequiresDistractionOptimization.
  3. Hébergez le MediaSession et le lecteur dans un MediaSessionService exporté avec android:foregroundServiceType="mediaPlayback", et connectez-vous depuis l'interface utilisateur en utilisant MediaController.Builder et buildAsync.

Étape 5 : Protéger les données sensibles dans les applications de navigateur

Comme les véhicules sont des appareils partagés, les navigateurs DOIVENT bloquer l'accès aux mots de passe enregistrés et aux méthodes de paiement, sauf s'ils sont protégés par un verrouillage de profil (SD-1). Avant de synchroniser les mots de passe ou les données de paiement vers le véhicule, les navigateurs DOIVENT inviter l'utilisateur à s'authentifier et afficher un avis sur l'écran de la voiture indiquant que ses données seront synchronisées avec la voiture (SD-2).

Vérifiez si un code PIN, un schéma ou un mot de passe est défini à l'aide de KeyguardManager, ouvrez Settings.ACTION_SECURITY_SETTINGS s'il n'est pas défini, et authentifiez-vous avec BiometricPrompt en utilisant BiometricManager.Authenticators.DEVICE_CREDENTIAL uniquement (les véhicules n'ont pas de matériel biométrique) :

val keyguardManager = context.getSystemService<KeyguardManager>()
val isDeviceSecure = keyguardManager?.isDeviceSecure == true
lateinit var biometricPrompt: BiometricPrompt

if (!isDeviceSecure) {
    context.startActivity(
        Intent(Settings.ACTION_SECURITY_SETTINGS).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
    )
} else {
    val promptInfo = BiometricPrompt.PromptInfo.Builder()
        .setTitle(context.getString(R.string.auth_title))
        .setSubtitle(context.getString(R.string.sync_data_to_car_notice))
        .setAllowedAuthenticators(BiometricManager.Authenticators.DEVICE_CREDENTIAL)
        .build()
    biometricPrompt.authenticate(promptInfo)
}

<!— saut de ligne intentionnel —>

Étape 6 : Vérifier l'implémentation

Construisez l'application en utilisant ./gradlew assembleDebug. Trouvez et corrigez toute erreur de construction.

Post-implémentation

…

[tronqué pour la traduction]

Skills associés