Développement d'application

Pour implémenter une application d'interaction vocale (VIA), procédez comme suit :

  1. Créez un squelette VIA.
  2. (Facultatif) Implémentez un parcours de configuration/connexion.
  3. (Facultatif) Implémentez un écran de paramètres.
  4. Déclarez les autorisations requises dans le fichier manifeste.
  5. Implémentez une UI d'élément vocal.
  6. Implémentez la reconnaissance vocale (doit inclure l'implémentation de l'API RecognitionService).
  7. Implémentez une expression (vous pouvez éventuellement implémenter l'API Text-to-Speech).
  8. Implémentez le traitement des commandes. Consultez Exécuter des commandes pour en savoir plus.

Les sections suivantes décrivent comment effectuer chacune des étapes mentionnées ci-dessus.

Créer un squelette VIA

Fichiers manifestes

Une application est détectée comme ayant une interaction vocale lorsque les éléments suivants sont inclus dans le fichier manifeste :

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>

Dans cet exemple :

  • Les VAI doivent exposer un service qui étend VoiceInteractionService, avec un filtre d'intent pour l'action VoiceInteractionService.SERVICE_INTERFACE ("android.service.voice.VoiceInteractionService").
  • Ce service doit disposer de l'autorisation de signature système BIND_VOICE_INTERACTION.
  • Ce service doit inclure un fichier de métadonnées android.voice_interaction contenant les éléments suivants :

    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" />

Pour en savoir plus sur chaque champ, consultez R.styleable#VoiceInteractionService. Étant donné que toutes les VIA sont également des services de reconnaissance vocale, vous devez également inclure les éléments suivants dans votre fichier manifeste :

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>

Les services de reconnaissance vocale nécessitent également les métadonnées suivantes :

res/xml/recognition_service.xml

<recognition-service
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:settingsActivity="com.example.MyRecognizerSettingsActivity" />

VoiceInteractionService, VoiceInteractionSessionService et VoiceInteractionSession

Le diagramme suivant illustre le cycle de vie de chacune de ces entités :

Cycles de vie

Figure 1 : Cycles de vie

Comme indiqué précédemment, VoiceInteractionService est le point d'entrée d'un VIA. Les principales responsabilités de ce service sont les suivantes :

  • Initialisez tous les processus qui doivent rester en cours d'exécution tant que cette VIA est active. Par exemple, la détection de mots clés.
  • Signale les commandes vocales compatibles (voir Appuyer pour lire avec l'Assistant vocal).
  • Lancer des sessions d'interaction vocale depuis l'écran de verrouillage (keyguard).

Dans sa forme la plus simple, une implémentation de VoiceInteractionService se présente comme suit :

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'implémentation de VoiceInteractionService#onGetSupportedVoiceActions() est requise pour gérer la fonctionnalité Appuyer pour lire de l'Assistant vocal. Un VoiceInteractionSessionService est utilisé par le système pour créer et interagir avec un VoiceInteractionSession. Il n'a qu'une seule responsabilité : démarrer de nouvelles sessions sur demande.

public class MyVoiceInteractionSessionService extends VoiceInteractionSessionService {
    @Override
    public VoiceInteractionSession onNewSession(Bundle args) {
        return new MyVoiceInteractionSession(this);
    }
}

Enfin, la plupart du travail est effectué dans une VoiceInteractionSession. Une même instance de session peut être réutilisée pour effectuer plusieurs interactions utilisateur. Dans AAOS, un CarVoiceInteractionSession d'assistance existe et permet d'implémenter certaines fonctionnalités automobiles uniques.

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 dispose d'un grand nombre de méthodes de rappel qui sont expliquées dans les sections suivantes. Consultez la documentation de VoiceInteractionSession pour obtenir la liste complète.

Implémenter un flux de configuration/de connexion

La configuration et la connexion peuvent avoir lieu :

  • Lors de l'intégration de l'appareil (assistant de configuration).
  • Lors du remplacement du service d'interaction vocale (paramètres).
  • Au premier lancement de l'application lorsqu'elle est sélectionnée.

Pour en savoir plus sur l'expérience utilisateur recommandée et les conseils visuels, consultez Assistants préchargés : conseils sur l'expérience utilisateur.

Configuration lors du remplacement du service vocal

L'utilisateur peut toujours sélectionner une VIA qui n'a pas été correctement configurée. Cela peut être dû aux raisons suivantes :

  • L'utilisateur a ignoré l'assistant de configuration ou l'étape de configuration de l'interaction vocale.
  • L'utilisateur a sélectionné une VIA différente de celle configurée lors de l'intégration de l'appareil.

Dans tous les cas, un VoiceInteractionService peut encourager l'utilisateur à terminer la configuration de plusieurs façons :

  • Rappel de notification.
  • Réponse vocale automatique lorsque l'utilisateur essaie de l'utiliser.

Remarque : Nous vous déconseillons vivement de présenter un flux de configuration VIA sans demande explicite de l'utilisateur. Cela signifie que les VAI doivent éviter d'afficher automatiquement du contenu sur l'unité principale lors du démarrage de l'appareil ou à la suite d'un changement d'utilisateur ou d'un déverrouillage.

Rappel de notification

Un rappel de notification est un moyen non intrusif d'indiquer qu'une configuration est nécessaire et de fournir aux utilisateurs un moyen d'accéder au flux de configuration de l'assistant.

Rappel de notification

Figure 2. Rappel de notification

Voici comment ce flux fonctionnerait :

Flux de rappel de notification

Figure 3. Flux de rappel de notification

Réponse vocale

Il s'agit du flux le plus simple à implémenter. Il consiste à lancer une expression sur un rappel VoiceInteractionSession#onShow(), à expliquer à l'utilisateur ce qu'il doit faire, puis à lui demander (si la configuration est autorisée en fonction de l'état de restriction de l'UX) s'il souhaite lancer le flux de configuration. Si la configuration n'est pas possible pour le moment, expliquez également cette situation.

Configuration lors de la première utilisation

Il est toujours possible que l'utilisateur déclenche une VIA qui n'a pas été correctement configurée. Dans ce cas :

  1. Informez-en l'utilisateur de vive voix (par exemple, "Pour fonctionner correctement, vous devez suivre quelques étapes…").
  2. Si le moteur de restrictions UX le permet (voir UX_RESTRICTIONS_NO_SETUP), demandez à l'utilisateur s'il souhaite démarrer le processus de configuration, puis ouvrez l'écran des paramètres pour le VIA.
  3. Sinon (par exemple, si l'utilisateur est au volant), laissez une notification pour que l'utilisateur clique sur l'option lorsqu'il pourra le faire en toute sécurité.

Créer des écrans de configuration de l'interaction vocale

Les écrans de configuration et de connexion doivent être développés en tant qu'activités régulières. Consultez les consignes visuelles et d'expérience utilisateur pour le développement de l'UI dans Assistants préchargés : conseils sur l'expérience utilisateur.

Consignes générales :

  • Les VAI doivent permettre aux utilisateurs d'interrompre et de reprendre la configuration à tout moment.
  • La configuration ne doit pas être autorisée si la restriction UX_RESTRICTIONS_NO_SETUP est en vigueur. Pour en savoir plus, consultez les Consignes concernant la distraction du conducteur.
  • Les écrans de configuration doivent correspondre au système de conception de chaque véhicule. La mise en page générale de l'écran, les icônes, les couleurs et d'autres aspects doivent être cohérents avec le reste de l'UI. Pour en savoir plus, consultez Personnalisation.

Implémenter un écran de paramètres

Intégration des paramètres

Figure 4. Intégration des paramètres

Les écrans de paramètres sont des activités Android classiques. S'il est implémenté, son point d'entrée doit être déclaré dans res/xml/interaction_service.xml dans les fichiers manifestes VIA (voir Fichiers manifestes). La section "Paramètres" est un bon endroit pour poursuivre la configuration et la connexion (si l'utilisateur ne les a pas terminées) ou pour proposer une option de déconnexion ou de changement d'utilisateur si nécessaire. Comme pour les écrans de configuration décrits ci-dessus, ces écrans doivent :

  • Offrez la possibilité de revenir à l'écran précédent dans la pile d'écrans (par exemple, aux paramètres de la voiture).
  • ne pas être autorisée lorsque vous conduisez. Pour en savoir plus, consultez les Consignes concernant la distraction du conducteur.
  • Associez chaque système de conception de véhicules. Pour en savoir plus, consultez Personnalisation.

Déclarer les autorisations requises dans le fichier manifeste

Les autorisations requises par une VIA peuvent être divisées en trois catégories :

  • Autorisations de signature du système Il s'agit d'autorisations accordées uniquement aux APK préinstallés et signés par le système. Les utilisateurs ne peuvent pas accorder ces autorisations. Seuls les OEM peuvent les accorder lors de la création de leurs images système. Pour en savoir plus sur l'obtention d'autorisations de signature, consultez Accorder des autorisations privilégiées au système.
  • Autorisations dangereuses : Il s'agit d'autorisations qu'un utilisateur doit accorder à l'aide de la boîte de dialogue PermissionsController. Les OEM peuvent préaccorder certaines de ces autorisations au VoiceInteractionService par défaut. Toutefois, étant donné que cette valeur par défaut peut varier d'un appareil à l'autre, les applications doivent pouvoir demander ces autorisations si nécessaire.
  • Autres autorisations Il s'agit de toutes les autres autorisations qui ne nécessitent pas l'intervention de l'utilisateur. Ces autorisations sont accordées automatiquement par le système.

Compte tenu de ce qui précède, la section suivante se concentre uniquement sur la demande d'autorisations dangereuses. Les autorisations ne doivent être demandées que lorsque l'utilisateur se trouve sur les écrans de connexion ou de paramètres.

Si l'application ne dispose pas des autorisations nécessaires pour fonctionner, le flux recommandé consiste à utiliser une expression vocale pour expliquer la situation à l'utilisateur et une notification pour lui permettre de revenir aux écrans des paramètres VIA. Pour en savoir plus, consultez 1. Rappel de notification.

Demander des autorisations sur l'écran des paramètres

Les autorisations dangereuses sont demandées à l'aide de la méthode ActivityCompat#requestPermission() habituelle (ou équivalente). Pour savoir comment demander des autorisations, consultez Demander des autorisations d'application.

Demander des autorisations

Figure 5. Demander des autorisations

Autorisation d'écouteur de notifications

Pour implémenter le flux TTR, les VUI doivent être désignées comme écouteur de notifications. Il ne s'agit pas d'une autorisation à proprement parler, mais d'une configuration qui permet au système d'envoyer des notifications aux écouteurs enregistrés. Pour savoir si le VIA a eu accès à ces informations, les applications peuvent :

Si cet accès n'est pas préaccordé, le VIA doit rediriger l'utilisateur vers la section "Accès aux notifications" des paramètres de la voiture, en utilisant une combinaison d'énoncés et de notifications. Le code suivant peut être utilisé pour ouvrir la section appropriée de l'application Paramètres :

private void requestNotificationListenerAccess() {
    Intent intent = new Intent(Settings
        .ACTION_NOTIFICATION_LISTENER_SETTINGS);
    intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName());
    startActivity(intent);
}

Implémenter une UI d'élément vocal

Lorsqu'un VoiceInteractionSession reçoit un rappel onShow(), il peut présenter une UI de plaque vocale. Pour obtenir des consignes visuelles et concernant l'UX sur l'implémentation des plaques vocales,consultez Assistants préchargés : conseils sur l'UX.

Afficher l&#39;élément vocal

Figure 6. Afficher l'élément vocal

Deux options s'offrent à vous pour implémenter cette UI :

  • Ignorer VoiceInteractionSession#onCreateContentView()
  • Lancer une activité à l'aide de VoiceInteractionSession#startAssistantActivity()

Utiliser onCreateContentView()

Il s'agit de la méthode par défaut pour présenter une plaque vocale. La classe de base VoiceInteractionSession crée une fenêtre et gère son cycle de vie tant qu'une session vocale est active. Les applications doivent remplacer VoiceInteractionSession#onCreateContentView() et renvoyer une vue associée à cette fenêtre dès que la session est créée. Cette vue doit être invisible au départ. Lorsqu'une interaction vocale commence, cette vue doit être rendue visible sur VoiceInteractionSession#onShow(), puis à nouveau invisible sur 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);
    }
    
}

Lorsque vous utilisez cette méthode, vous pouvez ajuster VoiceInteractionSession#onComputeInsets() pour tenir compte des régions masquées de votre UI.

Utiliser startAssistantActivity()

Dans ce cas, VoiceInteractionSession délègue la gestion de l'UI de la plaque vocale à une activité régulière. Lorsque cette option est utilisée, une implémentation VoiceInteractionSession doit désactiver la création de sa fenêtre de contenu par défaut (voir Utiliser onCreateContentView()) sur le rappel onPrepareShow(). À VoiceInteractionSession#onShow(), la session démarrerait l'activité de reconnaissance vocale à l'aide de VoiceInteractionSession#startAssistantActivity(). Cette méthode lance l'UI avec les paramètres de fenêtre et les indicateurs d'activité appropriés.

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);
    }

    
}

