Esegui i comandi

Questa pagina descrive come eseguire i comandi con l'interazione vocale.

Esegui i comandi multimediali

I comandi relativi ai media possono essere suddivisi in tre diversi gruppi:

  • Fonti multimediali esterne (come Spotify installato in AAOS).
  • Fonti multimediali backend (come la musica trasmessa in streaming tramite VIA).
  • Fonti mediatiche locali (come l'autoradio).

Gestire i comandi delle origini multimediali esterne

Le fonti multimediali esterne sono definite come app Android che supportano le API MediaSessionCompat e MediaBrowseCompat (fare riferimento a Creare app multimediali per auto per una spiegazione dettagliata sull'uso di queste API).

Importante: affinché un'app assistente possa connettersi a MediaBrowseService di tutte le app multimediali installate nel sistema, deve:

  1. Essere installato come sistema firmato (consulta le linee guida per lo sviluppo di applicazioni multimediali per AAOS e il codice di esempio PackageValidator ).
  2. Mantieni l'autorizzazione con privilegi di sistema android.permission.MEDIA_CONTENT_CONTROL (vedi Concedere autorizzazioni con privilegi di sistema ).

Oltre a MediaBrowserCompat e MediaControllerCompat , AAOS fornisce quanto segue:

  • CarMediaService fornisce informazioni centralizzate sulla fonte multimediale attualmente selezionata. Viene utilizzato anche per riprendere una fonte multimediale riprodotta in precedenza dopo lo spegnimento-riavvio dell'auto.
  • car-media-common fornisce metodi convenienti per elencare, connettere e interagire con le app multimediali.

Di seguito sono fornite le linee guida specifiche per l'implementazione dei comandi comuni di interazione vocale.

Ottieni un elenco delle fonti multimediali installate

Le origini multimediali possono essere rilevate utilizzando PackageManager e filtrando i servizi che corrispondono a MediaBrowserService.SERVICE_INTERFACE . In alcune auto potrebbero essere presenti implementazioni speciali del servizio browser multimediale, che dovrebbero essere escluse. Ecco un esempio di questa logica:

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;
}

Tieni presente che le fonti multimediali potrebbero essere installate o disinstallate in qualsiasi momento. Per mantenere un elenco accurato, si consiglia di implementare un'istanza BroadcastReceiver per le azioni di intento ACTION_PACKAGE_ADDED , ACTION_PACKAGE_CHANGED , ACTION_PACKAGE_REPLACED e ACTION_PACKAGE_REMOVED .

Connettersi alla sorgente multimediale attualmente in riproduzione

CarMediaService fornisce metodi per ottenere la fonte multimediale attualmente selezionata e quando questa fonte multimediale cambia. Questi cambiamenti potrebbero verificarsi perché l'utente ha interagito direttamente con l'interfaccia utente o a causa dell'uso dei pulsanti hardware nell'auto. D'altra parte, la libreria car-media-common offre modi convenienti per connettersi a una determinata fonte multimediale. Ecco uno snippet semplificato su come connettersi all'app multimediale attualmente selezionata:

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
    }

    …
}

Controlla la riproduzione della sorgente multimediale attualmente in riproduzione

Con un MediaBrowserCompat connesso è facile inviare comandi di controllo del trasporto all'app di destinazione. Ecco un esempio semplificato:

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;
    }

    …
}

Gestire i comandi della sorgente multimediale locale (radio, lettore CD, Bluetooth, USB)

Le fonti multimediali locali espongono le proprie funzionalità al sistema utilizzando le stesse API MediaSession e MediaBrowse descritte sopra. Per soddisfare le particolarità di ciascun tipo di hardware, questi servizi MediaBrowse utilizzano convenzioni specifiche per organizzare le informazioni e i comandi multimediali.

Gestire la radio

Radio MediaBrowseService può essere identificato dal filtro intent ACTION_PLAY_BROADCASTRADIO . Si prevede che seguano i controlli di riproduzione e la struttura di navigazione multimediale descritta in Implementare la radio . AAOS offre la libreria car-broadcastradio-support contenente costanti e metodi per aiutare gli OEM a creare implementazioni MediaBrowseService per i propri servizi radio che seguono il protocollo definito e fornisce supporto per le app che utilizzano il loro albero di navigazione (ad esempio, VIA).

Gestisce l'ingresso ausiliario, l'audio CD e il supporto USB

Non esiste un'implementazione predefinita di queste fonti multimediali come parte di AOSP. L’approccio suggerito è quello di:

Gestire il Bluetooth

Il contenuto multimediale Bluetooth viene esposto tramite il profilo Bluetooth AVRCP. Per facilitare l'accesso a questa funzionalità, AAOS include un'implementazione MediaBrowserService e MediaSession che estrae i dettagli della comunicazione (vedi pacchetti/app/Bluetooth ).

