Per implementare un'applicazione di interazione vocale (VIA), completa questi passaggi:
- Crea uno scheletro VIA.
- (Facoltativo) Implementa un flusso di configurazione/accesso.
- (Facoltativo) Implementa una schermata Impostazioni.
- Dichiara le autorizzazioni richieste nel file manifest.
- Implementa una UI della 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. Consulta questi contenuti in Evasione dei comandi.
Le sezioni seguenti descrivono come completare ogni passaggio sopra indicato.
Crea uno scheletro 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 di intent per l'azioneVoiceInteractionService.SERVICE_INTERFACE ("android.service.voice.VoiceInteractionService"). - Questo servizio deve avere l'autorizzazione per la firma di sistema
BIND_VOICE_INTERACTION. - Questo servizio deve includere un file di metadati
android.voice_interactioncontenente 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 maggiori dettagli su ogni campo, consulta R.styleable#VoiceInteractionService.
Poiché tutte le 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 i seguenti metadati:
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 illustra il ciclo di vita di ciascuna di queste entità:

Figura 1. Cicli di vita
Come indicato in precedenza, VoiceInteractionService è il punto di accesso a una VIA. Le principali responsabilità di questo servizio sono:
- Inizializzare tutti i processi che devono rimanere in esecuzione finché questa VIA è quella attiva. Ad esempio, il rilevamento hotword.
- Segnalare le azioni vocali supportate (vedi Assistente vocale Tap-to-Read (TTR)).
- Avviare le sessioni di interazione vocale dalla schermata di blocco (keyguard).
Nella sua forma più semplice, un'implementazione di VoiceInteractionService sarebbe simile alla seguente:
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
la funzionalità Tap-to-Read dell'Assistente vocale.
Il sistema utilizza un VoiceInteractionSessionService 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, in un VoiceInteractionSession viene eseguita la maggior parte del lavoro. Una singola istanza di sessione può essere riutilizzata per completare più interazioni utente. In AAOS, esiste un helper CarVoiceInteractionSession che aiuta a implementare alcune delle funzionalità uniche di Automotive.
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 ha un ampio set di metodi di callback che vengono
spiegati nelle sezioni seguenti. Per un elenco completo, consulta la documentazione di VoiceInteractionSession.
Implementa un flusso di configurazione/accesso
La configurazione e l'accesso possono avvenire:
- Durante l'onboarding del dispositivo (Configurazione guidata).
- Durante lo scambio del servizio di interazione vocale (Impostazioni).
- Al primo avvio quando l'app viene selezionata.
Per maggiori dettagli sull'esperienza utente consigliata e sulle indicazioni visive, consulta Assistenti precaricati: indicazioni UX.
Configurazione durante lo scambio del servizio vocale
L'utente può sempre selezionare una VIA che non è stata configurata correttamente. Ciò può accadere perché:
- L'utente ha saltato completamente la Configurazione guidata o il passaggio di configurazione dell'interazione vocale.
- L'utente ha selezionato una VIA 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 di notifica.
- Risposta vocale automatica quando l'utente tenta di utilizzarla.
Nota: è fortemente sconsigliato presentare un flusso di configurazione VIA senza una richiesta esplicita dell'utente. Ciò significa che le VIA devono evitare di visualizzare automaticamente i contenuti sull'HU durante l'avvio del dispositivo o in seguito a un cambio o sblocco dell'utente.
Promemoria di notifica
Un promemoria di notifica è un modo non intrusivo per indicare la necessità di configurazione e per fornire agli utenti un'opportunità di navigare nel flusso di configurazione dell'assistente.

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

Figura 3. Flusso del promemoria di notifica
Risposta vocale
Questo è il flusso più semplice da implementare: avvia un'espressione su un callback VoiceInteractionSession#onShow(), spiega all'utente cosa deve fare e poi chiedi (se la configurazione è consentita in base allo stato di limitazione UX) 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 una VIA che non è stata configurata correttamente. In questi casi:
- Informa verbalmente l'utente di questa situazione (ad esempio, "Per funzionare correttamente, devi completare alcuni passaggi…").
- Se il motore di limitazione 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 su cui l'utente può fare clic quando è sicuro.
Crea schermate di configurazione dell'interazione vocale
Le schermate di configurazione e accesso devono essere sviluppate come attività regolari. Consulta le linee guida UX e visive per lo sviluppo della UI in Assistenti precaricati: indicazioni UX.
Linee guida generali:
- Le VIA devono consentire agli utenti di interrompere e riprendere la configurazione in qualsiasi momento.
- La configurazione non deve essere consentita se la limitazione
UX_RESTRICTIONS_NO_SETUPè in vigore. 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 della UI. Per maggiori dettagli, consulta Personalizzazione.
Implementa una schermata Impostazioni

