Para implementar una aplicación de interacción de voz (VIA), debes completar estos pasos:
- Crea un esqueleto mediante el VIA.
- Implementa un flujo de configuración o acceso (opcional).
- Implementa una pantalla de configuración (opcional).
- Declara los permisos necesarios en el archivo de manifiesto.
- Implementa una IU de placa de voz.
- Implementar el reconocimiento de voz (debe incluir la implementación de la API de RecognitionService).
- Implementa una declaración (de forma opcional, puedes implementar la API de TextToSpeech).
- Implementar la entrega de comandos Ver este contenido en Cómo entregar comandos.
En las siguientes secciones, se describe cómo completar cada paso mencionado anteriormente.
Crea un esqueleto mediante VIA
Manifiestos
Una app se detecta como una con interacción de voz cuando se cumple lo siguiente: incluido 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 extienda
VoiceInteractionService
, con un filtro de intents 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
contenga lo siguiente: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" />
Para obtener detalles sobre cada campo, consulta R.styleable#VoiceInteractionService
.
Dado que todas las VIA también son servicios de reconocimiento de voz, también debe
incluye lo siguiente en tu 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
En el siguiente diagrama, se muestra el ciclo de vida de cada una de estas entidades:
Figura 1: Lifecycles
Como se indicó antes, VoiceInteractionService
es el punto de entrada
a un VIA. Las responsabilidades principales de este servicio son las siguientes:
- Inicializa cualquier proceso que se deba mantener en ejecución por el tiempo que esta VIA es la activa. Por ejemplo, la detección de palabras clave.
- Informa las acciones de voz compatibles (consulta Presionar para leer del Asistente de voz).
- Permite iniciar sesiones de interacción por voz desde la pantalla de bloqueo (bloqueo de teclado).
En su forma más sencilla, 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; } ... }
La implementación de VoiceInteractionService#onGetSupportedVoiceActions()
es
necesario para manejar
Presionar para leer de Asistente de voz
El sistema usa un VoiceInteractionSessionService para crear y
interactuar con una VoiceInteractionSession. Solo tiene una responsabilidad,
iniciar sesiones nuevas cuando se solicite.
public class MyVoiceInteractionSessionService extends VoiceInteractionSessionService { @Override public VoiceInteractionSession onNewSession(Bundle args) { return new MyVoiceInteractionSession(this); } }
Por último, en una VoiceInteractionSession es donde la mayor parte del trabajo
se realizaría. Una única instancia de sesión puede reutilizarse para completar varias
interacciones del usuario. En AAOS, existe un CarVoiceInteractionSession
auxiliar,
para implementar algunas de las funcionalidades únicas de la industria automotriz.
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 son
que se explican en las siguientes secciones. consulta la documentación de VoiceInteractionSession
para obtener una lista completa.
Implementar un flujo de configuración/acceso
Pueden realizarse la configuración y el acceso:
- Durante la integración del dispositivo (asistente de configuración).
- Durante el cambio de servicio de interacción por voz (Configuración).
- Cuando se selecciona la app por primera vez,
Para obtener detalles sobre la experiencia del usuario recomendada y la orientación visual, consulta Asistentes precargados: Guía de UX.
Configuración durante el cambio del servicio de voz
Siempre es posible que el usuario seleccione un VIA que no ha sido configurado. Esto puede suceder por los siguientes motivos:
- El usuario omitió el asistente de configuración por completo o la voz de configuración de interacción.
- El usuario seleccionó un VIA diferente del que se configuró durante el dispositivo. durante el proceso de incorporación.
En cualquier caso, un VoiceInteractionService
tiene varias formas de incentivar al usuario
para completar la configuración:
- Recordatorio de notificación.
- Es la respuesta de voz automática cuando el usuario intenta usarla.
Nota: No se recomienda presentar un flujo de configuración mediante VIA. sin una solicitud explícita del usuario. Esto significa que las VIA deben evitar automáticamente mostrar contenido en el HU durante el inicio del dispositivo o como resultado de un cambio de usuario desbloquear.
Recordatorio de notificación
Una notificación de recordatorio es una forma no invasiva de indicar la necesidad de la configuración. y brindarles a los usuarios una indicación visual para navegar a la configuración del Asistente de tu flujo de trabajo.
Figura 2: Recordatorio de notificación
Este flujo funcionaría de la siguiente manera:
Figura 3: Flujo de recordatorios de notificaciones
Respuesta de voz
Este es el flujo más simple de implementar, iniciar una declaración en
Una devolución de llamada VoiceInteractionSession#onShow()
, en la que se le explica al usuario
debe realizarse y, luego, preguntarles (si se permite la configuración dado el estado de restricción de UX)
si desea iniciar el flujo de configuración. Si no es posible realizar la configuración en ese momento, explica lo siguiente:
en tu situación actual.
Configurar en el primer uso
Siempre es posible que el usuario active un VIA que no ha sido configurado. En esos casos:
- Informa verbalmente al usuario sobre esta situación (por ejemplo, "Para trabajar correctamente, Necesitamos que completes algunos pasos ... ").
- Si el motor de restricciones de UX lo permite (consulta UX_RESTRICTIONS_NO_SETUP), pregúntale al usuario si quiere iniciar la y, luego, abre la pantalla de Configuración del VIA.
- De lo contrario (por ejemplo, si el usuario está conduciendo), deja una notificación para que el usuario haz clic en la opción cuando sea seguro hacerlo.
Cómo crear pantallas de configuración de interacción de voz
Las pantallas de acceso y configuración deben desarrollarse como actividades habituales. Consulta la lineamientos visuales y de UX para el desarrollo de IU en Asistentes precargados: Guía de UX.
Lineamientos generales:
- Las Innovaciones deben permitir a los usuarios interrumpir y reanudar la configuración en cualquier momento.
- No se debe permitir la configuración si la restricción
UX_RESTRICTIONS_NO_SETUP
está activa. Para obtener más información, consulta Lineamientos sobre distracción del conductor. - Las pantallas de configuración deben coincidir con el sistema de diseño de cada vehículo. Pantalla general el diseño, los iconos, los colores y otros aspectos deben ser coherentes con el resto de la interfaz de usuario. Consulta Personalización para conocer los detalles.
Cómo implementar una pantalla de configuración
Figura 4: Integración de la configuración
Las pantallas de configuración son actividades habituales de Android. Si se implementa, su punto de entrada
se debe declarar en el res/xml/interaction_service.xml
como parte del VIA
manifiestos (consulta
Manifiestos).
La sección Configuración es un buen lugar para continuar con la configuración y el acceso (si el usuario no la completó
o bien, ofrece la opción de salir o cambiar de usuario, de ser necesario. Similar a la configuración
pantallas descritas anteriormente, estas pantallas deben:
- Ofrecer la opción de volver a la pantalla anterior en la pila de pantallas (por ejemplo, a la Configuración del vehículo).
- No se permite mientras se conduce. Para obtener más información, consulta los Lineamientos sobre distracciones del conductor.
- Haz coincidir cada sistema de diseño de vehículo. Para obtener más información, consulta Personalización.
Declara los permisos necesarios en el archivo de manifiesto
Los permisos que se requieren en un VIA se pueden dividir en tres categorías:
- Permisos de firma del sistema. Estos son permisos Solo se otorga a APK preinstalados y firmados por el sistema. Los usuarios no pueden otorgar estos permisos, solo los OEM pueden otorgarlos cuando compilan las imágenes del sistema. Para obtener más información sobre cómo obtener permisos de firma, consulta Cómo otorgar permisos privilegiados del sistema.
- Permisos peligrosos. Estos son los permisos que un usuario debe otorgar con el diálogo PermissionsController. Los OEM pueden otorgar previamente algunos de estos permisos para el VoiceInteractionService predeterminado. Sin embargo, como esta configuración pueden cambiar de un dispositivo a otro, las apps deberían poder solicitar estas permisos cuando sea necesario.
- Otros permisos. Estos son todos los demás permisos que no requieren la intervención del usuario. Estos permisos se otorgan automáticamente por el sistema.
Dado lo anterior, la siguiente sección se enfoca solo en solicitar permisos peligrosos. Solo se deben solicitar permisos mientras el usuario esté en las pantallas de acceso o configuración.
Si la aplicación no tiene los permisos necesarios para funcionar, el de flujo recomendado es utilizar una expresión oral para explicarle la situación al usuario y una notificación para proporcionar una indicación visual que el usuario puede usar para vuelve a las pantallas de configuración de VIA. Para obtener más información, consulta 1. Recordatorio de notificación.
Solicita permisos como parte de la pantalla de configuración
Los permisos peligrosos se solicitan con el método normal ActivityCompat#requestPermission()
(o equivalente). Para obtener detalles sobre cómo solicitar permisos, consulta
Solicita permisos de la app.
Figura 5: Solicita permisos
Permiso de objeto de escucha de notificaciones
Para implementar el flujo del TTR, los VAI deben designarse como objeto de escucha de notificaciones. Este no es un permiso propiamente dicho, predeterminada que permite que el sistema envíe notificaciones a objetos de escucha. Para saber si se otorgó acceso a esta información a la VIA, haz lo siguiente: las apps pueden hacer lo siguiente:
- Comprueba si hay objetos de escucha de notificaciones con anticipación usando
CarAssistUtils#assistantIsNotificationListener()
Esto puede hacerse, por ejemplo, durante el flujo de configuración. - (Obligatorio) Debes reaccionar a la acción de controlar
CarVoiceInteractionSession#onShow()
VOICE_ACTION_HANDLE_EXCEPTION
y la excepciónEXCEPTION_NOTIFICATION_LISTENER_PERMISSIONS_MISSING
.
Si este acceso no se otorga previamente, el VIA debe dirigir al usuario al Sección de acceso a notificaciones de la configuración del vehículo, con una combinación de declaraciones y notificaciones. Puedes usar el siguiente código para abrir la sección correspondiente de la App de Configuración:
private void requestNotificationListenerAccess() { Intent intent = new Intent(Settings .ACTION_NOTIFICATION_LISTENER_SETTINGS); intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName()); startActivity(intent); }
Cómo implementar una IU de placa de voz
Cuando un objeto VoiceInteractionSession
recibe una devolución de llamada onShow()
, ocurre lo siguiente:
puede presentar una IU de placa de voz. Para conocer los lineamientos visuales y de UX sobre la implementación de placas de voz,consulta
Asistentes precargados: Guía de UX.
Figura 6: Cómo visualizar la placa de voz
Hay dos opciones para implementar esta IU:
- Anular
VoiceInteractionSession#onCreateContentView()
- Cómo iniciar una actividad con
VoiceInteractionSession#startAssistantActivity()
Cómo usar onCreateContentView()
Esta es la forma predeterminada de presentar una placa de voz. El VoiceInteractionSession
crea una ventana y administra su ciclo de vida durante el tiempo que una voz
la sesión está activa. Las apps deben anular VoiceInteractionSession#onCreateContentView()
y devolverá una vista que se adjunta a esa ventana en cuanto la sesión se
crear. Inicialmente, esta vista debería ser invisible. Cuando comienza una interacción de voz,
esta vista debería mostrarse el VoiceInteractionSession#onShow()
y, luego, invisible de nuevo el 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); } … }
Cuando uses este método, te recomendamos ajustar VoiceInteractionSession#onComputeInsets()
.
para tener en cuenta las regiones oscuras de la IU.
Cómo usar startAssistantActivity()
En este caso, VoiceInteractionSession
delegará el control de la voz
IU de placa a una actividad normal. Cuando se usa esta opción, se muestra un VoiceInteractionSession
implementación debe inhabilitar la creación de su ventana de contenido predeterminada (consulta Cómo usar onCreateContentView()) en onPrepareShow()
devolución de llamada. A las VoiceInteractionSession#onShow()
, se iniciará la sesión con la voz
actividad de la placa con VoiceInteractionSession#startAssistantActivity()
. Esta
inicia la IU con la configuración de la ventana y las marcas de actividad adecuadas.
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 el
VoiceInteractionSession
, un conjunto de intents internos o vinculación de servicios
como en los productos necesarios. Por ejemplo, cuando se invoca VoiceInteractionSession#onHide()
, el
debe poder pasar esta solicitud a la actividad.
Importante. En Automotive, solo se admiten las anotaciones especiales
actividades o actividades enumeradas en la "lista de actividades permitidas" de UXR se pueden mostrar mientras
conducir. Esto se aplica a las actividades iniciadas con
VoiceInteractionSession#startAssistantActivity()
. Recuerda
anota tu actividad con <meta-data
android:name="distractionOptimized" android:value="true"/>
o incluye esto
Actividad en la clave systemActivityWhitelist
de /packages/services/Car/service/res/values/config.xml
. Para obtener más información, consulta Controlador
Lineamientos de distracción
Implementa el reconocimiento de voz
En esta sección, aprenderás a implementar el reconocimiento de voz mediante la detección y el reconocimiento de palabras clave. Una palabra clave es una palabra de activación que se usa para iniciar una búsqueda nueva o acción por voz. Por ejemplo, "Hey Google" o "Hey Google".
Detección de palabra clave de DSP
Android proporciona acceso a un detector de palabras clave siempre activo a nivel de la DSP
los medios de AlwaysOnHotwordDetector
.
de implementar la detección de palabras clave
con una CPU baja. El uso de esta función está
se divide en dos partes:
- Creación de la instancia de un
AlwaysOnHotwordDetector
. - Inscripción de un modelo de sonido de detección de palabras clave.
La implementación de VoiceInteractionService puede crear un detector de palabras clave mediante
VoiceInteractionService#createAlwaysOnHotwordDetector()
,
pasando la frase clave y la configuración regional que desean usar para la detección. Como resultado, el
La app recibe un onAvailabilityChanged()
Es la devolución de llamada con uno de los siguientes valores posibles:
STATE_HARDWARE_UNAVAILABLE
La función de DSP no está disponible en la dispositivo. En este caso, se usa la detección de palabras clave de software.STATE_HARDWARE_UNSUPPORTED
La compatibilidad con DSP no está disponible en general, pero La DSP no admite la combinación determinada de frase clave y configuración regional. La app puede optar por usar Detección de palabra clave de software.STATE_HARDWARE_ENROLLED
La detección de palabras activas está lista y se puede iniciar llamando al métodostartRecognition()
.STATE_HARDWARE_UNENROLLED
Un modelo de sonido para la frase clave solicitada no es disponible, pero es posible inscribirse.
La inscripción de modelos de sonido de detección de palabras clave se puede realizar con IVoiceInteractionManagerService#updateKeyphraseSoundModel()
.
Se pueden registrar varios modelos en el sistema a la vez, pero solo uno
está asociado con un AlwaysOnHotwordDetector
.
La detección de palabras clave de DSP podría no estar disponible en todos los dispositivos. A través de desarrolladores
debes verificar las capacidades del hardware con getDspModuleProperties()
. Para ver un ejemplo de código que muestra
cómo inscribir modelos de sonido, consulta VoiceEnrollment/src/com/android/test/voiceenrollment/EnrollmentUtil.java
.
Consulta la sección Captura simultánea para obtener información sobre
reconocimiento simultáneo de palabras clave.
Detección de palabra clave de software
Como se indicó anteriormente, la detección de palabras clave de DSP puede no estar disponible en todos dispositivos (por ejemplo, Android Emulator no ofrece emulación de DSP). En este caso, el reconocimiento de voz mediante software es la única alternativa. Para evitar interferir en que podrían necesitar acceso al micrófono, los VIA deben acceder a la entrada de audio usando lo siguiente:
- La captura de audio debe usar MediaRecorder.AudioSource.HOTWORD.
- Mantén presionado el permiso
android.Manifest.permission.CAPTURE_AUDIO_HOTWORD
.
Ambas constantes son @hide
y están disponibles solo para apps empaquetadas.
Cómo administrar la entrada de audio y el reconocimiento de voz
La entrada de audio se implementará con la clase MediaRecorder.
Para obtener más información sobre cómo usar esta API, consulta el archivo MediaRecorder
Descripción general. También se espera que los servicios de interacción por voz estén RecognitionService
implementaciones de clase. Cualquier aplicación del sistema que requiera el reconocimiento de voz utiliza el
para acceder a esta función. Para realizar el reconocimiento de voz y tener acceso al micrófono, las VIA
debe contener android.permission.RECORD_AUDIO
.
Apps que acceden a un RecognitionService
se espera que la implementación
también tenga este permiso.
Antes de Android 10, el acceso al micrófono se otorgaba a una sola app por vez tiempo (a excepción de la detección de palabras clave, ver arriba). A partir de Android 10, se puede compartir el acceso al micrófono. Para obtener más información, consulta Uso compartido Entrada de audio
Acceder a la salida de audio
Cuando el VIA está listo para dar respuestas verbales, es importante sigue este conjunto de lineamientos:
- Al solicitar foco de audio o administrar la salida de audio, la app
debe usar
AudioAttributes#USAGE_ASSISTANT
yAudioAttributes#CONTENT_TYPE_SPEECH
como atributos de audio. - Durante el reconocimiento de voz, el foco de audio debe solicitarse con
AudioManage#AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE
. Ten en cuenta que es posible que algunas apps de música no reaccionen correctamente a los comandos multimedia (consulta Cómo entregar comandos de contenido multimedia) mientras se reproduce el audio se quita el enfoque.