Questa pagina descrive come eseguire i comandi con l'interazione vocale.
Eseguire i comandi multimediali
I comandi relativi ai contenuti multimediali possono essere suddivisi in tre gruppi diversi:
- Origini multimediali esterne (ad esempio Spotify installato in AAOS).
- Origini multimediali di backend (ad esempio la musica riprodotta in streaming tramite la VIA).
- Origini di media locali (ad esempio la radio dell'auto).
Gestire i comandi delle origini multimediali esterne
Le origini multimediali esterne sono definite come app per Android che supportano le API MediaSessionCompat
e MediaBrowseCompat
(consulta la sezione Creare app multimediali per auto per una spiegazione dettagliata sull'utilizzo di queste API).
Importante:affinché un'app di assistenza si connetta al MediaBrowseService
di tutte le app multimediali installate nel sistema, deve:
- Essere installato come firmato dal sistema (consulta le linee guida per lo sviluppo di applicazioni multimediali per AAOS e il codice di esempio
PackageValidator
). - Disporre dell'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 sorgente multimediale attualmente selezionata. Viene anche utilizzato per riprendere una sorgente multimediale riprodotta in precedenza dopo lo spegnimento e il riavvio dell'auto.car-media-common
fornisce metodi pratici per elencare, connettere e interagire con le app multimediali.
Di seguito sono riportate linee guida specifiche per l'implementazione dei comandi di interazione vocale comuni.
Visualizzare un elenco delle origini multimediali installate
Le origini multimediali possono essere rilevate utilizzando PackageManager
e filtrando i servizi corrispondenti a MediaBrowserService.SERVICE_INTERFACE
.
In alcune auto potrebbero essere presenti implementazioni speciali di servizi di browser multimediali,
che devono 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 origini multimediali potrebbero essere installate o disinstallate in qualsiasi momento. Per mantenere un elenco preciso, ti consigliamo di implementare un'istanza BroadcastReceiver
per le azioni di intent ACTION_PACKAGE_ADDED
,
ACTION_PACKAGE_CHANGED
,
ACTION_PACKAGE_REPLACED
e ACTION_PACKAGE_REMOVED
.
Connettiti all'origine multimediale in riproduzione
CarMediaService
fornisce metodi per ottenere la fonte multimediale attualmente selezionata e quando questa fonte media cambia. Queste modifiche 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 pratici per connettersi a una determinata fonte media. Ecco uno snippet semplificato su come connettersi all'app media selezionata al momento:
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 } … }
Controllare la riproduzione dell'origine multimediale in riproduzione
Con un MediaBrowserCompat
collegato, è 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 delle sorgenti multimediali locali (radio, lettore CD, Bluetooth, USB)
Le origini multimediali locali espongono le loro funzionalità al sistema utilizzando le stesse API MediaSession e MediaBrowse descritte sopra. Per adattarsi alle particolarità di ogni 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 per intent ACTION_PLAY_BROADCASTRADIO
. Devono rispettare la struttura dei controlli di riproduzione e della navigazione tra i contenuti multimediali descritta in Implementare la radio. AAOS offre la libreria
car-broadcastradio-support
contenente costanti e metodi per aiutare gli OEM a creare implementazioni di MediaBrowseService per i propri servizi radio che rispettano il protocollo definito e fornisce supporto per le app che utilizzano la struttura ad albero di navigazione (ad esempio le VIA).
Gestire l'ingresso ausiliario, l'audio CD e i contenuti multimediali USB
Non esiste un'implementazione predefinita di queste origini multimediali nell'ambito di AOSP. L'approccio suggerito è:
- Chiedi agli OEM di implementare i servizi multimediali per ciascuno di questi dispositivi. Per maggiori dettagli, vedi Creare app multimediali per le auto.
- Queste implementazioni di MediaBrowseService verranno identificate e a cui verrà data una risposta nelle azioni di intente definite in Intenti di riproduzione generale.
- Questi servizi mostreranno una struttura di navigazione seguendo le linee guida descritte in Altri tipi di origini.
Gestire il Bluetooth
I contenuti multimediali Bluetooth sono esposti tramite il profilo Bluetooth AVRCP. Per facilitare l'accesso a questa funzionalità, AAOS include un'implementazione di MediaBrowserService e MediaSession che estrae i dettagli di comunicazione (vedi packages/apps/Bluetooth).
La rispettiva struttura ad albero del browser multimediale è definita nella classe BrowseTree. I comandi di controllo della riproduzione possono essere inviati in modo simile a qualsiasi altra app, utilizzando l'implementazione di MediaSession.
Gestire i comandi relativi ai contenuti multimediali in streaming
Per implementare lo streaming multimediale lato server, il VIA deve diventare esso stesso una sorgente multimediale, implementando le API MediaBrowse e MediaSession. Fai riferimento a Creare app multimediali per le auto. Implementando queste API, un'app di controllo vocale potrebbe, tra le altre cose:
- Partecipare senza problemi alla selezione delle sorgenti multimediali
- Riprendere automaticamente dopo il riavvio dell'auto
- Fornire il controllo della riproduzione e della navigazione utilizzando l'interfaccia utente di Media Center
- Ricevere eventi dei pulsanti multimediali hardware standard
Eseguire i comandi di navigazione
Non esiste un modo standardizzato per interagire con tutte le app di navigazione. Per le integrazioni con Google Maps, consulta Intent di Google Maps per Android Automotive. Per le integrazioni con altre app, contatta direttamente gli sviluppatori delle app. Prima di lanciare un intento per qualsiasi app (incluso Google Maps), verifica che l'intento possa essere risolto (vedi Richieste di intent). In questo modo, hai la possibilità di informare l'utente nel caso in cui l'app di destinazione non sia disponibile.
Eseguire i comandi del veicolo
L'accesso alle proprietà del veicolo sia in lettura che in scrittura viene fornito tramite
CarPropertyManager.
I tipi di proprietà dei veicoli, la relativa implementazione e altri dettagli sono descritti
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
definito contiene proprietà standard e specifiche del fornitore, tipi di dati, modalità di modifica, unità e definizione dell'accesso in lettura/scrittura.
Per accedere alle stesse costanti da Java, puoi utilizzare VehiclePropertyIds e le relative classi complementari. Proprietà diverse hanno autorizzazioni Android diverse che ne controllano l'accesso. Queste autorizzazioni sono dichiarate nel manifest di CarService e la mappatura tra proprietà e autorizzazioni descritta nel Javadoc di VehiclePropertyIds e applicata in PropertyHalServiceIds.
Leggere una proprietà del 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); } ... }
Impostare 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")); } … }
Eseguire i comandi di comunicazione
Gestire i comandi di messaggistica
I VIA devono gestire i messaggi in arrivo seguendo il flusso "tocca per leggere" descritto in Tocca per leggere con l'assistente vocale, che può eventualmente gestire l'invio di risposte al mittente del messaggio in arrivo.
Inoltre, le 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, le VIA possono utilizzare TelephonyManager
per effettuare chiamate e chiamare il numero di voicemail dell'utente. In questi casi,
le VIA interagiranno direttamente con lo stack di telefonia o con l'app Telefono auto. In ogni caso, dovrebbe essere l'app Telefono auto a mostrare all'utente l'interfaccia utente relativa alle chiamate vocali.
Eseguire altri comandi
Per un elenco di altri possibili punti di integrazione tra il VIA e il sistema, controlla l'elenco degli intent Android ben noti. Molti comandi degli utenti possono essere risolti lato server (ad esempio, la lettura delle email e degli eventi nel calendario degli utenti) e non richiedono interazioni con il sistema diverse dall'interazione vocale stessa.
Azioni immersive (visualizzazione di contenuti visivi)
Se migliora le azioni o la comprensione dell'utente, un VIA può fornire contenuti visivi supplementari sullo schermo dell'auto. Per ridurre al minimo le distrazioni del conducente, mantieni questi contenuti semplici, brevi e utili. Per maggiori dettagli sulle linee guida UI/UX per le azioni immersive, consulta la sezione Assistenti preinstallati: indicazioni sull'esperienza utente.
Per consentire la personalizzazione e la coerenza con il resto del design dell'unità principale (HU), le app VIA devono utilizzare i componenti della libreria UI Car per la maggior parte degli elementi dell'interfaccia utente. Per maggiori dettagli, consulta la sezione Personalizzazione.