Asystent głosowy Dotknij, aby przeczytać

Android Automotive uważa głos za kluczowy element zapewniający bezpieczne interakcje i jeden z najbezpieczniejszych sposobów interakcji użytkowników z systemem operacyjnym Android Automotive podczas jazdy. W rezultacie rozszerzyliśmy interfejsy API asystentów głosowych Androida (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 czytanie i odpowiadanie na wiadomości tekstowe w imieniu użytkownika, gdy użytkownik wchodzi w interakcję z powiadomieniami o wiadomościach. Aby zapewnić taką funkcjonalność, możesz zintegrować asystenta głosowego z CarVoiceInteractionSession .

W branży motoryzacyjnej powiadomienia wysyłane do Centrum powiadomień identyfikowane jako INBOX lub INBOX_IN_GROUP (na przykład wiadomości SMS) zawierają przycisk Odtwórz . Użytkownik może kliknąć przycisk Odtwórz , aby wybrany asystent głosowy przeczytał powiadomienie na głos i opcjonalnie udzielił odpowiedzi głosowej.

Powiadomienie typu „dotknij, aby przeczytać”.

Rysunek 1. Powiadomienie typu „dotknij, aby przeczytać” z przyciskiem Odtwórz.

Zintegruj się z CarVoiceInteractionSession

W kolejnych sekcjach opisano sposób integracji asystenta głosowego z CarVoiceInteractionSession .

Obsługuj interakcje głosowe

Aplikacje zapewniające usługi interakcji głosowych w samochodzie muszą integrować się z istniejącymi interakcjami głosowymi w systemie Android. Aby dowiedzieć się więcej, zobacz Asystent Google dla Androida (z wyjątkiem VoiceInteractionSession ). Chociaż wszystkie elementy interfejsu API interakcji głosowej pozostają takie same, jak zaimplementowane na urządzeniach mobilnych, CarVoiceInteractionSession (opisane w Implementowanie CarVoiceInteractionSession ) zastępuje VoiceInteractionSession . Więcej informacji znajdziesz na tych stronach:

Zaimplementuj sesję CarVoiceInteractionSession

CarVoiceInteractionSession udostępnia interfejsy API, których można użyć, aby umożliwić asystentom głosowym czytanie na głos wiadomości tekstowych, a następnie odpowiadanie na te wiadomości w imieniu użytkownika.

Kluczowa różnica między klasami CarVoiceInteractionSession i VoiceInteractionSession polega na tym, że CarVoiceInteractionSession przekazuje akcję w onShow , dzięki czemu asystent głosowy może wykryć kontekst żądania użytkownika natychmiast po rozpoczęciu sesji CarVoiceInteractionSession . Parametry onShow dla każdej klasy są wymienione w poniższej tabeli:

Sesja interakcji CarVoice Sesja interakcji głosowej
onShow przyjmuje te trzy parametry:
  • args
  • showFlags
  • actions
onShow przyjmuje te dwa parametry:
  • args
  • showFlags

Zmiany w Androidzie 10

Począwszy od Androida 10, platforma wywołuje VoiceInteractionService.onGetSupportedVoiceActions , aby wykryć, które akcje są obsługiwane. Asystent głosowy zastępuje i implementuje VoiceInteractionService.onGetSupportedVoiceActions , jak pokazano w poniższym przykładzie:

public class MyInteractionService extends VoiceInteractionService {
    private static final List SUPPORTED_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;
   }
}

Prawidłowe działania opisano w poniższej tabeli. Aby uzyskać szczegółowe informacje na temat każdej akcji, zobacz Diagramy sekwencji .

Działanie Oczekiwany ładunek Oczekiwana akcja interakcji głosowej
VOICE_ACTION_READ_NOTIFICATION Czytaj wiadomości na głos użytkownikowi, a następnie uruchamiaj oczekującą intencję Oznacz jako przeczytane, gdy wiadomości zostaną pomyślnie odczytane. Opcjonalnie poproś użytkownika o odpowiedź.
VOICE_ACTION_REPLY_NOTIFICATION Możliwość wysyłki z kluczem.
KEY_NOTIFICATION , który jest mapowany na StatusBarNotification .
Wymaga android.permission.BIND_NOTIFICATION_LISTENER_SERVICE .
Poproś użytkownika o podanie wiadomości z odpowiedzią, wprowadź wiadomość z odpowiedzią do RemoteInputReply oczekującej intencji, a następnie uruchom oczekującą intencję.
VOICE_ACTION_HANDLE_EXCEPTION Sznurek z kluczem.
KEY_EXCEPTION , który odwzorowuje ExceptionValue (opisane w wartościach wyjątków ).
KEY_FALLBACK_ASSISTANT_ENABLED , który odwzorowuje wartość logiczną. Jeśli wartość ma wartość true , asystent zastępczy, który może obsłużyć żądanie użytkownika, został wyłączony.
Oczekiwane działanie, które należy podjąć w przypadku wyjątku, jest określone w dokumentacji wyjątku.

Wartości wyjątków

EXCEPTION_NOTIFICATION_LISTENER_PERMISSIONS_MISSING wskazuje asystentowi głosowemu, że brakuje mu uprawnienia Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE i aby uzyskać to pozwolenie od użytkownika.

Poproś o pozwolenie nasłuchiwania powiadomień

Jeśli domyślny asystent głosowy nie ma uprawnień słuchacza powiadomień, FallbackAssistant platformy (jeśli został włączony przez producenta samochodu) może przeczytać wiadomość na głos, zanim asystent głosowy otrzyma powiadomienie z prośbą o pozwolenie. Aby ustalić, czy FallbackAssistant jest włączony i przeczytał wiadomość, asystent głosowy powinien sprawdzić wartość logiczną KEY_FALLBACK_ASSISTANT_ENABLED w ładunku.

Platforma zaleca, aby asystent głosowy dodał logikę ograniczającą szybkość transmisji w zależności od liczby żądań tego pozwolenia. Takie postępowanie szanuje użytkownika, który nie chce przyznać asystentowi głosowemu tego uprawnienia i woli, aby FallbackAssistant czytał wiadomości tekstowe na głos. Monitowanie użytkownika o pozwolenie za każdym razem, gdy użytkownik naciśnie przycisk Odtwórz w powiadomieniu o wiadomości, może być niekorzystne dla użytkownika. Platforma nie narzuca limitów stawek w imieniu asystenta głosowego.

Prosząc o pozwolenie nasłuchiwania powiadomień, asystent głosowy powinien użyć CarUxRestrictionsManager w celu ustalenia, czy użytkownik zaparkował, czy prowadzi. Jeśli użytkownik prowadzi samochód, asystent głosowy wyświetla powiadomienie zawierające instrukcje dotyczące udzielenia zezwolenia. Pomaga to (i przypomina) użytkownikowi o udzieleniu pozwolenia, gdy jest to bezpieczniejsze.

Pracuj z StatusBarNotification

StatusBarNotification przekazywane za pomocą akcji głosowych Przeczytaj i Odpowiedz są zawsze zawarte w powiadomieniu o wiadomościach kompatybilnych z samochodem, zgodnie z opisem w sekcji Powiadamianie użytkowników o wiadomościach . Chociaż niektóre powiadomienia mogą nie mieć intencji „Oczekujące na odpowiedź”, wszystkie mają intencję „Oznacz jako przeczytane”.

Aby usprawnić interakcje z powiadomieniami, użyj NotificationPayloadHandler , który zapewnia metody wyodrębniania wiadomości z powiadomienia i zapisywania wiadomości odpowiedzi do odpowiedniego oczekującego celu powiadomienia. Gdy asystent głosowy odczyta wiadomość, musi uruchomić intencję Oznacz jako przeczytaną.

Spełnij warunki wstępne dotyczące funkcji „Dotknij, aby przeczytać”.

Gdy użytkownik uruchomi akcję głosową, aby przeczytać wiadomości i odpowiedzieć na nie, powiadamiana jest tylko VoiceInteractionSession domyślnego asystenta głosowego. Jak wspomniano powyżej, ten domyślny asystent głosowy musi również mieć uprawnienia słuchacza powiadomień.

Diagramy sekwencji

Liczby te przedstawiają przebieg logiczny CarVoiceInteractionSession actions :

VOICE_ACTION_READ_NOTIFICATION

Rysunek 2. Diagram sekwencji dla VOICE_ACTION_READ_NOTIFICATION.

W przypadku rysunku 3 zaleca się stosowanie limitów szybkości na żądaniach uprawnień:

VOICE_ACTION_REPLY_NOTIFICATION

Rysunek 3. Diagram sekwencji dla VOICE_ACTION_REPLY_NOTIFICATION.

VOICE_ACTION_HANDLE_EXCEPTION

Rysunek 4. Diagram sekwencji dla VOICE_ACTION_HANDLE_EXCEPTION.

Przeczytaj nazwę aplikacji

Jeśli chcesz, aby asystent głosowy czytał na głos nazwę aplikacji do przesyłania wiadomości podczas odczytywania wiadomości (na przykład „Sam z Hangouts powiedział…”), utwórz funkcję podobną do tej pokazanej w poniższym przykładzie kodu, aby mieć pewność, że asystent czyta wiadomość poprawna nazwa:

@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;
}