Per implementare un'applicazione di interazione vocale (VIA), completa questi passaggi:
- Crea una struttura VIA.
- (Facoltativo) Implementa un flusso di configurazione/accesso.
- (Facoltativo) Implementa una schermata Impostazioni.
- Dichiara le autorizzazioni richieste nel file manifest.
- Implementa un'interfaccia utente per la finestra di conversazione.
- Implementa il riconoscimento vocale (deve includere l'implementazione dell'API RecognitionService).
- Implementa l'espressione (facoltativamente, puoi implementare l'API TextToSpeech).
- Implementa l'evasione dei comandi. Vedi questi contenuti in Esecuzione dei comandi.
Le sezioni seguenti descrivono come completare ogni passaggio menzionato sopra.
Crea una struttura VIA
Manifest
Un'app viene rilevata come app con interazione vocale quando nel manifest è incluso quanto segue:
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.myvoicecontrol"> ... <application ... > <service android:name=".MyInteractionService" android:label="@string/app_name" android:permission="android.permission.BIND_VOICE_INTERACTION" android:process=":interactor"> <meta-data android:name="android.voice_interaction" android:resource="@xml/interaction_service" /> <intent-filter> <action android:name= "android.service.voice.VoiceInteractionService" /> </intent-filter> </service> </application> </manifest>
In questo esempio:
- Le VIA devono esporre un servizio che estende
VoiceInteractionService, con un filtro per intent per l'azioneVoiceInteractionService.SERVICE_INTERFACE ("android.service.voice.VoiceInteractionService"). - Questo servizio deve disporre dell'autorizzazione di firma del sistema
BIND_VOICE_INTERACTION. - Questo servizio deve includere un file di metadati
android.voice_interactionche contenga quanto segue:res/xml/interaction_service.xml
<voice-interaction-service xmlns:android="http://schemas.android.com/apk/res/android" android:sessionService= "com.example.MyInteractionSessionService" android:recognitionService= "com.example.MyRecognitionService" android:settingsActivity= "com.example.MySettingsActivity" android:supportsAssist="true" android:supportsLaunchVoiceAssistFromKeyguard="true" android:supportsLocalInteraction="true" />
Per informazioni dettagliate su ciascun campo, vedi R.styleable#VoiceInteractionService.
Dato che tutti i VIA sono anche servizi di riconoscimento vocale, devi includere anche quanto segue nel manifest:
AndroidManifest.xml
<manifest ...> <uses-permission android:name="android.permission.RECORD_AUDIO"/> <application ...> ... <service android:name=".RecognitionService" ...> <intent-filter> <action android:name="android.speech.RecognitionService" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> <meta-data android:name="android.speech" android:resource="@xml/recognition_service" /> </service> </application> </manifest>
I servizi di riconoscimento vocale richiedono anche il seguente metadato:
res/xml/recognition_service.xml
<recognition-service
xmlns:android="http://schemas.android.com/apk/res/android"
android:settingsActivity="com.example.MyRecognizerSettingsActivity" />VoiceInteractionService, VoiceInteractionSessionService e VoiceInteractionSession
Il seguente diagramma mostra il ciclo di vita di ciascuna di queste entità:

