Para implementar una aplicación de interacción de voz (VIA), complete estos pasos:
- Cree un esqueleto VIA.
- ( opcional ) Implemente un flujo de configuración/inicio de sesión.
- ( opcional ) Implementar una pantalla de Configuración.
- Declare los permisos necesarios en el archivo de manifiesto.
- Implemente una interfaz de usuario de placa de voz.
- Implementar el reconocimiento de voz (debe incluir la implementación de la API de RecognitionService).
- Implemente la expresión (opcionalmente, puede implementar la API TextToSpeech).
- Implementar cumplimiento de comandos. Ver este contenido en Cumplimiento de Comandos .
Las siguientes secciones describen cómo completar cada paso mencionado anteriormente.
Crear un esqueleto VIA
Manifiestos
Una aplicación se detecta como una con interacción de voz cuando se incluye lo siguiente en el manifiesto:
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>
En este ejemplo:
- Los VIA deben exponer un servicio que amplíe
VoiceInteractionService
, con un filtro de intención para la acciónVoiceInteractionService.SERVICE_INTERFACE ("android.service.voice.VoiceInteractionService")
. - Este servicio debe tener el permiso de firma del sistema
BIND_VOICE_INTERACTION
. - Este servicio debe incluir un archivo de metadatos
android.voice_interaction
para contener lo siguiente:res/xml/interacción_servicio.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" />
Para obtener detalles sobre cada campo, consulte R.styleable#VoiceInteractionService
. Dado que todos los VIA también son servicios de reconocimiento de voz, también debe incluir lo siguiente en su manifiesto:
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>
Los servicios de reconocimiento de voz también requieren los siguientes metadatos:
res/xml/recognition_service.xml
<recognition-service xmlns:android="http://schemas.android.com/apk/res/android" android:settingsActivity="com.example.MyRecognizerSettingsActivity" />
VoiceInteractionService
, VoiceInteractionSessionService
y VoiceInteractionSession
El siguiente diagrama muestra el ciclo de vida de cada una de estas entidades:
Figura 1. Ciclos de vida
Como se indicó anteriormente, VoiceInteractionService
es el punto de entrada a un VIA. Las principales responsabilidades de este servicio son:
- Inicialice cualquier proceso que deba seguir ejecutándose mientras este VIA sea el activo. Por ejemplo, detección de palabras activas.
- Informa acciones de voz admitidas (ver Asistente de voz Tocar para leer ).
- Inicie sesiones de interacción de voz desde la pantalla de bloqueo (protector de teclado).
En su forma más simple, una implementación de VoiceInteractionService se vería así:
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; } ... }
Se requiere la implementación de VoiceInteractionService#onGetSupportedVoiceActions()
para manejar Voice Assistant Tap-to-Read . El sistema utiliza VoiceInteractionSessionService para crear e interactuar con VoiceInteractionSession . Solo tiene una responsabilidad, iniciar nuevas sesiones cuando se le solicite.
public class MyVoiceInteractionSessionService extends VoiceInteractionSessionService { @Override public VoiceInteractionSession onNewSession(Bundle args) { return new MyVoiceInteractionSession(this); } }
Finalmente, una VoiceInteractionSession es donde se realizaría la mayor parte del trabajo. Una única instancia de sesión puede reutilizarse para completar múltiples interacciones de usuario. En AAOS, existe un asistente CarVoiceInteractionSession
, que ayuda a implementar algunas de las funcionalidades únicas del automóvil.
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
tiene un gran conjunto de métodos de devolución de llamada que se explicarán en las siguientes secciones. consulte la documentación de VoiceInterationSession
para obtener una lista completa.
Implementar un flujo de configuración/inicio de sesión
La configuración y el inicio de sesión pueden ocurrir:
- Durante la incorporación del dispositivo (Asistente de configuración).
- Durante el intercambio de servicios de interacción de voz (Configuración).
- En el primer lanzamiento cuando se selecciona la aplicación.
Para obtener detalles sobre la experiencia de usuario recomendada y la orientación visual, consulte Asistentes precargados: orientación de UX .
Configuración durante el cambio de servicio de voz
Siempre es posible que el usuario seleccione un VIA que no haya sido configurado correctamente. Esto puede suceder porque:
- El usuario omitió el Asistente de configuración por completo o el usuario omitió el paso de configuración de la interacción de voz.
- El usuario seleccionó un VIA diferente al configurado durante la incorporación del dispositivo.
En cualquier caso, VoiceInteractionService
tiene varias formas de animar al usuario a completar la configuración:
- Recordatorio de notificación.
- Respuesta de voz automática cuando el usuario intenta utilizarla.
Nota : se desaconseja encarecidamente presentar un flujo de configuración de VIA sin una solicitud explícita del usuario. Esto significa que los VIA deben evitar mostrar contenido automáticamente en la HU durante el arranque del dispositivo o como resultado de un cambio o desbloqueo del usuario.
1. Recordatorio de notificación
Un recordatorio de notificación es una forma no intrusiva de indicar la necesidad de configuración y de proporcionar a los usuarios la posibilidad de navegar en el flujo de configuración del asistente.
Figura 2. Recordatorio de notificación
Así es como funcionaría este flujo:
Figura 3. Flujo de recordatorio de notificación
Note
: según las reglas de restricción de UX (consulte las Pautas de distracción del conductor ), es posible que no se permitan los flujos de configuración mientras se conduce. Cuando el usuario hace clic en la notificación y no se permite la configuración, la aplicación debe usar un enunciado para explicar la situación al usuario en lugar de intentar mostrar una interfaz de usuario que se bloqueará de inmediato.
2. Respuesta de voz
Este es el flujo más simple de implementar, iniciando una expresión en una devolución de llamada de VoiceInteractionSession#onShow()
, explicando al usuario lo que debe hacerse y luego preguntándole (si la configuración está permitida dado el estado de restricción de UX) si desea iniciar el flujo de configuración. Si la configuración no es posible en ese momento, explique también esta situación.
Configuración en el primer uso
Siempre es posible que el usuario active un VIA que no se haya configurado correctamente. En esos casos:
- Informar verbalmente al usuario sobre esta situación (por ejemplo, "Para que funcione correctamente, necesito que completes algunos pasos...").
- Si el motor de restricciones de UX lo permite (consulte UX_RESTRICTIONS_NO_SETUP ), pregúntele al usuario si desea iniciar el proceso de configuración y luego abra la pantalla Configuración para VIA.
- De lo contrario (por ejemplo, si el usuario está conduciendo), deje una notificación para que el usuario haga clic en la opción cuando sea seguro hacerlo.
Creación de pantallas de configuración de interacción de voz
Las pantallas de configuración e inicio de sesión deben desarrollarse como actividades regulares. Consulte las pautas visuales y de experiencia de usuario para el desarrollo de la interfaz de usuario en Asistentes precargados: guía de experiencia de usuario.
Reglas generales:
- Los VIA deberían permitir a los usuarios interrumpir y reanudar la configuración en cualquier momento.
- No se debe permitir la instalación si la restricción
UX_RESTRICTIONS_NO_SETUP
está en vigor. Para obtener más información, consulte las Pautas de distracción del conductor . - Las pantallas de configuración deben coincidir con el sistema de diseño de cada vehículo. El diseño general de la pantalla, los iconos, los colores y otros aspectos deben ser coherentes con el resto de la interfaz de usuario. Ver Personalización para más detalles.
Implementar una pantalla de configuración
Figura 4. Integración de configuraciones
Las pantallas de configuración son actividades regulares de Android. Si se implementa, su punto de entrada debe declararse en res/xml/interaction_service.xml
como parte de los manifiestos de VIA (consulte Manifiestos ). La sección Configuración es un buen lugar para continuar con la configuración e iniciar sesión (si el usuario no la completó) u ofrecer una opción para cerrar sesión o cambiar de usuario si es necesario. De forma similar a las pantallas de configuración descritas anteriormente, estas pantallas deberían:
- Proporcione la opción de volver a la pantalla anterior en la pila de pantallas (por ejemplo, a Configuración del automóvil).
- No se permitirá mientras se conduce. Para obtener más información, consulte las Pautas de distracción del conductor .
- Haga coincidir cada sistema de diseño de vehículos. Para obtener más información, consulte Personalización .
Declarar los permisos requeridos en el archivo de manifiesto
Los permisos requeridos por un VIA se pueden dividir en tres categorías:
- Permisos de firma del sistema. Estos son permisos que solo se otorgan a APK preinstalados y firmados por el sistema. Los usuarios no pueden otorgar estos permisos, solo los OEM pueden otorgarlos al crear las imágenes de su sistema. Para obtener más información sobre cómo obtener permisos de firma, consulte Otorgar permisos privilegiados del sistema .
- Permisos peligrosos. Estos son permisos que un usuario debe otorgar mediante el cuadro de diálogo PermissionsController. Los OEM pueden otorgar previamente algunos de estos permisos al VoiceInteractionService predeterminado. Pero dado que este valor predeterminado puede cambiar de un dispositivo a otro, las aplicaciones deberían poder solicitar estos permisos cuando sea necesario.
- Otros permisos. Estos son todos los demás permisos que no requieren la intervención del usuario. Estos permisos serán otorgados automáticamente por el sistema.
Dado lo anterior, la siguiente sección se centrará únicamente en solicitar permisos peligrosos. Los permisos solo deben solicitarse mientras el usuario está en las pantallas de inicio de sesión o configuración.
Si la aplicación no tiene los permisos necesarios para operar, el flujo recomendado es usar una declaración de voz para explicar la situación al usuario y una notificación para proporcionar una posibilidad que el usuario puede usar para navegar de regreso a las pantallas de configuración de VIA. . Para obtener más información, consulte 1. Recordatorio de notificación .
Solicitar permisos como parte de la pantalla de configuración
Los permisos peligrosos se solicitan mediante el método normal ActivityCompat#requestPermission()
(o equivalente). Para obtener detalles sobre cómo solicitar permisos, consulte Solicitar permisos de aplicaciones .
Figura 5. Solicitud de permisos
Permiso de escucha de notificaciones
Para implementar el flujo de TTR, los VIA deben designarse como detectores de notificaciones. Este no es un permiso en sí, sino una configuración que permite que el sistema envíe notificaciones a los oyentes registrados. Para saber si el VIA tuvo acceso a esta información, las aplicaciones pueden:
- (Opcional) Verifique si hay escuchas de notificaciones con anticipación usando
CarAssistUtils#assistantIsNotificationListener()
. Esto podría hacerse, por ejemplo, durante el flujo de configuración. - (Obligatorio) Reaccione al manejo de
CarVoiceInteractionSession#onShow()
con la acciónVOICE_ACTION_HANDLE_EXCEPTION
y la excepciónEXCEPTION_NOTIFICATION_LISTENER_PERMISSIONS_MISSING
.
Si este acceso no se otorga previamente, el VIA debe dirigir al usuario a la sección Acceso a notificaciones de Configuración del automóvil, mediante una combinación de declaraciones y notificaciones. El siguiente código se puede utilizar para abrir la sección correspondiente de la aplicación de configuración:
private void requestNotificationListenerAccess() { Intent intent = new Intent(Settings .ACTION_NOTIFICATION_LISTENER_SETTINGS); intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName()); startActivity(intent); }
Implementar una interfaz de usuario de placa de voz
Cuando una VoiceInteractionSession
recibe una devolución de llamada onShow()
, puede presentar una interfaz de usuario de placa de voz. Para obtener pautas visuales y de experiencia de usuario sobre la implementación de placas de voz, consulte Asistentes precargados: orientación de experiencia de usuario .
Figura 6. Visualización de la placa de voz
Hay dos opciones sobre cómo implementar esta interfaz de usuario:
- Anular
VoiceInteractionSession#onCreateContentView()
- Inicie una actividad usando
VoiceInteractionSession#startAssistantActivity()
Usando onCreateContentView()
Esta es la forma predeterminada de presentar una placa de voz. La clase base VoiceInteractionSession creará una ventana y administrará su ciclo de vida mientras la sesión de voz esté activa. Las aplicaciones deben anular VoiceInteractionSession#onCreateContentView()
y devolver una vista que se adjuntará a esa ventana tan pronto como se cree la sesión. Esta vista debería ser inicialmente invisible. Cuando comienza una interacción de voz, esta vista debe hacerse visible en VoiceInteractionSession#onShow()
y luego volver a ser invisible en 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); } … }
Al usar este método, es posible que desee ajustar VoiceInteractionSession#onComputeInsets() para tener en cuenta las regiones ocultas de su interfaz de usuario.
Uso startAssistantActivity()
En este caso, VoiceInteractionSession
delegará el manejo de la interfaz de usuario de la placa de voz a una actividad normal. Cuando se usa esta opción, una implementación de VoiceInteractionSession
debe deshabilitar la creación de su ventana de contenido predeterminada (consulte Usar onCreateContentView() ) en la devolución de llamada onPrepareShow()
. En VoiceInteractionSession#onShow()
, la sesión iniciaría la actividad de la placa de voz mediante VoiceInteractionSession#startAssistantActivity()
. Este método inicia la interfaz de usuario con la configuración de ventana y los indicadores de actividad adecuados.
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); } … }
Para mantener una comunicación entre esta actividad y VoiceInteractionSession
, es posible que se requiera un conjunto de intentos internos o enlace de servicio. Por ejemplo, cuando se VoiceInteractionSession#onHide()
, la sesión debe poder pasar esta solicitud a la actividad.
Importante. En Automotive, solo las actividades especialmente anotadas o las actividades enumeradas en la "lista permitida" de UXR se pueden mostrar mientras se conduce. Esto también se aplica a las actividades iniciadas con VoiceInteractionSession#startAssistantActivity()
. Recuerde anotar su actividad con <meta-data android:name="distractionOptimized" android:value="true"/>
o incluir esta actividad en la clave systemActivityWhitelist
de /packages/services/Car/service/res/values/config.xml
archivo /packages/services/Car/service/res/values/config.xml
. Para obtener más información, consulte Pautas de distracción del conductor .
Implementar reconocimiento de voz
En esta sección, aprenderá a implementar el reconocimiento de voz a través de la detección y el reconocimiento de palabras activas. Una palabra activa es una palabra desencadenante que se utiliza para iniciar una nueva consulta o acción por voz. Por ejemplo, "OK Google" o "Hola Google".
Detección de palabras activas DSP
Android proporciona acceso a un detector de palabras activas siempre activo en el nivel de DSP mediante la clase AlwaysOnHotwordDetector
. Esto proporciona una manera conveniente de implementar la detección de palabras activas con poca CPU. El uso de esta funcionalidad se divide en dos partes:
- Instanciación de un
AlwaysOnHotwordDetector
. - Registro de un modelo de sonido de detección de palabras activas.
La implementación de VoiceInteractionService puede crear un detector de palabras activas utilizando VoiceInteractionService#createAlwaysOnHotwordDetector()
, pasando una frase clave y una configuración regional que deseen usar para la detección. Como resultado, la aplicación recibirá una devolución de llamada onAvailabilityChanged()
con uno de los siguientes valores posibles:
-
STATE_HARDWARE_UNAVAILABLE
. La capacidad DSP no está disponible en el dispositivo. En este caso, se utilizará la detección de palabras activas de software. -
STATE_HARDWARE_UNSUPPORTED
. La compatibilidad con DSP no está disponible en general, pero DSP no admite una determinada combinación de frase clave y configuración regional. La aplicación puede optar por utilizar la detección de palabras activas de software . -
STATE_HARDWARE_ENROLLED
. La detección de palabras activas está lista y se puede iniciar llamando al métodostartRecognition()
. -
STATE_HARDWARE_UNENROLLED
. No hay disponible un modelo de sonido para la frase clave solicitada, pero es posible realizar la inscripción.
La inscripción de modelos de sonido de detección de palabras activas se puede realizar mediante IVoiceInteractionManagerService#updateKeyphraseSoundModel()
. Se pueden registrar varios modelos en el sistema en un momento dado, pero solo un modelo se asociará con un AlwaysOnHotwordDetector
. Es posible que la detección de palabras activas de DSP no esté disponible en todos los dispositivos. Los desarrolladores de VIA deben comprobar las capacidades del hardware mediante el método getDspModuleProperties()
. Para obtener un código de muestra que muestre cómo inscribir modelos de sonido, consulte VoiceEnrollment/src/com/android/test/voiceenrollment/EnrollmentUtil.java
. Consulte Captura simultánea sobre el reconocimiento de palabras activas simultáneas.
Detección de palabras activas de software
Como se indicó anteriormente, es posible que la detección de palabras activas de DSP no esté disponible en todos los dispositivos (por ejemplo, el emulador de Android no proporciona emulación de DSP). En este caso, el software de reconocimiento de voz es la única alternativa. Para evitar interferir con otras aplicaciones que puedan necesitar acceso al micrófono, los VIA deben acceder a la entrada de audio mediante:
- La captura de audio debe usar MediaRecorder.AudioSource.HOTWORD .
- Mantenga el permiso
android.Manifest.permission.CAPTURE_AUDIO_HOTWORD
.
Ambas constantes son @hide
y están disponibles solo para aplicaciones empaquetadas.
Administrar la entrada de audio y el reconocimiento de voz
La entrada de audio se implementaría mediante la API de MediaRecorder . Para obtener más información sobre cómo usar esta API, consulte la descripción general de MediaRecorder . También se espera que los servicios de interacción de voz sean implementaciones de RecognitionService
. Cualquier aplicación en el sistema que requiera reconocimiento de voz utilizará la API SpeechRecognizer para acceder a esta capacidad. Para realizar el reconocimiento de voz y tener acceso al micrófono, los VIA deben tener android.permission.RECORD_AUDIO
. Se espera que las aplicaciones que acceden a una implementación de RecognitionService
también tengan este permiso.
Antes de Android 10, el acceso al micrófono se otorgaba solo a una aplicación a la vez (con la excepción de la detección de palabras activas, consulte más arriba). A partir de Android 10, se puede compartir el acceso al micrófono. Para obtener más información, consulte Compartir entrada de audio .
Acceso a la salida de audio
Cuando el VIA esté listo para proporcionar respuestas verbales, es importante seguir el siguiente conjunto de pautas:
- Al solicitar el enfoque de audio o administrar la salida de audio, la aplicación debe usar
AudioAttributes#USAGE_ASSISTANT
yAudioAttributes#CONTENT_TYPE_SPEECH
como atributos de audio. - Durante el reconocimiento de voz, se debe solicitar el enfoque de audio con
AudioManage#AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE
. Tenga en cuenta que algunas aplicaciones de medios pueden no reaccionar correctamente a los comandos de medios (consulte Cumplimiento de los comandos de medios ) mientras se quita el foco de audio.