Sviluppo di app

Per implementare un'applicazione di interazione vocale (VIA), completa questi passaggi:

  1. Crea una struttura VIA.
  2. (Facoltativo) Implementa un flusso di configurazione/accesso.
  3. (Facoltativo) Implementa una schermata Impostazioni.
  4. Dichiara le autorizzazioni richieste nel file manifest.
  5. Implementa un'interfaccia utente per la finestra di conversazione.
  6. Implementa il riconoscimento vocale (deve includere l'implementazione dell'API RecognitionService).
  7. Implementa l'espressione (facoltativamente, puoi implementare l'API TextToSpeech).
  8. 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'azione VoiceInteractionService.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_interaction 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. 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à:

Cicli di vita

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.

Promemoria di notifica

Figura 2. Promemoria di notifica

Ecco come funzionerebbe questo flusso:

Flusso di promemoria delle notifiche

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:

  1. Informa verbalmente l'utente di questa situazione (ad esempio, "Per funzionare correttamente, ho bisogno che tu completi alcuni passaggi… ").
  2. 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.
  3. 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

Integrazione 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.

Richiedi autorizzazioni

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:

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.

Visualizzare la finestra di conversazione

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 metodo startRecognition().
  • 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:

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: