Sviluppo di app

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

  1. Crea uno scheletro 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 della finestra di conversazione.
  6. Implementare 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. 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'azione VoiceInteractionService.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_interactionfile 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à:

Cicli di vita

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.

Promemoria di notifica

Figura 2. Promemoria di notifica

Ecco come funziona questo flusso:

Flusso di promemoria delle notifiche

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:

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

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

Richiedi autorizzazioni

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:

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.

Visualizzazione della finestra di conversazione

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

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: