Android Automotive uważa głos za kluczowy element interakcji bezpiecznych dla kierowcy i jeden z najbezpieczniejszych sposobów na interakcję z Androidem Automotive podczas jazdy. W rezultacie rozszerzyliśmy interfejsy API Asystenta głosowego na Androidzie (w tym VoiceInteractionSession
), aby umożliwić asystentom głosowym wykonywanie zadań dla użytkowników, które mogą być trudne do wykonania podczas jazdy.
Funkcja „dotknij, aby przeczytać” umożliwia asystentom głosowym odczytywanie i odpowiadanie na wiadomości tekstowe w imieniu użytkownika, gdy ten będzie wchodzić w interakcję z powiadomieniami o wiadomościach. Aby udostępnić tę funkcję, możesz zintegrować asystenta głosowego z CarVoiceInteractionSession
.
W systemie samochodowym powiadomienia wyświetlane w Centrum powiadomień o typie INBOX
lub INBOX_IN_GROUP
(np. SMS-y) zawierają przycisk Odtwórz. Użytkownik może kliknąć Odtwórz, aby wybrany asystent głosowy odczytał powiadomienie na głos, a opcjonalnie – aby na nie odpowiedzieć głosowo.
Rysunek 1. Powiadomienie „Dotknij, aby przeczytać” z przyciskiem Odtwórz.
Integracja z CarVoiceInteractionSession
W kolejnych sekcjach znajdziesz opis integracji asystenta głosowego z CarVoiceInteractionSession
.
Obsługa interakcji głosowych
Aplikacje, które zapewniają usługi interakcji głosowej w samochodzie, muszą
być zintegrowane z dotychczasowymi interakcjami głosowymi w Androidzie. Więcej informacji znajdziesz w artykule Asystent Google na Androida (z wyjątkiem VoiceInteractionSession
). Wszystkie elementy interfejsu API interakcji głosowej pozostają takie same jak na urządzeniach mobilnych, ale CarVoiceInteractionSession
(opisany w artykule Wdrażanie interfejsu CarVoiceInteractionSession) zastępuje VoiceInteractionSession
. Więcej informacji znajdziesz na tych stronach:
Zaimplementuj CarVoiceInteractionSession
CarVoiceInteractionSession
pozwala na korzystanie z interfejsów API, które umożliwiają asystentom głosowym odczytywanie na głos wiadomości tekstowych i odpowiadanie na nie w imieniu użytkownika.
Główna różnica między klasami CarVoiceInteractionSession
i VoiceInteractionSession
polega na tym, że CarVoiceInteractionSession
przekazuje działanie w onShow
, dzięki czemu asystent głosowy może wykryć kontekst żądania użytkownika, gdy tylko CarVoiceInteractionSession
rozpocznie sesję. Parametry onShow
dla poszczególnych klas znajdziesz w tabeli poniżej:
CarVoiceInteractionSession | VoiceInteractionSession |
---|---|
onShow przyjmuje 3 parametry:
|
onShow przyjmuje 2parametry:
|
Zmiany w Androidzie 10
Od Androida 10 platforma wywołuje funkcję VoiceInteractionService.onGetSupportedVoiceActions
, aby wykryć, które działania są obsługiwane. Asystent głosowy zastępuje i wdraża VoiceInteractionService.onGetSupportedVoiceActions
, jak w tym przykładzie:
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; } }
Dozwolone działania są opisane w tabeli poniżej. Szczegółowe informacje o każdym działaniu znajdziesz w diagramach sekwencji.
Działanie | Oczekiwany ładunek | Oczekiwane działanie po interakcji głosowej |
---|---|---|
VOICE_ACTION_READ_NOTIFICATION |
Czytaj na głos wiadomości użytkownikowi, a potem wywołaj działanie „Oznacz jako przeczytane” po odczytaniu wiadomości. Opcjonalnie poproś użytkownika o odpowiedź. | |
VOICE_ACTION_REPLY_NOTIFICATION |
Parcelable z kluczem.KEY_NOTIFICATION
zmapowany na StatusBarNotification .Wymaga android.permission.BIND_NOTIFICATION_LISTENER_SERVICE . |
Poproś użytkownika o podanie odpowiedzi, wpisz ją w polu RemoteInputReply zapytania oczekującego, a potem uruchom to zapytanie. |
VOICE_ACTION_HANDLE_EXCEPTION |
Ciąg znaków z kluczem.KEY_EXCEPTION
mapuje się na ExceptionValue
(opisane w sekcji Wartości wyjątków).KEY_FALLBACK_ASSISTANT_ENABLED , która jest mapowana na wartość logiczną. Jeśli wartość to true , pomocnik awaryjny, który może obsłużyć żądanie użytkownika, został wyłączony. |
Oczekiwane działanie w przypadku wyjątku jest określone w dokumentacji dotyczącej tego wyjątku. |
Wartości wyjątku
EXCEPTION_NOTIFICATION_LISTENER_PERMISSIONS_MISSING
wskazuje asystentowi głosowemu, że brakuje mu uprawnienia Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE
i że musi uzyskać to uprawnienie od użytkownika.
Prośba o zgodę na odbiór powiadomień
Jeśli domyślny asystent głosowy nie ma uprawnień do odbioru powiadomień, platforma FallbackAssistant
(jeśli została włączona przez producenta samochodu) może odczytać wiadomość na głos, zanim asystent głosowy poprosi o uprawnienia. Aby ustalić, czy FallbackAssistant
jest włączona i czy przeczytała wiadomość, asystent głosowy powinien sprawdzić wartość logiczną KEY_FALLBACK_ASSISTANT_ENABLED
w pliku danych.
Platforma zaleca, aby asystent głosowy dodał logikę ograniczającą częstotliwość żądania tego uprawnienia. Dzięki temu użytkownik, który nie chce przyznać Asystentowi głosowemu tego uprawnienia i woli, aby FallbackAssistant
odczytywał na głos wiadomości tekstowe, nie będzie miał tego uprawnienia. Proszenie użytkownika o pozwolenie za każdym razem, gdy naciśnie Odtwórz w powiadomieniu o wiadomości, może negatywnie wpłynąć na wrażenia użytkownika. Platforma nie nakłada limitów szybkości w imieniu asystenta głosowego.
Podczas prośby o dostęp do powiadomień asystent głosowy powinien używać CarUxRestrictionsManager
, aby określić, czy użytkownik jest zaparkowany, czy prowadzi pojazd. Jeśli użytkownik prowadzi pojazd, asystent głosowy wyświetli powiadomienie z instrukcjami udzielenia uprawnienia. Pomoże to użytkownikowi przyznać uprawnienia, gdy będzie to bezpieczne (i przypomni mu o tym).
Praca z klasą StatusBarNotification
Wartość StatusBarNotification
przekazana w ramach działań głosowych „Read” i „Reply” jest zawsze wyświetlana w powiadomieniu o wiadomości zgodnym z wymaganiami dotyczącymi samochodów, zgodnie z opisem w sekcji Powiadomienia użytkowników o wiadomościach. Niektóre powiadomienia mogą nie mieć intencji Odpowiedz, ale wszystkie mają oznaczenie jako przeczytane.
Aby usprawnić interakcje z powiadomieniami, użyj interfejsu NotificationPayloadHandler
, który zawiera metody wyodrębniania wiadomości z powiadomienia i tworzenia wiadomości odpowiedzi do odpowiedniej oczekującej intencji powiadomienia. Gdy asystent głosowy odczyta wiadomość, musi wywołać intent Oznaczyć jako przeczytane.
Warunki wstępne funkcji Dotknij, aby przeczytać
Gdy użytkownik uruchamia działanie głosowe, aby odczytać i odpwiedzieć na wiadomości, tylko VoiceInteractionSession
domyślnego asystenta głosowego jest powiadamiany. Jak już wspomnieliśmy, ten domyślny asystent głosowy musi też mieć uprawnienia do odbierania powiadomień.
Diagramy sekwencji
Te rysunki przedstawiają przepływy logiczne w programie CarVoiceInteractionSession actions
:
Rysunek 2. Schemat sekwencji dla VOICE_ACTION_READ_NOTIFICATION.
W przypadku rysunku 3 zaleca się zastosowanie limitów częstotliwości żądań uprawnień:
Rysunek 3. Schemat sekwencji dla VOICE_ACTION_REPLY_NOTIFICATION.
Rysunek 4. Schemat sekwencji dla VOICE_ACTION_HANDLE_EXCEPTION.
Czytaj nazwę aplikacji
Jeśli chcesz, aby asystent głosowy odczytywał na głos nazwę aplikacji do obsługi wiadomości (np. „Sam z Hangouts powiedział…”), utwórz funkcję podobną do tej w następującym przykładzie kodu, aby upewnić się, że asystent odczytuje prawidłową nazwę:
@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; }