O Android Automotive considera a voz um componente crucial na habilitação de interações de direção segura e uma das formas mais seguras para os usuários interagirem com o sistema operacional Android Automotive enquanto dirigem. Como resultado, as APIs existentes do Android Voice Assistant (incluindo VoiceInteractionSession
) foram expandidas para permitir que os assistentes de voz executem tarefas para os usuários que podem ser difíceis de realizar durante a condução.
O Tap-to-Read permite que os assistentes de voz leiam e respondam a mensagens de texto em nome desse usuário, quando o usuário interage com as notificações de mensagem. Para fornecer essa funcionalidade, você pode integrar um assistente de voz com CarVoiceInteractionSession
.
No setor automotivo, as notificações postadas na Central de Notificações identificadas como notificações INBOX ou INBOX_IN_GROUP (por exemplo, mensagens SMS) incluirão um botão de ação Reproduzir. Este botão permite ao usuário fazer com que a notificação seja lida em voz alta pelo VIA selecionado e, opcionalmente, responder por voz.
Figura 1. Notificação de toque para ler
Integre com CarVoiceInteractionSession
1. Suporta VoiceInteractions
Os aplicativos que fornecem serviços de interação de voz do carro devem se integrar às interações de voz Android existentes (com exceção de VoiceInteractionSession
). Embora todos os outros componentes da API de interação por voz permaneçam os mesmos implementados em dispositivos móveis, CarVoiceInteractionSession
(descrito abaixo) substitui VoiceInteractionSession
. Para mais informações, consulte estes artigos:
2. Implemente CarVoiceInteractionSession
CarVoiceInteractionSession
expõe APIs que podem ser usadas para permitir que assistentes de voz leiam em voz alta e respondam a mensagens de texto em nome do usuário.
Ao comparar CarVoiceInteractionSession
e VoiceInteractionSession
, a principal diferença é que CarVoiceInteractionSession
passa a ação em onShow
para que o assistente de voz possa detectar o contexto da solicitação do usuário assim que CarVoiceInteractionSession
iniciar uma sessão.
CarVoiceInteractionSession | VoiceInteractionSession |
---|---|
onShow recebe estes três parâmetros:
| onShow recebe esses dois parâmetros:
|
Mudanças no Android 10
A partir do Android 10, a plataforma chama VoiceInteractionService.onGetSupportedVoiceActions
para detectar quais ações são compatíveis. O assistente de voz substitui e implementa VoiceInteractionService.onGetSupportedVoiceActions
, conforme mostrado abaixo:
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 abaixo. Para obter detalhes sobre cada ação, consulte os Diagramas de Sequência abaixo.
Ação | Carga útil esperada | Ação de interação de voz esperada |
---|---|---|
VOICE_ACTION_READ_NOTIFICATION | Leia as mensagens em voz alta para o usuário e, em seguida, dispare a intenção Marcar como lida pendente quando as mensagens forem lidas com êxito. Opcionalmente, solicite uma resposta do usuário. | |
VOICE_ACTION_REPLY_NOTIFICATION | Parcelável com chave.KEY_NOTIFICATION que mapeia para um StatusBarNotification .Requer android.permission.BIND_NOTIFICATION_LISTENER_SERVICE | Solicite ao usuário que declare a mensagem de resposta, insira a mensagem de resposta no RemoteInputReply da intenção pendente e acione a intenção pendente. |
VOICE_ACTION_HANDLE_EXCEPTION | Corda com chave. KEY_EXCEPTION que mapeia para um ExceptionValue (descrito abaixo). KEY_FALLBACK_ASSISTANT_ENABLED que mapeia para um valor booleano. Se o valor for true, o Fallback Assistant que pode manipular a solicitação do usuário foi desabilitado. | A ação esperada a ser tomada para a exceção será definida na documentação da exceção. |
ExceptionValue
EXCEPTION_NOTIFICATION_LISTENER_PERMISSIONS_MISSING
indica ao assistente de voz que está faltando a permissão Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE
e para obter essa permissão do usuário.
3. Solicitar permissão de ouvinte de notificação
Se o assistente de voz padrão não tiver permissões de ouvinte de notificação, o FallbackAssistant da plataforma (se habilitado pelo fabricante do carro) poderá ler a mensagem em voz alta antes que o assistente de voz seja notificado para solicitar a permissão. Para determinar se o FallbackAssistant está ativado e, portanto, leu a mensagem, o assistente de voz deve verificar o valor booleano KEY_FALLBACK_ASSISTANT_ENABLED
na carga útil.
A plataforma recomenda que o assistente de voz adicione uma lógica de limitação de taxa quanto ao número de vezes que essa permissão é solicitada. Isso respeita o usuário que não deseja conceder essa permissão ao assistente de voz e prefere que o FallbackAssistant
leia em voz alta as mensagens de texto. Solicitar permissão a esse usuário sempre que ele pressionar Reproduzir na notificação de mensagem pode levar a uma experiência negativa do usuário. A plataforma não impõe limites de taxa em nome do assistente de voz.
Ao solicitar a permissão do Notification Listener, o assistente de voz deve usar 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 que fornece instruções sobre como conceder a permissão. Isso ajuda (e lembra) o usuário a conceder a permissão quando for mais seguro.
4. Trabalhe com StatusBarNotification
StatusBarNotifications
transmitidas com as ações de voz Read e Reply estão sempre em uma notificação de mensagem compatível com carro, conforme descrito em Notificar usuários sobre mensagens . Embora algumas notificações possam não ter a intenção de resposta pendente, todas elas têm intenções pendentes de marcar como lidas.
Para simplificar as interações com notificações, use NotificationPayloadHandler , que fornece métodos para extrair mensagens da notificação e gravar as mensagens de resposta na intenção pendente apropriada da notificação. Depois que o assistente de voz lê a mensagem, o assistente de voz deve disparar a intenção Mark as Read.
5. Satisfaça as pré-condições de tocar para ler
Somente a VoiceInteractionSession
do assistente de voz padrão é notificada quando um usuário aciona a ação de voz para ler e responder às mensagens. Conforme mencionado acima, este assistente de voz padrão também deve ter a permissão Ouvinte de Notificação.
Diagramas de Sequência
Essas figuras exibem os fluxos lógicos das CarVoiceInteractionSession actions
.
Figura 2. Diagrama de sequência para VOICE_ACTION_READ_NOTIFICATION
No caso da Figura 3 abaixo, recomenda-se a aplicação de limites de taxa nas solicitações de permissão.
Figura 3. Diagrama de sequência para VOICE_ACTION_REPLY_NOTIFICATION
Figura 4. Diagrama de sequência para VOICE_ACTION_HANDLE_EXCEPTION
Dicas e truques
Lendo o nome de um aplicativo
Se o seu assistente de voz quiser ler em voz alta o nome do aplicativo de mensagens durante a leitura da mensagem (ou seja, "Sam do Hangouts disse..."), você deve criar uma função como a mostrada abaixo para garantir que está 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 applications, so check this // field for a system application 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; }