Figura 4. Integrazione delle impostazioni
Le schermate delle impostazioni sono attività Android regolari. Se implementato, il relativo 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 per continuare la configurazione e l'accesso (se l'utente non l'ha completata) o offrire un'opzione di disconnessione o cambio utente se necessario. Analogamente alle schermate di configurazione descritte sopra, queste schermate devono:
- Fornire l'opzione per uscire e tornare alla schermata precedente nello stack di schermate (ad esempio, Impostazioni auto).
- Non essere consentite durante la guida. Per maggiori dettagli, consulta le Linee guida sulla distrazione del conducente.
- Corrispondere al sistema di progettazione di ogni veicolo. Per maggiori dettagli, consulta Personalizzazione.
Dichiara le autorizzazioni richieste nel file manifest
Le autorizzazioni richieste da una VIA possono essere suddivise in tre categorie:
- Autorizzazioni per la 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 maggiori informazioni su come ottenere le autorizzazioni per la firma, consulta 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 VoiceInteractionService predefinito. Tuttavia, poiché questo valore predefinito potrebbe variare 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.
Tenendo conto 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 è quello di utilizzare un'espressione vocale per spiegare la situazione all'utente e una notifica per fornire un'opportunità che l'utente può utilizzare per tornare alle schermate delle impostazioni VIA. Per maggiori dettagli, vedi 1. Promemoria di notifica.
Richiedi le autorizzazioni come parte della schermata delle impostazioni
Le autorizzazioni pericolose vengono richieste utilizzando il metodo regolare ActivityCompat#requestPermission() (o equivalente). Per maggiori dettagli su come richiedere le autorizzazioni, consulta
Richiedere le autorizzazioni per le app.

Figura 5. Richiedi autorizzazioni
Autorizzazione per il listener di notifiche
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 ai listener registrati. Per scoprire se alla VIA è stato concesso l'accesso a queste informazioni, le app possono:
- (Facoltativo) Controllare in anticipo se sono presenti listener di notifiche utilizzando
CarAssistUtils#assistantIsNotificationListener(). Questa operazione può essere eseguita, ad esempio, durante il flusso di configurazione. - (Obbligatorio) Reagire alla gestione del
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 di 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);
}Implementa una UI della finestra di conversazione
Quando un VoiceInteractionSession riceve un callback onShow(), può presentare una UI della finestra di conversazione. Per le linee guida visive e UX sull'implementazione della finestra di conversazione,consulta
Assistenti precaricati: indicazioni UX.