La rispettiva struttura ad albero del browser multimediale è definita nella classe SfogliaTree . I comandi di controllo della riproduzione possono essere forniti in modo simile a qualsiasi altra app, utilizzando la sua implementazione MediaSession.

Gestire i comandi di streaming multimediale

Per implementare lo streaming multimediale lato server, VIA deve diventare esso stesso una fonte multimediale, implementando MediaBrowse e MediaSession API. Fare riferimento a Creare app multimediali per le automobili . Implementando queste API, un'app di controllo vocale sarebbe in grado di (tra le altre cose):

  • Partecipa senza problemi alla selezione della fonte multimediale
  • Riprende automaticamente dopo il riavvio dell'auto
  • Fornisci controllo della riproduzione e della navigazione utilizzando l'interfaccia utente di Media Center
  • Ricevi eventi dei pulsanti multimediali hardware standard

Non esiste un modo standardizzato di interagire con tutte le app di navigazione. Per le integrazioni con Google Maps, consulta Google Maps per Android Automotive Intents . Per integrazioni con altre app, contatta direttamente gli sviluppatori dell'app. Prima di lanciare un intento su qualsiasi app (incluso Google Maps), verifica che l'intento possa essere risolto (vedi Richieste di intenti ). Ciò crea l'opportunità di informare l'utente nel caso in cui l'app di destinazione non sia disponibile.

Esegui i comandi del veicolo

L'accesso alle proprietà del veicolo sia in lettura che in scrittura viene fornito tramite CarPropertyManager . I tipi di proprietà del veicolo, la sua implementazione e altri dettagli sono spiegati in Configurazioni delle proprietà . Per una descrizione accurata delle proprietà supportate da Android è meglio fare riferimento direttamente a hardware/interfaces/automotive/vehicle/2.0/types.hal . L'enum VehicleProperty qui definita contiene proprietà standard e specifiche del fornitore, tipi di dati, modalità di modifica, unità e definizione di accesso in lettura/scrittura.

Per accedere a queste stesse costanti da Java, puoi utilizzare VehiclePropertyIds e le sue classi complementari. Proprietà diverse hanno autorizzazioni Android diverse che ne controllano l'accesso. Queste autorizzazioni sono dichiarate nel manifest CarService e la mappatura tra proprietà e autorizzazioni descritta nel Javadoc VehiclePropertyIds e applicata in PropertyHalServiceIds .

Leggere la proprietà di un veicolo

Di seguito è riportato un esempio che mostra come leggere la velocità del veicolo:

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);
    }

    ...
}

Imposta una proprietà del veicolo

Di seguito è riportato un esempio che mostra come accendere e spegnere l'aria condizionata anteriore.

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"));
    }

    …
}

Esegui i comandi di comunicazione

Gestire i comandi di messaggistica

I VIA devono gestire i messaggi in arrivo seguendo il flusso "tocca per leggere" descritto nell'assistente vocale Tap-to-Read , che può facoltativamente gestire l'invio di risposte al mittente del messaggio in entrata. Inoltre, i VIA possono utilizzare SmsManager (parte del pacchetto android.telephony ) per comporre e inviare messaggi SMS direttamente dall'auto o tramite Bluetooth.

Gestire i comandi di chiamata

In modo simile, i VIA possono utilizzare TelephonyManager per effettuare telefonate e chiamare il numero di segreteria dell'utente. In questi casi i VIA interagiranno direttamente con lo stack di telefonia o con l'app Car Dialer. In ogni caso, l'app Car Dialer dovrebbe essere quella che mostra all'utente l'interfaccia utente relativa alle chiamate vocali.

Esegui altri comandi

Per un elenco di altri possibili punti di integrazione tra VIA e il sistema, controlla l'elenco degli intenti Android noti. Molti comandi utente possono essere risolti lato server (ad esempio, la lettura delle e-mail degli utenti e degli eventi del calendario) e non richiedono alcuna interazione con il sistema oltre all'interazione vocale stessa.

Azioni immersive (visualizzazione di contenuti visivi)

Laddove migliora le azioni o la comprensione dell'utente, un VIA può fornire contenuti visivi supplementari sullo schermo dell'auto. Per ridurre al minimo la distrazione del conducente, mantieni tali contenuti semplici, brevi e utilizzabili. Per dettagli sulle linee guida UI/UX sulle azioni immersive, consulta Assistenti precaricati: linee guida UX .

Per consentire la personalizzazione e la coerenza con il resto del design dell'unità principale (HU), i VIA dovrebbero utilizzare i componenti della libreria dell'interfaccia utente dell'auto per la maggior parte degli elementi dell'interfaccia utente. Per i dettagli, vedere Personalizzazione .