Exécuter des commandes

Cette page explique comment exécuter des commandes avec l'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 (telles que Spotify installé dans AAOS).
  • Sources multimédias de backend (comme la musique diffusée en streaming via VIA).
  • Sources média 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 obtenir une explication détaillée sur l'utilisation de ces API).

Important : Pour qu'une application d'assistance se connecte à l'MediaBrowseService de toutes les applications multimédias installées dans le système, elle doit :

  1. être installée avec une signature système (consultez les consignes de développement d'applications multimédias pour AAOS et l'exemple de code PackageValidator).
  2. Détenir l'autorisation android.permission.MEDIA_CONTENT_CONTROL avec privilèges système (voir Accorder des autorisations avec privilèges système).

En plus de MediaBrowserCompat et MediaControllerCompat, AAOS fournit les éléments suivants :

  • CarMediaService fournit des informations centralisées sur la source multimédia actuellement sélectionnée. Il est également utilisé pour reprendre la lecture d'une source multimédia précédemment en cours de lecture après un redémarrage de la voiture.
  • car-media-common fournit des méthodes pratiques pour lister, se connecter et interagir avec les 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 en filtrant les services correspondant à MediaBrowserService.SERVICE_INTERFACE. Dans certains véhicules, il peut exister des implémentations spéciales du service de navigateur multimédia, 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;
}

Notez 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 pour obtenir la source multimédia actuellement sélectionnée et lorsque cette source multimédia change. Ces modifications peuvent se produire parce que l'utilisateur a interagi directement avec l'UI ou en utilisant les boutons matériels de 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é sur la façon de 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

Avec un MediaBrowserCompat connecté, il est facile d'envoyer des commandes de contrôle du 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 de sources multimédias locales (radio, lecteur CD, Bluetooth, USB)

Les sources multimédias locales exposent leur fonctionnalité au système à l'aide des mêmes API MediaSession et MediaBrowse détaillées ci-dessus. Pour tenir compte des spécificité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 Radio MediaBrowseService peut être identifié par le filtre d'intent ACTION_PLAY_BROADCASTRADIO. Ils doivent suivre la structure des commandes de lecture et de navigation multimédia décrite dans Implémenter la radio. AAOS propose la bibliothèque car-broadcastradio-support qui contient 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. Elle est également compatible avec les applications qui consomment leur arborescence de navigation (par exemple, les VPA).

Gérer l'entrée auxiliaire, l'audio du CD et le support USB

Il n'existe aucune implémentation par défaut de ces sources multimédias dans AOSP. L'approche suggérée est la suivante :

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 MediaBrowserService et MediaSession qui abstrait les détails de communication (voir packages/apps/Bluetooth).

La structure arborescente du navigateur multimédia respectif est définie au niveau de la classe BrowseTree. Les commandes de contrôle de la lecture peuvent être fournies de la même manière que pour toute autre application, en utilisant son implémentation MediaSession.

Gérer les commandes de streaming multimédia

Pour implémenter le streaming multimédia côté serveur, le VAI doit lui-même devenir une source multimédia, en implémentant les API MediaBrowse et MediaSession. Consultez Créer des applications multimédias pour voitures. En implémentant ces API, une application de commande vocale pourrait (entre autres) :

  • Participez de manière fluide à la sélection de la source média
  • être automatiquement repris après le redémarrage de la voiture ;
  • Contrôler la lecture et la navigation à l'aide de l'interface utilisateur du Centre multimédia
  • Recevoir les événements standards des boutons multimédias du matériel

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 ces applications. Avant de lancer une intention vers une application (y compris Google Maps), vérifiez que l'intention peut être résolue (voir Intentions Google Maps). Cela permet d'informer l'utilisateur si l'application cible n'est pas disponible.

Exécuter des commandes de véhicule

L'accès aux propriétés du véhicule en lecture et en écriture est fourni par le biais de CarPropertyManager. Les types de propriétés de véhicule, leur implémentation et d'autres détails sont expliqués dans Configurations des 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 des propriétés standards et 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. Différentes propriétés ont différentes autorisations Android qui contrôlent leur accès. Ces autorisations sont déclarées dans le manifeste CarService, et le mappage entre les propriétés et les autorisations est décrit dans la documentation Javadoc VehiclePropertyIds et appliqué dans PropertyHalServiceIds.

Lire une propriété du 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é du véhicule

Voici un exemple montrant comment activer et désactiver 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 AV doivent gérer les messages entrants en suivant le flux "Appuyer pour lire" décrit dans Appuyer pour lire de l'assistant vocal, qui peut éventuellement gérer l'envoi de réponses à l'expéditeur du message entrant. De plus, les AV peuvent utiliser SmsManager (qui fait partie du package android.telephony) pour rédiger et envoyer des SMS directement depuis la voiture ou via Bluetooth.

Gérer les commandes d'appel

De même, les AVIN 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 AVIS interagissent directement avec la pile de téléphonie ou avec l'application Car Dialer. Dans tous les cas, c'est l'application Car Dialer qui doit afficher l'interface utilisateur 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 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 autre que l'interaction vocale elle-même.

Actions immersives (affichage de 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 la distraction du conducteur, veillez à ce que ces contenus soient simples, brefs et pratiques. Pour en savoir plus sur les consignes relatives à l'UI/UX pour les actions immersives, consultez Assistants préchargés : conseils sur l'UX.

Pour permettre la personnalisation et la cohérence avec le reste de la conception de l'unité principale (HU), les VPA doivent utiliser les composants de la bibliothèque Car UI pour la plupart des éléments d'interface utilisateur. Pour en savoir plus, consultez Personnalisation.