Figura 6. Visualizzazione della finestra di conversazione
Esistono due opzioni per implementare questa UI:
- Esegui l'override di
VoiceInteractionSession#onCreateContentView() - Avvia un'attività utilizzando
VoiceInteractionSession#startAssistantActivity()
Utilizza onCreateContentView()
Questo è il modo predefinito per presentare una finestra di conversazione. 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 deve essere invisibile. 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 UI.
Utilizza startAssistantActivity()
In questo caso, VoiceInteractionSession delega la gestione della UI della finestra di conversazione a un'attività regolare. Quando viene utilizzata questa opzione, un'VoiceInteractionSession
implementazione deve disattivare la creazione della finestra di contenuti predefinita (vedi Utilizzo di onCreateContentView()) nel callback onPrepareShow(). In VoiceInteractionSession#onShow(), la sessione avvia l'attività della finestra di conversazione utilizzando VoiceInteractionSession#startAssistantActivity(). Questo metodo avvia la UI con le impostazioni della finestra e i flag di attività appropriati.
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 di servizi. Ad esempio, quando viene richiamato VoiceInteractionSession#onHide(), la sessione deve essere in grado di passare questa richiesta all'attività.
Importante. In Automotive, solo le attività con annotazioni speciali o quelle elencate nella "lista consentita" UXR possono essere visualizzate durante la guida. Questo vale anche per le attività avviate con VoiceInteractionSession#startAssistantActivity(). Ricorda di
annotare l'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 maggiori informazioni, consulta le Linee guida sulla distrazione del conducente.
Implementa 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, "Ok Google" o "Hey Google".
Rilevamento hotword DSP
Android fornisce l'accesso a un rilevatore di hotword sempre attivo a livello DSP tramite
AlwaysOnHotwordDetector.
modo per implementare il rilevamento hotword con una CPU bassa. L'utilizzo di questa funzionalità è suddiviso in due parti:
- Creazione di un'istanza di
AlwaysOnHotwordDetector. - Registrazione di un modello audio di rilevamento 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 onAvailabilityChanged()
callback con uno dei seguenti valori possibili:
STATE_HARDWARE_UNAVAILABLE. La funzionalità DSP non è disponibile sul dispositivo. In questo caso, viene utilizzato il rilevamento hotword software.STATE_HARDWARE_UNSUPPORTED. Il supporto DSP non è disponibile in generale, ma il DSP non supporta la combinazione di frase chiave e impostazioni internazionali specificata. L'app può scegliere di utilizzare il rilevamento hotword software.STATE_HARDWARE_ENROLLED. Il rilevamento hotword è pronto e può essere avviato chiamando il metodostartRecognition().STATE_HARDWARE_UNENROLLED. Non è disponibile un modello audio per la frase chiave richiesta, ma è possibile la registrazione.
La registrazione dei modelli audio di rilevamento hotword può essere eseguita utilizzando IVoiceInteractionManagerService#updateKeyphraseSoundModel().
Nel sistema possono essere registrati più modelli contemporaneamente, ma a un AlwaysOnHotwordDetector è associato un solo
modello.
Il rilevamento hotword DSP potrebbe non essere disponibile su tutti i dispositivi. Gli sviluppatori VIA
devono verificare le funzionalità hardware utilizzando il metodogetDspModuleProperties(). Per un esempio di codice che mostra
come registrare i modelli audio, consulta VoiceEnrollment/src/com/android/test/voiceenrollment/EnrollmentUtil.java.
Consulta Acquisizione simultanea per il riconoscimento hotword
simultaneo.
Rilevamento hotword software
Come indicato sopra, il rilevamento hotword DSP potrebbe non essere disponibile su 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 di interferire 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.
- L'autorizzazione
android.Manifest.permission.CAPTURE_AUDIO_HOTWORD.
Entrambe queste costanti sono @hide e disponibili solo per le app in bundle.
Gestisci l'input audio e il riconoscimento vocale
L'input audio viene implementato utilizzando la classe MediaRecorder.
Per maggiori informazioni su come utilizzare questa API, consulta la MediaRecorder
Overview. È previsto che i servizi di interazione vocale siano anche RecognitionService
implementazioni della classe. 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, le VIA
devono avere android.permission.RECORD_AUDIO.
È previsto che anche le app che accedono a un'RecognitionService
implementazione abbiano questa autorizzazione.
Prima di Android 10, l'accesso al microfono veniva concesso a una sola app alla volta (ad eccezione del rilevamento hotword, vedi sopra). A partire da Android 10, l'accesso al microfono può essere condiviso. Per maggiori informazioni, consulta Condividere l'input audio.
Accedi all'output audio
Quando la VIA è pronta a fornire risposte verbali, è importante seguire questo insieme di linee guida:
- Quando richiedi lo stato attivo audio o gestisci l'output audio, l'app
deve utilizzare
AudioAttributes#USAGE_ASSISTANTeAudioAttributes#CONTENT_TYPE_SPEECHcome attributi audio. - Durante il riconoscimento vocale, lo stato attivo audio deve essere richiesto con
AudioManage#AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE. Tieni presente che alcune app multimediali potrebbero non reagire correttamente ai comandi multimediali (vedi Evasione dei comandi multimediali) mentre lo stato attivo audio viene rimosso.