Figura 1. Cicli di vita
Come detto in precedenza, VoiceInteractionService è il punto di ingresso
di un VIA. Le principali responsabilità di questo servizio sono:
- Inizializza tutti i processi che devono essere mantenuti in esecuzione finché questo VIA è quello attivo. Ad esempio, il rilevamento hotword.
- Riporta le azioni vocali supportate (vedi Assistente vocale Tap-to-Read).
- Avviare sessioni di interazione vocale dalla schermata di blocco (keyguard).
Nella sua forma più semplice, un'implementazione di VoiceInteractionService si presenta in questo modo:
public class MyVoiceInteractionService extends VoiceInteractionService { private static final List<String> SUPPORTED_VOICE_ACTIONS = Arrays.asList( CarVoiceInteractionSession.VOICE_ACTION_READ_NOTIFICATION, CarVoiceInteractionSession.VOICE_ACTION_REPLY_NOTIFICATION, CarVoiceInteractionSession.VOICE_ACTION_HANDLE_EXCEPTION ); @Override public void onReady() { super.onReady(); // TODO: Setup hotword detector } @NonNull @Override public Set<String> onGetSupportedVoiceActions( @NonNull Set<String> voiceActions) { Set<String> result = new HashSet<>(voiceActions); result.retainAll(SUPPORTED_VOICE_ACTIONS); return result; } ... }
L'implementazione di VoiceInteractionService#onGetSupportedVoiceActions() è
necessaria per gestire
Tap-to-Read dell'assistente vocale.
Un VoiceInteractionSessionService viene utilizzato dal sistema per creare e interagire con un VoiceInteractionSession. Ha una sola responsabilità:
avviare nuove sessioni quando richiesto.
public class MyVoiceInteractionSessionService extends VoiceInteractionSessionService { @Override public VoiceInteractionSession onNewSession(Bundle args) { return new MyVoiceInteractionSession(this); } }
Infine, la maggior parte del lavoro viene svolta in una VoiceInteractionSession. Una singola istanza di sessione potrebbe essere riutilizzata per completare più
interazioni utente. In AAOS esiste un helper CarVoiceInteractionSession che aiuta a implementare alcune delle funzionalità uniche per il settore automobilistico.
public class MyVoiceInteractionSession extends CarVoiceInteractionSession { public InteractionSession(Context context) { super(context); } @Override protected void onShow(String action, Bundle args, int showFlags) { closeSystemDialogs(); // TODO: Unhide UI and update UI state // TODO: Start processing audio input } ... }
VoiceInteractionSession dispone di un ampio set di metodi di callback che sono
spiegati nelle sezioni seguenti. Per un elenco completo, consulta la documentazione di VoiceInteractionSession.
Implementare un flusso di configurazione/accesso
La configurazione e l'accesso possono avvenire:
- Durante l'onboarding del dispositivo (configurazione guidata).
- Durante lo scambio di servizi di interazione vocale (Impostazioni).
- Al primo avvio, quando l'app è selezionata.
Per informazioni dettagliate sull'esperienza utente consigliata e sulla guida visiva, vedi Assistenti precaricati: guida all'esperienza utente.
Configurazione durante lo scambio del servizio vocale
L'utente può sempre selezionare un'app VIA che non è stata configurata correttamente. Ciò può accadere perché:
- L'utente ha saltato completamente la configurazione guidata oppure il passaggio di configurazione dell'interazione vocale.
- L'utente ha selezionato un'emittente integrata diversa da quella configurata durante l'onboarding del dispositivo.
In ogni caso, un VoiceInteractionService ha diversi modi per incoraggiare l'utente
a completare la configurazione:
- Promemoria della notifica.
- Risposta vocale automatica quando l'utente tenta di utilizzarla.
Nota: è fortemente sconsigliato presentare un flusso di configurazione della VIA senza una richiesta esplicita dell'utente. Ciò significa che gli assistenti vocali intelligenti devono evitare di mostrare automaticamente contenuti sull'HU durante l'avvio del dispositivo o in seguito a un cambio di utente o uno sblocco.
Promemoria di notifica
Un promemoria di notifica è un modo non intrusivo per indicare la necessità di configurazione e per fornire agli utenti un modo per accedere al flusso di configurazione dell'assistente.

Figura 2. Promemoria di notifica
Ecco come funzionerebbe questo flusso:

Figura 3. Flusso di promemoria delle notifiche
Risposta vocale
Questo è il flusso più semplice da implementare, che avvia un'espressione su
un callback VoiceInteractionSession#onShow(), spiega all'utente cosa
deve essere fatto e poi gli chiede (se la configurazione è consentita in base allo stato della limitazione dell'esperienza utente)
se vuole avviare il flusso di configurazione. Se la configurazione non è possibile al momento, spiega anche questa situazione.
Configurazione al primo utilizzo
L'utente può sempre attivare un'VIA che non è stata configurata correttamente. In questi casi:
- Informa verbalmente l'utente di questa situazione (ad esempio, "Per funzionare correttamente, ho bisogno che tu completi alcuni passaggi… ").
- Se il motore di restrizioni UX lo consente (vedi UX_RESTRICTIONS_NO_SETUP), chiedi all'utente se vuole avviare la procedura di configurazione e poi apri la schermata Impostazioni per la VIA.
- In caso contrario (ad esempio, se l'utente sta guidando), lascia una notifica che lo inviti a fare clic sull'opzione quando è sicuro farlo.
Creare schermate di configurazione dell'interazione vocale
Le schermate di configurazione e accesso devono essere sviluppate come normali attività. Consulta le linee guida visive e UX per lo sviluppo dell'interfaccia utente in Assistenti precaricati: indicazioni UX.
Linee guida generali:
- Gli assistenti vocali integrati devono consentire agli utenti di interrompere e riprendere la configurazione in qualsiasi momento.
- La configurazione non deve essere consentita se è in vigore la limitazione
UX_RESTRICTIONS_NO_SETUP. Per maggiori dettagli, consulta le linee guida sulla distrazione del conducente. - Le schermate di configurazione devono corrispondere al sistema di progettazione di ogni veicolo. Il layout generale dello schermo, le icone, i colori e altri aspetti devono essere coerenti con il resto dell'interfaccia utente. Per ulteriori dettagli, consulta la sezione Personalizzazione.
Implementare una schermata delle impostazioni

Figura 4. Integrazione delle impostazioni
Le schermate delle impostazioni sono normali attività Android. Se implementato, il punto di accesso
deve essere dichiarato in res/xml/interaction_service.xml come parte dei manifest VIA (vedi
Manifest).
La sezione Impostazioni è un buon punto di partenza per continuare la configurazione e l'accesso (se l'utente non l'ha completata) o per offrire un'opzione di disconnessione o cambio utente, se necessario. Analogamente alle schermate di configurazione descritte sopra, queste schermate devono:
- Offri la possibilità di uscire e tornare alla schermata precedente nella pila di schermate (ad esempio, alle impostazioni dell'auto).
- Non essere consentito durante la guida. Per maggiori dettagli, consulta le linee guida sulla distrazione del conducente.
- Abbina ciascun sistema di progettazione del veicolo. Per maggiori dettagli, vedi Personalizzazione.
Dichiarare le autorizzazioni richieste nel file manifest
Le autorizzazioni richieste da un VIA possono essere suddivise in tre categorie:
- Autorizzazioni di firma di sistema. Si tratta di autorizzazioni concesse solo agli APK preinstallati e firmati dal sistema. Gli utenti non possono concedere queste autorizzazioni, solo gli OEM possono concederle durante la creazione delle immagini di sistema. Per ulteriori informazioni su come ottenere le autorizzazioni di firma, vedi Concedere autorizzazioni con privilegi di sistema.
- Autorizzazioni pericolose. Si tratta di autorizzazioni che un utente deve concedere utilizzando la finestra di dialogo PermissionsController. Gli OEM possono pre-concedere alcune di queste autorizzazioni al servizio VoiceInteractionService predefinito. Tuttavia, dato che questo valore predefinito potrebbe cambiare da dispositivo a dispositivo, le app devono essere in grado di richiedere queste autorizzazioni quando necessario.
- Altre autorizzazioni. Si tratta di tutte le altre autorizzazioni che non richiedono l'intervento dell'utente. Queste autorizzazioni vengono concesse automaticamente dal sistema.
Alla luce di quanto sopra, la sezione seguente si concentra solo sulla richiesta di autorizzazioni pericolose. Le autorizzazioni devono essere richieste solo quando l'utente si trova nelle schermate di accesso o delle impostazioni.
Se l'app non dispone delle autorizzazioni necessarie per funzionare, il flusso consigliato è utilizzare un comando vocale per spiegare la situazione all'utente e una notifica per fornire un'agevolazione che l'utente può utilizzare per tornare alle schermate delle impostazioni dell'assistente vocale integrato. Per maggiori dettagli, vedi 1. Promemoria della notifica.
Richiedere le autorizzazioni nell'ambito della schermata delle impostazioni
Le autorizzazioni pericolose vengono richieste utilizzando il metodo ActivityCompat#requestPermission() standard (o equivalente). Per informazioni dettagliate su come richiedere le autorizzazioni, vedi
Richiedere le autorizzazioni app.

Figura 5. Richiedi autorizzazioni
Autorizzazione del listener di notifica
Per implementare il flusso TTR, le VIA devono essere designate come listener di notifiche. Non si tratta di un'autorizzazione in sé, ma di una configurazione che consente al sistema di inviare notifiche agli ascoltatori registrati. Per sapere se all'assistente virtuale integrato è stato concesso l'accesso a queste informazioni, le app possono:
- (Facoltativo) Controlla in anticipo se sono presenti listener di notifiche utilizzando
CarAssistUtils#assistantIsNotificationListener(). Ad esempio, questa operazione può essere eseguita durante il flusso di configurazione. - (Obbligatorio) Reagisci alla gestione di
CarVoiceInteractionSession#onShow()con l'azioneVOICE_ACTION_HANDLE_EXCEPTIONe l'eccezioneEXCEPTION_NOTIFICATION_LISTENER_PERMISSIONS_MISSING.
Se questo accesso non è pre-concesso, la VIA deve indirizzare l'utente alla sezione Accesso alle notifiche delle Impostazioni auto, utilizzando una combinazione di espressioni e notifiche. Il seguente codice può essere utilizzato per aprire la sezione appropriata dell'app Impostazioni:
private void requestNotificationListenerAccess() {
Intent intent = new Intent(Settings
.ACTION_NOTIFICATION_LISTENER_SETTINGS);
intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName());
startActivity(intent);
}Implementare un'interfaccia utente della finestra di conversazione
Quando un VoiceInteractionSession riceve un callback onShow(),
può presentare una UI della targa vocale. Per le linee guida visive e UX sull'implementazione della targa vocale,consulta
Assistenti precaricati: indicazioni UX.

Figura 6. Visualizzare la finestra di conversazione
Esistono due opzioni per implementare questa UI:
- Override
VoiceInteractionSession#onCreateContentView() - Avviare un'attività utilizzando
VoiceInteractionSession#startAssistantActivity()
Utilizzare onCreateContentView()
Questo è il modo predefinito di presentare una voce. La classe base VoiceInteractionSession
crea una finestra e ne gestisce il ciclo di vita finché una sessione vocale è attiva. Le app devono eseguire l'override di VoiceInteractionSession#onCreateContentView()
e restituire una visualizzazione collegata a quella finestra non appena viene
creata la sessione. Questa visualizzazione inizialmente non deve essere visibile. Quando inizia un'interazione vocale,
questa visualizzazione deve essere resa visibile su VoiceInteractionSession#onShow()
e poi di nuovo invisibile su VoiceInteractionSession#onHide().
public class MyVoiceInteractionSession extends CarVoiceInteractionSession { private View mVoicePlate; … @Override public View onCreateContentView() { mVoicePlate = inflater.inflate(R.layout.voice_plate, null); … } @Override protected void onShow(String action, Bundle args, int showFlags) { // TODO: Update UI state to "listening" mVoicePlate.setVisibility(View.VISIBLE); } @Override public void onHide() { mVoicePlate.setVisibility(View.GONE); } … }
Quando utilizzi questo metodo, potresti voler modificare VoiceInteractionSession#onComputeInsets()
per tenere conto delle regioni oscurate della tua UI.
Utilizzare startAssistantActivity()
In questo caso, VoiceInteractionSession delega la gestione dell'interfaccia utente della piastra vocale a un'attività normale. Quando viene utilizzata questa opzione, un'implementazione di VoiceInteractionSession
deve disattivare la creazione della finestra dei contenuti predefinita (vedi Utilizzo di onCreateContentView()) nel callback onPrepareShow(). Alle ore VoiceInteractionSession#onShow(), la sessione avvierà l'attività
di riconoscimento vocale utilizzando VoiceInteractionSession#startAssistantActivity(). Questo
metodo avvia l'interfaccia utente con le impostazioni della finestra e i flag di attività corretti.
public class MyVoiceInteractionSession extends CarVoiceInteractionSession { … @Override public void onPrepareShow(Bundle args, int showFlags) { super.onPrepareShow(args, showFlags); setUiEnabled(false); } @Override protected void onShow(String action, Bundle args, int showFlags) { closeSystemDialogs(); Intent intent = new Intent(getContext(), VoicePlateActivity.class); intent.putExtra(VoicePlateActivity.EXTRA_ACTION, action); intent.putExtra(VoicePlateActivity.EXTRA_ARGS, args); startAssistantActivity(intent); } … }
Per mantenere una comunicazione tra questa attività e VoiceInteractionSession, potrebbe essere necessario un insieme di intent interni o un binding del servizio. Ad esempio, quando viene richiamato VoiceInteractionSession#onHide(), la
sessione deve essere in grado di trasmettere questa richiesta all'attività.
Importante: In Automotive, durante la guida possono essere visualizzate solo le attività annotate in modo speciale o quelle elencate nella "lista consentita" della UX. Questo vale anche per le attività avviate con
VoiceInteractionSession#startAssistantActivity(). Ricorda di
annotare la tua attività con <meta-data
android:name="distractionOptimized" android:value="true"/> o di includerla
nella chiave systemActivityWhitelist del file /packages/services/Car/service/res/values/config.xml. Per ulteriori informazioni, consulta le linee guida sulla distrazione del conducente.
Implementare il riconoscimento vocale
In questa sezione imparerai a implementare il riconoscimento vocale tramite il rilevamento e il riconoscimento delle hotword. Una hotword è una parola di attivazione utilizzata per avviare una nuova query o azione tramite comandi vocali. Ad esempio, "Hey Google".
Rilevamento hotword DSP
Android fornisce l'accesso a un rilevatore di hotword sempre attivo a livello di DSP tramite
AlwaysOnHotwordDetector.
modo per implementare il rilevamento hotword con un utilizzo ridotto della CPU. L'utilizzo di questa funzionalità è
diviso in due parti:
- Creazione di un'istanza di
AlwaysOnHotwordDetector. - Registrazione di un modello sonoro di rilevamento di hotword.
L'implementazione di VoiceInteractionService può creare un rilevatore di hotword utilizzando
VoiceInteractionService#createAlwaysOnHotwordDetector(),
passando una frase chiave e le impostazioni internazionali che vuole utilizzare per il rilevamento. Di conseguenza, l'app riceve un callback onAvailabilityChanged() con uno dei seguenti valori possibili:
STATE_HARDWARE_UNAVAILABLE. La funzionalità DSP non è disponibile sul dispositivo. In questo caso, viene utilizzato il rilevamento di hotword software.STATE_HARDWARE_UNSUPPORTED. Il supporto DSP non è disponibile in generale, ma DSP non supporta la combinazione di frase chiave e impostazioni internazionali specificata. L'app può scegliere di utilizzare il rilevamento di hotword software.STATE_HARDWARE_ENROLLED. Il rilevamento hotword è pronto e può essere avviato chiamando il metodostartRecognition().STATE_HARDWARE_UNENROLLED. Non è disponibile un modello sonoro per la frase chiave richiesta, ma è possibile la registrazione.
La registrazione dei modelli sonori di rilevamento di hotword può essere eseguita utilizzando IVoiceInteractionManagerService#updateKeyphraseSoundModel().
Nel sistema possono essere registrati più modelli contemporaneamente, ma solo uno
è associato a un AlwaysOnHotwordDetector.
Il rilevamento della hotword DSP potrebbe non essere disponibile su tutti i dispositivi. Gli sviluppatori VIA
devono verificare le funzionalità hardware utilizzando il metodo getDspModuleProperties(). Per un esempio di codice che mostra
come registrare i modelli audio, vedi VoiceEnrollment/src/com/android/test/voiceenrollment/EnrollmentUtil.java.
Consulta la sezione Acquisizione simultanea relativa al
riconoscimento simultaneo della hotword.
Rilevamento hotword software
Come indicato sopra, il rilevamento della hotword DSP potrebbe non essere disponibile in tutti i dispositivi (ad esempio, l'emulatore Android non fornisce l'emulazione DSP). In questo caso, il riconoscimento vocale software è l'unica alternativa. Per evitare interferenze con altre app che potrebbero aver bisogno di accedere al microfono, le VIA devono accedere all'input audio utilizzando:
- L'acquisizione audio deve utilizzare MediaRecorder.AudioSource.HOTWORD.
- Autorizzazione
android.Manifest.permission.CAPTURE_AUDIO_HOTWORD.
Entrambe queste costanti sono @hide e disponibili solo per le app in bundle.
Gestire l'input audio e il riconoscimento vocale
L'input audio verrà implementato utilizzando la classe MediaRecorder.
Per saperne di più su come utilizzare questa API, consulta la panoramica di
MediaRecorder. È inoltre previsto che i servizi di interazione vocale siano implementazioni di classi RecognitionService. Qualsiasi app nel sistema che richiede il riconoscimento vocale utilizza
per accedere a questa funzionalità. Per eseguire il riconoscimento vocale e avere accesso al microfono, gli IVR
devono contenere android.permission.RECORD_AUDIO.
Le app che accedono a un'implementazione di RecognitionService
devono disporre anche di questa autorizzazione.
Prima di Android 10, l'accesso al microfono veniva concesso a una sola app alla volta (ad eccezione del rilevamento dell'hotword, vedi sopra). A partire da Android 10, l'accesso al microfono può essere condiviso. Per saperne di più, consulta Condivisione dell'input audio.
Accedere all'uscita audio
Quando l'IVA è pronta a fornire risposte verbali, è importante seguire questo insieme di linee guida:
- Quando richiede la messa a fuoco dell'audio o gestisce l'output audio, l'app
deve utilizzare
AudioAttributes#USAGE_ASSISTANTeAudioAttributes#CONTENT_TYPE_SPEECHcome attributi audio. - Durante il riconoscimento vocale, la messa a fuoco dell'audio deve essere richiesta con
AudioManage#AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE. Tieni presente che alcune app multimediali potrebbero non reagire correttamente ai comandi multimediali (vedi Esecuzione dei comandi multimediali) mentre viene rimosso il focus audio.