Pour maintenir une communication entre cette activité et le VoiceInteractionSession, un ensemble d'intents internes ou de liaison de service peut être requis. Par exemple, lorsque VoiceInteractionSession#onHide() est appelé, la session doit pouvoir transmettre cette requête à l'activité.

Important : Dans Automotive, seules les activités spécialement annotées ou celles figurant dans la "liste autorisée" UXR peuvent être affichées pendant la conduite. Cela s'applique également aux activités lancées avec VoiceInteractionSession#startAssistantActivity(). N'oubliez pas d'annoter votre activité avec <meta-data android:name="distractionOptimized" android:value="true"/> ou d'inclure cette activité dans la clé systemActivityWhitelist du fichier /packages/services/Car/service/res/values/config.xml. Pour en savoir plus, consultez les Consignes concernant la distraction du conducteur.

Implémenter la reconnaissance vocale

Dans cette section, vous allez apprendre à implémenter la reconnaissance vocale en détectant et en reconnaissant les mots clés. Un mot clé d'activation est un mot déclencheur utilisé pour démarrer une nouvelle requête ou action par commande vocale. (par exemple, "Ok Google" ou "Hey Google").

Détection de mot clé par le DSP

Android fournit un détecteur de mot clé toujours activé au niveau du DSP à l'aide de AlwaysOnHotwordDetector. façon d'implémenter la détection de mots clés avec un faible CPU. L'utilisation de cette fonctionnalité est divisée en deux parties :

