Cette page explique comment exécuter des commandes via une interaction vocale.
Exécuter des commandes multimédias
Les commandes liées aux contenus multimédias peuvent être divisées en trois groupes:
- Sources multimédias externes (par exemple, Spotify installé dans AAOS)
- Sources multimédias backend (par exemple, musique diffusée via le VIA)
- Sources multimédias locales (comme la radio de la voiture).
Gérer les commandes de sources multimédias externes
Les sources multimédias externes sont définies comme des applications Android compatibles avec les API MediaSessionCompat
et MediaBrowseCompat
(consultez Créer des applications multimédias pour voitures pour en savoir plus sur l'utilisation de ces API).
Important:Pour qu'une application d'assistant puisse se connecter à la MediaBrowseService
de toutes les applications multimédias installées dans le système, elle doit:
- Être installé en tant que code signé par le système (voir les consignes de développement d'applications multimédias pour AAOS et l'exemple de code
PackageValidator
). - Détenir l'autorisation
android.permission.MEDIA_CONTENT_CONTROL
de niveau système (voir Accorder des autorisations de niveau système).
En plus de MediaBrowserCompat
et MediaControllerCompat
, AAO:
CarMediaService
fournit des informations centralisées sur la source multimédia actuellement sélectionnée. Cette commande permet également de reprendre une source multimédia en cours de lecture après l'arrêt et le redémarrage de la voiture.car-media-common
fournit des méthodes pratiques pour lister, se connecter et interagir avec des applications multimédias.
Vous trouverez ci-dessous des consignes spécifiques à l'implémentation des commandes d'interaction vocale courantes.
Obtenir la liste des sources multimédias installées
Les sources multimédias peuvent être détectées à l'aide de PackageManager
et filtrées pour les services correspondant à MediaBrowserService.SERVICE_INTERFACE
.
Dans certains véhicules, il peut y avoir des implémentations de services de navigateur multimédia spéciales, qui doivent être exclues. Voici un exemple de cette logique:
private Map<String, MediaSource> getAvailableMediaSources() { List<String> customMediaServices = Arrays.asList(mContext.getResources() .getStringArray(R.array.custom_media_packages)); List<ResolveInfo> mediaServices = mPackageManager.queryIntentServices( new Intent(MediaBrowserService.SERVICE_INTERFACE), PackageManager.GET_RESOLVED_FILTER); Map<String, MediaSource> result = new HashMap<>(); for (ResolveInfo info : mediaServices) { String packageName = info.serviceInfo.packageName; if (customMediaServices.contains(packageName)) { // Custom media sources should be ignored, as they might have a // specialized handling (e.g., radio). continue; } String className = info.serviceInfo.name; ComponentName componentName = new ComponentName(packageName, className); MediaSource source = MediaSource.create(mContext, componentName); result.put(source.getDisplayName().toString().toLowerCase(), source); } return result; }
Sachez que les sources multimédias peuvent être installées ou désinstallées à tout moment. Pour maintenir une liste précise, il est recommandé d'implémenter une instance BroadcastReceiver
pour les actions d'intent ACTION_PACKAGE_ADDED
, ACTION_PACKAGE_CHANGED
, ACTION_PACKAGE_REPLACED
et ACTION_PACKAGE_REMOVED
.
Se connecter à la source multimédia en cours de lecture
CarMediaService
fournit des méthodes permettant d'obtenir la source multimédia actuellement sélectionnée et de savoir quand elle change. Ces modifications peuvent se produire lorsque l'utilisateur interagit directement avec l'UI ou lorsqu'il utilise des boutons physiques dans la voiture. En revanche, la bibliothèque car-media-common offre des moyens pratiques de se connecter à une source multimédia donnée. Voici un extrait simplifié expliquant comment se connecter à l'application multimédia actuellement sélectionnée:
public class MediaActuator implements MediaBrowserConnector.onConnectedBrowserChanged { private final Car mCar; private CarMediaManager mCarMediaManager; private MediaBrowserConnector mBrowserConnector; … public void initialize(Context context) { mCar = Car.createCar(context); mBrowserConnector = new MediaBrowserConnector(context, this); mCarMediaManager = (CarMediaManager) mCar.getCarManager(Car.CAR_MEDIA_SERVICE); mBrowserConnector.connectTo(mCarMediaManager.getMediaSource()); … } @Override public void onConnectedBrowserChanged( @Nullable MediaBrowserCompat browser) { // TODO: Handle connected/disconnected browser } … }
Contrôler la lecture de la source multimédia en cours de lecture
Avec un MediaBrowserCompat
connecté, il est facile d'envoyer des commandes de contrôle de transport à l'application cible. Voici un exemple simplifié:
public class MediaActuator … { … private MediaControllerCompat mMediaController; @Override public void onConnectedBrowserChanged( @Nullable MediaBrowserCompat browser) { if (browser != null && browser.isConnected()) { mMediaController = new MediaControllerCompat(mContext, browser.getSessionToken()); } else { mMediaController = null; } } private boolean playSongOnCurrentSource(String song) { if (mMediaController == null) { // No source selected. return false; } MediaControllerCompat.TransportControls controls = mMediaController.getTransportControls(); PlaybackStateCompat state = controller.getPlaybackState(); if (state == null || ((state.getActions() & PlaybackStateCompat.ACTION_PLAY_FROM_SEARCH) == 0)) { // Source can't play from search return false; } controls.playFromSearch(query, null); return true; } … }
Gérer les commandes des sources multimédias locales (radio, lecteur CD, Bluetooth, USB)
Les sources multimédias locales exposent leurs fonctionnalités au système à l'aide des mêmes API MediaSession et MediaBrowse décrites ci-dessus. Pour tenir compte des particularités de chaque type de matériel, ces services MediaBrowse utilisent des conventions spécifiques pour organiser leurs informations et leurs commandes multimédias.
Gérer la radio
Le service MediaBrowserService de radio peut être identifié par le filtre d'intent ACTION_PLAY_BROADCASTRADIO
. Ils doivent respecter les commandes de lecture et la structure de navigation multimédia décrites dans la section Implémenter la radio. AAOS propose la bibliothèque car-broadcastradio-support
contenant des constantes et des méthodes pour aider les OEM à créer des implémentations MediaBrowseService pour leurs propres services radio qui suivent le protocole défini, et prend en charge les applications qui utilisent leur arborescence de navigation (par exemple, les VIA).
Gérer l'entrée auxiliaire, l'audio CD et les contenus multimédias USB
Aucune implémentation par défaut de ces sources multimédias n'est disponible dans AOSP. Voici l'approche suggérée:
- Demander aux OEM d'implémenter des services multimédias pour chacun d'eux. Pour en savoir plus, consultez Créer des applications multimédias pour voitures.
- Ces implémentations MediaBrowseService seront identifiées et traitées dans les actions d'intent définies dans la section Intents de lecture généraux.
- Ces services exposent un arbre de navigation conformément aux consignes décrites dans la section Autres types de sources.
Gérer le Bluetooth
Le contenu multimédia Bluetooth est exposé via le profil Bluetooth AVRCP. Pour faciliter l'accès à cette fonctionnalité, AAOS inclut une implémentation de MediaBrowserService et de MediaSession qui abstrait les détails de la communication (voir packages/apps/Bluetooth).
La structure arborescente du navigateur multimédia respectif est définie dans la classe BrowseTree. Les commandes de contrôle de la lecture peuvent être transmises comme n'importe quelle autre application, à l'aide de son implémentation MediaSession.
Gérer les commandes de streaming multimédia
Pour implémenter le streaming multimédia côté serveur, le VIA doit devenir lui-même une source multimédia, en implémentant les API MediaBrowse et MediaSession. Consultez la section Créer des applications multimédias pour voitures. En implémentant ces API, une application de commande vocale peut, entre autres :
- Participer facilement à la sélection de la source multimédia
- être automatiquement reprise après le redémarrage de la voiture ;
- Fournir des commandes de lecture et de navigation à l'aide de l'UI Media Center
- Recevoir des événements de bouton multimédia matériel standard
Exécuter les commandes de navigation
Il n'existe pas de méthode standardisée pour interagir avec toutes les applications de navigation. Pour les intégrations avec Google Maps, consultez Intents Google Maps pour Android Automotive. Pour les intégrations avec d'autres applications, contactez directement les développeurs de l'application. Avant de lancer un intent vers une application (y compris Google Maps), vérifiez qu'il peut être résolu (voir la section Requêtes d'intent). Vous pouvez ainsi informer l'utilisateur si l'application cible n'est pas disponible.
Exécuter les commandes du véhicule
L'accès aux propriétés du véhicule en lecture et en écriture est fourni via CarPropertyManager.
Les types de propriétés de véhicule, leur implémentation et d'autres informations sont expliqués dans la section Configurations de propriétés. Pour obtenir une description précise des propriétés compatibles avec Android, il est préférable de se référer directement à hardware/interfaces/automotive/vehicle/2.0/types.hal
.
L'énumération VehicleProperty définie ici contient à la fois des propriétés standards et des propriétés spécifiques au fournisseur, des types de données, un mode de modification, des unités et une définition d'accès en lecture/écriture.
Pour accéder à ces mêmes constantes depuis Java, vous pouvez utiliser VehiclePropertyIds et ses classes associées. Les différentes propriétés ont des autorisations Android différentes qui contrôlent leur accès. Ces autorisations sont déclarées dans le fichier manifeste CarService, et le mappage entre les propriétés et les autorisations décrit dans la documentation Javadoc VehiclePropertyIds et appliqué dans PropertyHalServiceIds.
Lire une propriété de véhicule
Voici un exemple montrant comment lire la vitesse du véhicule:
public class CarActuator ... { private final Car mCar; private final CarPropertyManager mCarPropertyManager; private final TextToSpeech mTTS; /** Global VHAL area id */ public static final int GLOBAL_AREA_ID = 0; public CarActuator(Context context, TextToSpeech tts) { mCar = Car.createCar(context); mCarPropertyManager = (CarPropertyManager) mCar.getCarManager(Car.PROPERTY_SERVICE); mTTS = tts; ... } @Nullable private void getSpeedInMetersPerSecond() { if (!mCarPropertyManager.isPropertyAvailable(VehiclePropertyIds.PERF_VEHICLE_SPEED, GLOBAL_AREA_ID)) { mTTS.speak("I'm sorry, but I can't read the speed of this vehicle"); return; } // Data type and unit can be found in // automotive/vehicle/2.0/types.hal float speedInMps = mCarPropertyManager.getFloatProperty( VehiclePropertyIds.PERF_VEHICLE_SPEED, GLOBAL_AREA_ID); int speedInMph = (int)(speedInMetersPerSecond * 2.23694f); mTTS.speak(String.format("Sure. Your current speed is %d miles " + "per hour", speedInUserUnit); } ... }
Définir une propriété de véhicule
Voici un exemple montrant comment allumer et éteindre la climatisation avant.
public class CarActuator … { … private void changeFrontAC(boolean turnOn) { List<CarPropertyConfig> configs = mCarPropertyManager .getPropertyList(new ArraySet<>(Arrays.asList( VehiclePropertyIds.HVAC_AC_ON))); if (configs == null || configs.size() != 1) { mTTS.speak("I'm sorry, but I can't control the AC of your vehicle"); return; } // Find the front area Ids for the AC property. int[] areaIds = configs.get(0).getAreaIds(); List<Integer> areasToChange = new ArrayList<>(); for (int areaId : areaIds) { if ((areaId & (VehicleAreaSeat.SEAT_ROW_1_CENTER | VehicleAreaSeat.SEAT_ROW_1_LEFT | VehicleAreaSeat.SEAT_ROW_1_RIGHT)) == 0) { continue; } boolean isACInAreaAlreadyOn = mCarPropertyManager .getBooleanProperty(VehiclePropertyIds.HVAC_AC_ON, areaId); if ((!isACInAreaAlreadyOn && turnOn) || (isACInAreaAlreadyOn && !turnOn)) { areasToChange.add(areaId); } } if (areasToChange.isEmpty()) { mTTS.speak(String.format("The AC is already %s", turnOn ? "on" : "off")); return; } for (int areaId : areasToChange) { mCarPropertyManager.setBooleanProperty( VehiclePropertyIds.HVAC_AC_ON, areaId, turnOn); } mTTS.speak(String.format("Okay, I'm turning your front AC %s", turnOn ? "on" : "off")); } … }
Exécuter des commandes de communication
Gérer les commandes de messagerie
Les assistants vocaux doivent gérer les messages entrants en suivant le flux "Appuyer pour lire" décrit dans Appuyer pour lire avec l'assistant vocal, qui peut éventuellement gérer l'envoi de réponses à l'expéditeur du message entrant.
De plus, les VIA peuvent utiliser SmsManager
(composant du package android.telephony
) pour composer et envoyer des SMS directement depuis la voiture ou via Bluetooth.
Gérer les commandes d'appel
De même, les VIA peuvent utiliser TelephonyManager
pour passer des appels téléphoniques et appeler le numéro de messagerie vocale de l'utilisateur. Dans ce cas, les VIA interagissent directement avec la pile de téléphonie ou avec l'application Téléphone de voiture. Dans tous les cas, l'application Téléphone de voiture doit être celle qui affiche l'UI liée aux appels vocaux à l'utilisateur.
Exécuter d'autres commandes
Pour obtenir la liste des autres points d'intégration possibles entre le VIA et le système, consultez la liste des intents Android bien connus. De nombreuses commandes utilisateur peuvent être résolues côté serveur (par exemple, la lecture des e-mails et des événements d'agenda des utilisateurs) et ne nécessitent aucune interaction avec le système, à l'exception de l'interaction vocale elle-même.
Actions immersives (afficher du contenu visuel)
Lorsqu'elle améliore les actions ou la compréhension des utilisateurs, une VIA peut fournir du contenu visuel supplémentaire sur l'écran de la voiture. Pour limiter les distractions du conducteur, faites en sorte que ces contenus soient simples, brefs et pratiques. Pour en savoir plus sur les consignes relatives à l'UI/UX concernant les actions immersives, consultez la section Assistants préchargés: conseils en matière d'expérience utilisateur.
Pour permettre la personnalisation et la cohérence avec le reste de la conception de l'unité principale (HU), les VIA doivent utiliser les composants de la bibliothèque d'UI pour voitures pour la plupart des éléments d'interface utilisateur. Pour en savoir plus, consultez la section Personnalisation.