Per implementare un'applicazione di interazione vocale (VIA), segui 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 un'interfaccia utente della finestra di conversazione.
- Implementare 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 Eseguire i comandi.
Le sezioni seguenti descrivono come completare ogni passaggio sopra indicato.
Creare uno scheletro VIA
Manifest
Un'app viene rilevata come con interazione vocale quando nel file 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 espanda
VoiceInteractionService
, con un filtro per intent per l'azioneVoiceInteractionService.SERVICE_INTERFACE ("android.service.voice.VoiceInteractionService")
. - Questo servizio deve disporre dell'autorizzazione di firma di sistema
BIND_VOICE_INTERACTION
. - Questo servizio deve includere un
android.voice_interaction
file di metadati che 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
.
Poiché tutti i VIA sono anche servizi di riconoscimento vocale, devi anche includere 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 mostra il ciclo di vita di ciascuna di queste entità:
Figura 1. Cicli di vita
Come affermato in precedenza, VoiceInteractionService
è il punto di accesso
a un VIA. Le responsabilità principali di questo servizio sono:
- Inizializza tutti i processi che devono essere mantenuti in esecuzione finché questo VIA è attivo. Ad esempio, il rilevamento di hotword.
- Segnala le azioni vocali supportate (vedi Tocca per leggere con l'assistente vocale).
- Avvia le sessioni di interazione vocale dalla schermata di blocco (guardia tasti).
Nella sua forma più semplice, un'implementazione di VoiceInteractionService è 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()
è obbligatoria per gestire la funzionalità Tocca per leggere dell'assistente vocale.
Il sistema utilizza un VoiceInteractionSessionService per creare e interagire con una VoiceInteractionSession. Ha un'unica responsabilità: avviare nuove sessioni quando richiesto.
public class MyVoiceInteractionSessionService extends VoiceInteractionSessionService { @Override public VoiceInteractionSession onNewSession(Bundle args) { return new MyVoiceInteractionSession(this); } }
Infine, una VoiceInteractionSession è dove viene svolta la maggior parte del lavoro. Una singola istanza di sessione potrebbe essere riutilizzata per completare più interazioni con l'utente. In AAOS esiste un helper CarVoiceInteractionSession
che aiuta a implementare alcune delle funzionalità uniche per i veicoli.
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 insieme di metodi di callback che sono illustrati 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 sulle indicazioni visive, consulta Assistenti preinstallati: indicazioni sull'esperienza utente.
Configurazione durante lo scambio del servizio vocale
È sempre possibile che l'utente selezioni un VIA che non è stato configurato 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 un VIA diverso da quello configurato 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: è vivamente sconsigliato presentare un flusso di configurazione VIA senza una richiesta esplicita dell'utente. Ciò significa che le app VIA devono evitare di mostrare automaticamente contenuti sull'HU durante l'avvio del dispositivo o a seguito di un cambio utente o sblocco.
Promemoria di notifica
Un promemoria di notifica è un modo non invadente per indicare la necessità di configurazione e per fornire agli utenti un'opzione per accedere al flusso di configurazione dell'assistente.
Figura 2. Promemoria di notifica
Ecco come funziona questo flusso:
Figura 3. Flusso di promemoria delle notifiche
Risposta vocale
Si tratta del flusso più semplice da implementare: viene avviato un comando su un callback VoiceInteractionSession#onShow()
, viene spiegato all'utente cosa deve fare e poi gli viene chiesto (se la configurazione è consentita in base allo stato della limitazione UX) se vuole avviare il flusso di configurazione. Se al momento non è possibile effettuare la configurazione, spiega anche questa situazione.
Configurazione al primo utilizzo
È sempre possibile che l'utente attivi un VIA che non è stato configurato 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 delle limitazioni UX lo consente (vedi UX_RESTRICTIONS_NO_SETUP), chiedi all'utente se vuole avviare la procedura di configurazione, quindi apri la schermata Impostazioni per il VIA.
- In caso contrario (ad esempio se l'utente è alla guida), lascia una notifica che lo inviti a fare clic sull'opzione quando è possibile.
Creare schermate di configurazione dell'interazione vocale
Le schermate di configurazione e di accesso devono essere sviluppate come normali attività. Consulta le linee guida UX e visive per lo sviluppo dell'interfaccia utente in Assistenti preinstallati: indicazioni sull'esperienza utente.
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 è in vigore la limitazione
UX_RESTRICTIONS_NO_SETUP
. Per maggiori dettagli, consulta le linee guida sulla distrazione alla guida. - Le schermate di configurazione devono corrispondere al sistema di design di ciascun veicolo. Il layout, le icone, i colori e altri aspetti della schermata generale devono essere coerenti con il resto dell'interfaccia utente. Per maggiori dettagli, consulta la sezione Personalizzazione.
Implementare una schermata delle impostazioni
Figura 4. Integrazione delle impostazioni
Le schermate delle impostazioni sono attività Android normali. Se implementati, il punto di contatto deve essere dichiarato in res/xml/interaction_service.xml
nell'ambito dei manifest VIA (vedi Manifest).
La sezione Impostazioni è un buon punto di partenza per continuare la configurazione e accedere (se l'utente non l'ha completata) o, se necessario, offrire un'opzione di disconnessione o cambio utente. Come per le schermate di configurazione descritte sopra, queste schermate dovrebbero:
- Fornisci l'opzione per tornare alla schermata precedente nell'elenco delle schermate (ad esempio, alle Impostazioni auto).
- Non essere consentito durante la guida. Per maggiori dettagli, consulta le linee guida sulla distrazione alla guida.
- Abbina ciascun sistema di progettazione del veicolo. Per maggiori dettagli, consulta la sezione Personalizzazione.
Dichiara 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 sono in grado di concedere queste autorizzazioni, solo gli OEM possono farlo 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 delle autorizzazioni che un utente deve concedere utilizzando la finestra di dialogo PermissionsController. Gli OEM possono concedere in anticipo alcune di queste autorizzazioni a VoiceInteractionService predefinito. Tuttavia, poiché questo valore predefinito potrebbe variare da dispositivo a dispositivo, le app dovrebbero essere in grado di richiedere queste autorizzazioni in caso di necessità.
- Altre autorizzazioni. Si tratta di tutte le altre autorizzazioni che non richiedono l'intervento dell'utente. Queste autorizzazioni vengono concesse automaticamente dal sistema.
In base a quanto sopra, la sezione seguente si concentra solo sulla richiesta di autorizzazioni pericolose. Le autorizzazioni devono essere richieste solo quando l'utente è nelle schermate di accesso o di impostazione.
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'affordance che l'utente può utilizzare per tornare alle schermate delle impostazioni di VIA. Per maggiori dettagli, vedi 1. Promemoria di notifica.
Richiedere le autorizzazioni nella schermata delle impostazioni
Le autorizzazioni pericolose vengono richieste utilizzando il metodo ActivityCompat#requestPermission()
normale (o equivalente). Per informazioni dettagliate su come richiedere le autorizzazioni, consulta
Richiedere le autorizzazioni app.
Figura 5. Richiedi autorizzazioni
Autorizzazione per l'ascoltatore di notifiche
Per implementare il flusso TTR, le VIA devono essere designate come ascoltatori 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 al VIA è stato concesso l'accesso a queste informazioni, le app possono:
- (Facoltativo) Controlla in anticipo se sono presenti ascoltatori di notifiche utilizzando
CarAssistUtils#assistantIsNotificationListener()
. Ad esempio, questo può essere fatto durante il flusso di configurazione. - (Obbligatorio) Reagisci alla gestione di
CarVoiceInteractionSession#onShow()
con l'azioneVOICE_ACTION_HANDLE_EXCEPTION
e l'eccezioneEXCEPTION_NOTIFICATION_LISTENER_PERMISSIONS_MISSING
.
Se questo accesso non è pre-accordato, il VIA deve indirizzare l'utente alla sezione Accesso alle notifiche delle Impostazioni dell'auto, utilizzando una combinazione di frasi 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 una chiamata onShow()
,
puoi presentare un'interfaccia utente della scheda vocale. Per le linee guida visive e sull'esperienza utente per l'implementazione della scheda vocale,consulta
Assistenti preinstallati: indicazioni sull'esperienza utente.
Figura 6. Visualizzazione della finestra di conversazione
Esistono due opzioni per implementare questa UI:
- Sostituisci
VoiceInteractionSession#onCreateContentView()
- Avviare un'attività utilizzando
VoiceInteractionSession#startAssistantActivity()
Utilizzare onCreateContentView()
Questo è il modo predefinito per presentare una scheda vocale. La classe di base VoiceInteractionSession
crea una finestra e ne gestisce il ciclo di vita per tutto il tempo in cui è attiva una sessione di chat vocale. Le app devono sostituire VoiceInteractionSession#onCreateContentView()
e restituire una visualizzazione collegata a quella finestra non appena viene creata la sessione. Questa visualizzazione dovrebbe essere inizialmente invisibile. Quando inizia un'interazione vocale, questa visualizzazione deve essere 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, ti consigliamo di modificare VoiceInteractionSession#onComputeInsets()
per tenere conto delle regioni oscurate dell'interfaccia utente.
Utilizzare startAssistantActivity()
In questo caso, VoiceInteractionSession
delega la gestione dell'interfaccia utente della tastiera vocale a un'attività normale. Quando viene utilizzata questa opzione, un'implementazione di VoiceInteractionSession
deve disattivare la creazione della finestra dei contenuti predefinita (vedi Utilizzare onCreateContentView()) nel callback onPrepareShow()
. Alle ore VoiceInteractionSession#onShow()
, la sessione avvia l'attività della scheda vocale utilizzando VoiceInteractionSession#startAssistantActivity()
. Questo metodo avvia l'interfaccia utente con le impostazioni della finestra e gli indicatori 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à eVoiceInteractionSession
, potrebbe essere necessaria una serie di Intent o associazioni di servizi interni. Ad esempio, quando viene invocato VoiceInteractionSession#onHide()
, la sessione deve essere in grado di trasmettere questa richiesta all'attività.
Importante. In ambito auto e motori, mentre guidi possono essere visualizzate solo le attività con annotazioni speciali o quelle elencate nella "lista consentita" per l'esperienza utente. 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 hotword utilizzata per avviare una nuova query o azione tramite comandi vocali. Ad esempio, "Hey Google".
Rilevamento hotword del DSP
Android fornisce l'accesso a un rilevatore di hotword sempre attivo a livello di DSP tramite AlwaysOnHotwordDetector
.
per implementare il rilevamento di hotword con una CPU ridotta. L'utilizzo di questa funzionalità è suddiviso in due parti:
- Creazione di un'istanza di
AlwaysOnHotwordDetector
. - Registrazione di un modello audio per il rilevamento di hotword.
L'implementazione di VoiceInteractionService può creare un rilevatore di hotword utilizzando
VoiceInteractionService#createAlwaysOnHotwordDetector()
,
passando una frase chiave e le impostazioni internazionali da 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
. L'assistenza DSP non è disponibile in generale, ma il DSP non supporta una determinata combinazione di frase chiave e impostazioni internazionali. L'app può scegliere di utilizzare il rilevamento di hotword software.STATE_HARDWARE_ENROLLED
. Il rilevamento di hotword è pronto e può essere avviato chiamando il metodostartRecognition()
.STATE_HARDWARE_UNENROLLED
. Non è disponibile un modello audio per la frase chiave richiesta, ma la registrazione è possibile.
La registrazione dei modelli audio per il rilevamento di hotword può essere eseguita utilizzando IVoiceInteractionManagerService#updateKeyphraseSoundModel()
.
È possibile registrare più modelli nel sistema in un determinato momento, ma solo un
modello è associato a un AlwaysOnHotwordDetector
.
Il rilevamento della hotword DSP potrebbe non essere disponibile su tutti i dispositivi. Gli sviluppatori VIA devono controllare le funzionalità hardware utilizzando il metodo getDspModuleProperties()
. Per un codice di esempio che mostra come registrare i modelli audio, consulta VoiceEnrollment/src/com/android/test/voiceenrollment/EnrollmentUtil.java
.
Consulta la sezione Acquisizione simultanea per informazioni sul riconoscimento simultaneo della hotword.
Rilevamento hotword del software
Come indicato sopra, il rilevamento delle 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 tramite software è l'unica alternativa. Per evitare interferenze con altre app che potrebbero richiedere l'accesso al microfono, le VIA devono accedere all'input audio utilizzando:
- L'acquisizione audio deve utilizzare MediaRecorder.AudioSource.HOTWORD.
- Disporre dell'autorizzazione
android.Manifest.permission.CAPTURE_AUDIO_HOTWORD
.
Entrambe queste costanti sono @hide
e sono 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 ulteriori informazioni 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 del sistema che richiede il riconoscimento vocale utilizza questa autorizzazione per accedere a questa funzionalità. Per eseguire il riconoscimento vocale e avere accesso al microfono, le autorizzazioni di accesso ai dati di terze parti devono essere impostate su 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 di hotword, vedi sopra). A partire da Android 10, l'accesso al microfono può essere condiviso. Per ulteriori informazioni, consulta la sezione Condividere l'input audio.
Accedere all'uscita audio
Quando il VIA è pronto a fornire risposte verbali, è importante seguire questa serie di linee guida:
- Quando richiede l'attenzione audio o gestisce l'output audio, l'app deve utilizzare
AudioAttributes#USAGE_ASSISTANT
eAudioAttributes#CONTENT_TYPE_SPEECH
come attributi audio. - Durante il riconoscimento vocale, l'attenzione audio deve essere richiesta con
AudioManage#AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE
. Tieni presente che alcune app multimediali potrebbero non reagire correttamente ai comandi multimediali (consulta Eseguire i comandi multimediali) quando l'audio viene rimosso.