L'implémentation de VoiceInteractionService peut créer un détecteur de mot clé à l'aide de VoiceInteractionService#createAlwaysOnHotwordDetector(), en transmettant une expression clé et un paramètre régional qu'elle souhaite utiliser pour la détection. Par conséquent, l'application reçoit un rappel onAvailabilityChanged() avec l'une des valeurs possibles suivantes :

  • STATE_HARDWARE_UNAVAILABLE. La fonctionnalité DSP n'est pas disponible sur l'appareil. Dans ce cas, la détection logicielle du mot clé est utilisée.
  • STATE_HARDWARE_UNSUPPORTED. L'assistance DSP n'est pas disponible en général, mais DSP n'est pas compatible avec la combinaison de mots clés et de paramètres régionaux donnée. L'application peut choisir d'utiliser la détection logicielle du mot clé.
  • STATE_HARDWARE_ENROLLED. La détection des mots clés est prête et peut être lancée en appelant la méthode startRecognition().
  • STATE_HARDWARE_UNENROLLED. Aucun modèle sonore n'est disponible pour l'expression clé demandée, mais l'enregistrement est possible.

Vous pouvez enregistrer des modèles sonores de détection de mot clé à l'aide de IVoiceInteractionManagerService#updateKeyphraseSoundModel(). Plusieurs modèles peuvent être enregistrés dans le système à un moment donné, mais un seul modèle est associé à un AlwaysOnHotwordDetector. Il est possible que la détection du mot clé par le DSP ne soit pas disponible sur tous les appareils. Les développeurs VIA doivent vérifier les capacités matérielles à l'aide de la méthode getDspModuleProperties(). Pour obtenir un exemple de code montrant comment enregistrer des modèles sonores, consultez VoiceEnrollment/src/com/android/test/voiceenrollment/EnrollmentUtil.java. Consultez Capture simultanée concernant la reconnaissance simultanée de mots clés.

