O Android Automotive considera a voz um componente crucial para
interações seguras no Google Drive e uma das maneiras mais seguras de
interagem com o Android Automotive OS enquanto dirige. Como resultado, expandimos a
APIs de assistente de voz do Android (incluindo VoiceInteractionSession
)
para permitir que assistentes de voz realizem tarefas para os usuários
que podem ser difíceis de realizar ao dirigir.
O recurso Tocar para ler permite que assistentes de voz leiam e respondam a mensagens de texto no
em nome do usuário, quando ele interage com as notificações de mensagem. Para fornecer
essa funcionalidade, é possível integrar um assistente de voz
CarVoiceInteractionSession
:
No Automotive, as notificações postadas na Central de notificações identificadas
como INBOX
ou INBOX_IN_GROUP
(por exemplo, mensagens SMS) incluem um
Botão Reproduzir. O usuário pode clicar em Reproduzir para que o
O assistente de voz lê a notificação em voz alta e, se quiser, pode responder por voz.
Figura 1. Notificação "Toque para ler" com o botão "Reproduzir".
Integrar com CarVoiceInteractionSession
As próximas seções descrevem como integrar um assistente de voz
CarVoiceInteractionSession
:
Suporte a interações por voz
Apps que oferecem serviços de interação por voz no carro precisam
se integram às interações de voz existentes do Android. Para saber mais, consulte Google Assistente para Android.
(exceto VoiceInteractionSession
). Embora todas as APIs de interação por voz
permanecem os mesmos elementos implementados em dispositivos móveis, CarVoiceInteractionSession
(descrito em Implementar CarVoiceInteractionSession), substitui
VoiceInteractionSession
Para ver mais informações, consulte estas páginas:
- VoiceInteractionSession (link em inglês)
- Implementação Seu próprio assistente
Implementar CarVoiceInteractionSession
CarVoiceInteractionSession
expõe APIs que podem ser usadas para permitir que assistentes de voz leiam mensagens de texto em voz alta e
responder a essas mensagens em nome do usuário.
A principal diferença entre o CarVoiceInteractionSession
e
VoiceInteractionSession
é que
CarVoiceInteractionSession
transmite a ação em onShow
para que o assistente de voz possa detectar o contexto da solicitação do usuário assim que
CarVoiceInteractionSession
inicia uma sessão. Parâmetros para onShow
para cada classe estão listados na tabela a seguir:
CarVoiceInteractionSession | VoiceInteractionSession (em inglês) |
---|---|
onShow usa estes três parâmetros:
|
onShow usa estes dois parâmetros:
|
Mudanças no Android 10
No Android 10 e versões mais recentes, a plataforma chama VoiceInteractionService.onGetSupportedVoiceActions
para detectar quais ações têm suporte. O assistente de voz substitui e
implementa VoiceInteractionService.onGetSupportedVoiceActions
,
conforme mostrado neste exemplo:
public class MyInteractionService extends VoiceInteractionService { private static final ListSUPPORTED_VOICE_ACTIONS = Arrays.asList( CarVoiceInteractionSession.VOICE_ACTION_READ_NOTIFICATION); @Override public Set onGetSupportedVoiceActions(@NonNull Set voiceActions) { Set result = new HashSet<>(voiceActions); result.retainAll(SUPPORTED_VOICE_ACTIONS); return result; } }
As ações válidas são descritas na tabela a seguir. Para obter detalhes sobre cada ação, consulte Diagramas de sequência.
Ação | Payload esperado | Ação de interação por voz esperada |
---|---|---|
VOICE_ACTION_READ_NOTIFICATION |
Leia as mensagens em voz alta para o usuário e depois dispare o botão "Marcar como lida" pendente quando as mensagens forem lidas. Opcionalmente, solicite o usuário para receber uma resposta. | |
VOICE_ACTION_REPLY_NOTIFICATION |
Parcelable com chave.KEY_NOTIFICATION
que mapeia para StatusBarNotification .Requer android.permission.BIND_NOTIFICATION_LISTENER_SERVICE . |
Peça que o usuário declare a mensagem de resposta, insira-a no
o RemoteInputReply da intent pendente e, em seguida, disparar o
com um intent pendente. |
VOICE_ACTION_HANDLE_EXCEPTION |
String com chave.KEY_EXCEPTION
que mapeia para ExceptionValue
(descrito em Valores de exceção).KEY_FALLBACK_ASSISTANT_ENABLED que mapeia para um valor booleano. Se o valor
é true , o assistente substituto que pode lidar com a solicitação do usuário foi
desativado. |
A ação esperada a ser tomada para a exceção é definida no documentação para a exceção. |
Valores de exceção
EXCEPTION_NOTIFICATION_LISTENER_PERMISSIONS_MISSING
indica ao assistente de voz que não tem a permissão Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE
e que ela precisa ser solicitada ao usuário.
Solicitar permissão do listener de notificações
Se o assistente de voz padrão não tiver o listener de notificações
permissão, o FallbackAssistant
da plataforma
(se ativado pelo fabricante do carro) pode ler a mensagem em voz alta antes de o assistente de voz ser
notificado para solicitar a permissão. Para determinar se o FallbackAssistant
está ativado e
leu a mensagem, o assistente de voz deve verificar
Valor booleano KEY_FALLBACK_ASSISTANT_ENABLED
no payload.
A plataforma recomenda que o assistente de voz adicione lógica de limitação de taxa
o número de vezes que a permissão é solicitada. Isso respeita o usuário que não
quiser conceder essa permissão ao assistente de voz e prefere a
FallbackAssistant
para ler mensagens de texto em voz alta. A solicitação de um
para pedir permissão sempre que ele pressionar Play em uma notificação de mensagem
pode ser uma experiência do usuário negativa. A plataforma não impõe limites de taxa.
em nome do assistente de voz.
Ao solicitar a permissão do ouvinte de notificações, o assistente de voz deve
use CarUxRestrictionsManager
para determinar se um usuário está estacionado ou dirigindo. Se o usuário estiver dirigindo, o assistente de voz
exibe uma notificação com instruções sobre como conceder a permissão. Ao fazer isso
ajuda (e lembra) o usuário de conceder a permissão quando for mais seguro.
Trabalhar com StatusBarNotification
StatusBarNotification
transmitido com a função de leitura e resposta.
os comandos de voz estão sempre em uma notificação de mensagens compatível com o carro, conforme descrito
em Notificar
usuários de mensagens. Embora algumas notificações possam não ter a opção "Resposta pendente"
todas elas terão intents pendentes Marcar como lida.
Para simplificar as interações com as notificações, use o NotificationPayloadHandler
,
que fornece métodos para extrair mensagens da notificação e gravar a
responder mensagens ao intent pendente apropriado da notificação. Após o
o assistente de voz ler a mensagem, ele precisa disparar a marcação
como intent de leitura.
Atender às condições prévias do recurso "Tocar para ler"
Apenas VoiceInteractionSession
da voz padrão
o Google Assistente é notificado quando um usuário aciona a ação de voz para ler e
responder às mensagens. Como mencionado acima, esse assistente de voz padrão também precisa
ter a permissão de listener de notificações.
Diagramas de sequência
Essas figuras mostram os fluxos lógicos de CarVoiceInteractionSession actions
:
Figura 2. Diagrama de sequência para VOICE_ACTION_READ_NOTE.
No caso da Figura 3, o aplicativo de limites de taxa nas solicitações de permissão é recomendado:
Figura 3. Diagrama de sequência de VOICE_ACTION_REPLY_NOTE.
Figura 4. Diagrama de sequência de VOICE_ACTION_HANDLE_EXCEPTION.
Ler o nome do app
Se quiser que seu assistente de voz leia o nome do aplicativo de mensagens em voz alta durante a leitura da mensagem (por exemplo, "Sam do Hangouts disse..."), crie uma função como a mostrada no exemplo de código a seguir para garantir que o assistente esteja lendo o nome correto:
@Nullable String getMessageApplicationName(Context context, StatusBarNotification statusBarNotification) { ApplicationInfo info = getApplicationInfo(context, statusBarNotification.getPackageName()); if (info == null) return null; Notification notification = statusBarNotification.getNotification(); // Sometimes system packages will post on behalf of other apps, so check this // field for a system app notification. if (isSystemApp(info) && notification.extras.containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME)) { return notification.extras.getString(Notification.EXTRA_SUBSTITUTE_APP_NAME); } else { PackageManager pm = context.getPackageManager(); return String.valueOf(pm.getApplicationLabel(info)); } } @Nullable ApplicationInfo getApplicationInfo(Context context, String packageName) { final PackageManager pm = context.getPackageManager(); ApplicationInfo info; try { info = pm.getApplicationInfo(packageName, 0); } catch (PackageManager.NameNotFoundException e) { return null; } return info; } boolean isSystemApp(ApplicationInfo info) { return (info.flags & ApplicationInfo.FLAG_SYSTEM) != 0; }