Détection de mot clé logiciel

Comme indiqué ci-dessus, la détection de mot clé DSP peut ne pas être disponible sur tous les appareils (par exemple, l'émulateur Android ne fournit pas d'émulation DSP). Dans ce cas, la reconnaissance vocale logicielle est la seule alternative. Pour éviter d'interférer avec d'autres applications qui pourraient avoir besoin d'accéder au micro, les AVR doivent accéder à l'entrée audio en utilisant :

Ces deux constantes sont @hide et ne sont disponibles que pour les applications groupées.

Gérer l'entrée audio et la reconnaissance vocale

L'entrée audio sera implémentée à l'aide de la classe MediaRecorder. Pour en savoir plus sur l'utilisation de cette API, consultez la présentation de MediaRecorder. Les services d'interaction vocale doivent également être des implémentations de la classe RecognitionService. Toute application du système nécessitant la reconnaissance vocale utilise le pour accéder à cette fonctionnalité. Pour effectuer la reconnaissance vocale et accéder au micro, les VAI doivent disposer de android.permission.RECORD_AUDIO. Les applications qui accèdent à une implémentation RecognitionService sont également censées détenir cette autorisation.

Avant Android 10, l'accès au micro n'était accordé qu'à une seule application à la fois (à l'exception de la détection de mots clés, voir ci-dessus). À partir d'Android 10, l'accès au micro peut être partagé. Pour en savoir plus, consultez Partager l'entrée audio.

Accéder à la sortie audio

Lorsque l'AVR est prêt à fournir des réponses verbales, il est important de suivre les consignes suivantes :