Aby wdrożyć aplikację do interakcji głosowej (VIA):
- Utwórz szkielet VIA.
- (opcjonalnie) Wdrożenie procesu konfiguracji lub logowania.
- (opcjonalnie) Wprowadź ekran Ustawienia.
- W pliku manifestu zadeklaruj wymagane uprawnienia.
- Zaimplementuj interfejs głosowy.
- Wdrożyć rozpoznawanie głosu (musi zawierać implementację interfejsu RecognitionService API).
- Wdrożyć wypowiedź (opcjonalnie możesz zaimplementować interfejs TextToSpeech API).
- Wdrożyć realizację poleceń. Zobacz te treści w sekcji Realizowanie poleceń.
W następnych sekcjach znajdziesz instrukcje wykonywania poszczególnych kroków.
Tworzenie szkieletu VIA
Pliki manifestu
Aplikacja jest wykrywana jako aplikacja z interakcją głosową, gdy w pliku manifestu znajduje się:
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>
W tym przykładzie:
- VIA musi udostępniać usługę, która rozszerza
VoiceInteractionService
, z filtrem intencji dla działaniaVoiceInteractionService.SERVICE_INTERFACE ("android.service.voice.VoiceInteractionService")
. - Ta usługa musi mieć uprawnienie
BIND_VOICE_INTERACTION
do podpisywania systemowego. - Ta usługa powinna zawierać plik metadanych
android.voice_interaction
, który zawiera: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" />
Szczegółowe informacje o każdym polu znajdziesz w artykule R.styleable#VoiceInteractionService
.
Ponieważ wszystkie interfejsy VIA są też usługami rozpoznawania głosu, w pliku manifestu musisz też uwzględnić:
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>
Usługi rozpoznawania głosu wymagają też tych metadanych:
res/xml/recognition_service.xml
<recognition-service xmlns:android="http://schemas.android.com/apk/res/android" android:settingsActivity="com.example.MyRecognizerSettingsActivity" />
VoiceInteractionService, VoiceInteractionSessionService i VoiceInteractionSession
Na poniższym diagramie przedstawiono cykl życia tych elementów:
Rysunek 1. Cykle życia
Jak już wspomnieliśmy, VoiceInteractionService
to punkt wejścia do VIA. Główne obowiązki tej usługi to:
- Inicjowanie procesów, które powinny być uruchomione tak długo, jak długo ten VIA jest aktywny. Na przykład wykrywanie słów-kluczy.
- Raporty obsługiwanych poleceń głosowych (patrz Asystent głosowy – kliknij, aby przeczytać).
- Uruchamianie sesji interakcji głosowej na ekranie blokady (klawiatura ekranowa).
W najprostszej postaci implementacja usługi VoiceInteractionService wygląda tak:
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; } ... }
Wdrożenie VoiceInteractionService#onGetSupportedVoiceActions()
jest wymagane do obsługi funkcji czytania przez Asystenta głosowego.
System używa usługi VoiceInteractionSessionService do tworzenia VoiceInteractionSession i interakcji z nią. Ma tylko jedno zadanie: uruchamiać nowe sesje na żądanie.
public class MyVoiceInteractionSessionService extends VoiceInteractionSessionService { @Override public VoiceInteractionSession onNewSession(Bundle args) { return new MyVoiceInteractionSession(this); } }
W końcu VoiceInteractionSession to miejsce, w którym wykonywana jest większość pracy. Jedno wystąpienie sesji może być używane wielokrotnie do przeprowadzania wielu interakcji z użytkownikiem. W AAOS istnieje pomocnicza funkcja CarVoiceInteractionSession
, która pomaga w wdrażaniu niektórych funkcji związanych z samochodami.
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
ma duży zestaw metod wywołania zwrotnego, które są opisane w następnych sekcjach. Pełną listę znajdziesz w dokumentacji VoiceInteractionSession
.
Wdrożenie procesu konfiguracji lub logowania
Konfiguracja i logowanie mogą się odbywać w taki sposób:
- Podczas konfiguracji urządzenia (kreator konfiguracji).
- Podczas przełączania usług interakcji głosowej (Ustawienia).
- Po pierwszym uruchomieniu aplikacji, gdy zostanie wybrana.
Szczegółowe informacje o zalecanym interfejsie użytkownika i wskazówkach wizualnych znajdziesz w artykule Wstępnie zainstalowane asystenty: wskazówki dotyczące UX.
Konfiguracja podczas przełączania usługi głosowej
Użytkownik może wybrać nieprawidłowo skonfigurowaną usługę VIA. Może się tak zdarzyć, jeśli:
- Użytkownik całkowicie pominął kreatora konfiguracji lub pomija krok konfiguracji interakcji głosowej.
- Użytkownik wybrał inny adres VIA niż skonfigurowany podczas konfiguracji urządzenia.
W każdym przypadku VoiceInteractionService
ma kilka sposobów na zachęcenie użytkownika do ukończenia konfiguracji:
- Powiadomienie z przypomnieniem.
- Automatyczna odpowiedź głosowa, gdy użytkownik próbuje z niej skorzystać.
Uwaga: zdecydowanie odradzamy prezentowanie procesu konfiguracji VIA bez wyraźnej prośby użytkownika. Oznacza to, że VIA nie powinny automatycznie wyświetlać treści na HU podczas uruchamiania urządzenia ani po przełączeniu użytkownika lub odblokowaniu.
Powiadomienie o przypomnieniu
Powiadomienie z przypomnieniem to dyskretny sposób na wskazanie użytkownikowi, że musi on skonfigurować urządzenie, oraz umożliwienie mu przejścia do procesu konfiguracji.
Rysunek 2. Powiadomienie o przypomnieniu
Oto jak to działa:
Rysunek 3. Proces przypomnienia o powiadomieniu
Odpowiedź głosowa
Jest to najprostszy do wdrożenia proces, który inicjuje wypowiedź w VoiceInteractionSession#onShow()
, wyjaśnia użytkownikowi, co należy zrobić, a następnie pyta (jeśli konfiguracja jest dozwolona zgodnie ze stanem ograniczenia interfejsu użytkownika), czy chce rozpocząć proces konfiguracji. Jeśli konfiguracja nie jest możliwa w danym momencie, wyjaśnij tę sytuację.
Konfiguracja podczas pierwszego użycia
Użytkownik może zawsze uruchomić nieprawidłowo skonfigurowaną usługę VIA. W takich przypadkach:
- Poinformuj użytkownika o tej sytuacji (np. „Aby prawidłowo działać, muszę wykonać kilka czynności…”).
- Jeśli mechanizm ograniczeń interfejsu użytkownika na to pozwala (patrz UX_RESTRICTIONS_NO_SETUP), zapytaj użytkownika, czy chce rozpocząć proces konfiguracji, a następnie otwórz ekran ustawień VIA.
- W przeciwnym razie (np. jeśli użytkownik prowadzi samochód), wyświetl powiadomienie, aby użytkownik kliknął opcję, gdy będzie to bezpieczne.
Tworzenie ekranów konfiguracji interakcji głosowej
Ekrany konfiguracji i logowania powinny być tworzone jako zwykłe działania. Zapoznaj się ze wskazówkami dotyczącymi UX i wizualizacji w ramach tworzenia interfejsu użytkownika w artykule Wstępnie zainstalowani asystenci: wskazówki dotyczące UX.
Ogólne wskazówki:
- Interfejs VIA powinien umożliwiać użytkownikom przerwanie i wznowienie konfiguracji w dowolnym momencie.
- Konfiguracja nie powinna być dozwolona, jeśli obowiązuje ograniczenie
UX_RESTRICTIONS_NO_SETUP
. Szczegółowe informacje znajdziesz w wytycznych dotyczących rozpraszania uwagi kierowcy. - Ekrany konfiguracji powinny być zgodne z systemem projektowania dla danego pojazdu. Ogólny układ ekranu, ikony, kolory i inne aspekty powinny być spójne z resztą interfejsu. Więcej informacji znajdziesz w sekcji Personalizacja.
Implementacja ekranu ustawień
Rysunek 4. Integracja ustawień
Ekrany ustawień to zwykłe czynności na Androidzie. Jeśli są one zaimplementowane, ich punkt wejścia musi zostać zadeklarowany w pliku res/xml/interaction_service.xml
w ramach pliku manifestu VIA (patrz Plik manifestu).
Sekcja Ustawienia to dobre miejsce na kontynuowanie konfiguracji i logowania (jeśli użytkownik nie dokończył tej czynności) lub na oferowanie opcji wylogowania lub przełączania użytkowników w razie potrzeby. Podobnie jak w przypadku opisanych wyżej ekranów konfiguracji te ekrany powinny:
- Dodaj opcję wyjścia na poprzedni ekran w grupie ekranów (np. do ustawień samochodu).
- nie mogą być używane podczas jazdy. Szczegółowe informacje znajdziesz w wytycznych dotyczących rozpraszania uwagi kierowcy.
- Dopasuj system projektowania pojazdu. Więcej informacji znajdziesz w artykule Dostosowywanie.
Zadeklaruj wymagane uprawnienia w pliku manifestu.
Uprawnienia wymagane przez VIA można podzielić na 3 kategorie:
- Uprawnienia do podpisu systemowego Te uprawnienia są przyznawane tylko wstępnie zainstalowanym plikom APK podpisanym przez system. Użytkownicy nie mogą przyznawać tych uprawnień. Mogą to zrobić tylko producenci OEM podczas tworzenia obrazów systemu. Więcej informacji o przyznawaniu uprawnień systemowych znajdziesz w artykule Przyznawanie uprawnień systemowych.
- Niebezpieczne uprawnienia Są to uprawnienia, które użytkownik musi przyznać za pomocą okna PermissionsController. Producenci OEM mogą z góry przyznać niektóre z tych uprawnień domyślnej usłudze VoiceInteractionService. Ponieważ jednak te domyślne ustawienia mogą się różnić w zależności od urządzenia, aplikacje powinny mieć możliwość żądania tych uprawnień w razie potrzeby.
- Inne uprawnienia Są to wszystkie inne uprawnienia, które nie wymagają interwencji użytkownika. Te uprawnienia są przyznawane automatycznie przez system.
Z tego powodu w następującej sekcji skupiamy się tylko na prośbach o uprawnienia niebezpieczne. Uprawnienia powinny być wymagane tylko wtedy, gdy użytkownik znajduje się na ekranie logowania lub ustawień.
Jeśli aplikacja nie ma uprawnień potrzebnych do działania, zalecany sposób postępowania to użycie wypowiedzi głosowej, aby wyjaśnić użytkownikowi sytuację, oraz powiadomienia, które umożliwi użytkownikowi powrót do ekranów ustawień VIA. Więcej informacji znajdziesz w sekcji 1. Powiadomienie o przypomnieniu.
Prośba o uprawnienia na ekranie ustawień
Uprawnienia niebezpieczne są wymagane za pomocą zwykłej metody ActivityCompat#requestPermission()
(lub równoważnej). Szczegółowe informacje o tym, jak poprosić o przyznanie uprawnień, znajdziesz w artykule Poproś o przyznanie uprawnień aplikacji.
Rysunek 5. Prośba o uprawnienia
Zgoda na odbiór powiadomień
Aby wdrożyć proces TTR, interfejs VIA musi być oznaczony jako odbiorca powiadomień. Nie jest to uprawnienie sensu stricto, ale konfiguracja, która pozwala systemowi wysyłać powiadomienia do zarejestrowanych słuchaczy. Aby dowiedzieć się, czy aplikacja ma dostęp do tych informacji, aplikacje mogą:
- (Opcjonalnie) Sprawdź z wyprzedzeniem, czy są odbiorki powiadomień, używając funkcji
CarAssistUtils#assistantIsNotificationListener()
. Możesz to zrobić na przykład podczas konfiguracji. - (Wymagany) Reakcja na obsługę
CarVoiceInteractionSession#onShow()
z działaniemVOICE_ACTION_HANDLE_EXCEPTION
i wyjątkiemEXCEPTION_NOTIFICATION_LISTENER_PERMISSIONS_MISSING
.
Jeśli dostęp nie został przyznany z góry, VIA powinna skierować użytkownika do sekcji Uprawnienia dotyczące powiadomień w Ustawieniach samochodu, używając kombinacji poleceń głosowych i powiadomień. Aby otworzyć odpowiednią sekcję w aplikacji Ustawienia, możesz użyć tego kodu:
private void requestNotificationListenerAccess() { Intent intent = new Intent(Settings .ACTION_NOTIFICATION_LISTENER_SETTINGS); intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName()); startActivity(intent); }
Wdrożenie interfejsu głosowego
Gdy VoiceInteractionSession
otrzyma onShow()
, może wyświetlić interfejs głosowy. Wskazówki dotyczące wrażeń wizualnych i interfejsu użytkownika związane z wdrażaniem płytki głosowej znajdziesz w artykule Wstępnie zainstalowane Asystenty: wskazówki dotyczące UX.
Rysunek 6. Wyświetlanie płytki głosowej
Istnieją 2 sposoby implementacji tego interfejsu:
- Zastąpić
VoiceInteractionSession#onCreateContentView()
- Uruchamianie aktywności przy użyciu dodatku
VoiceInteractionSession#startAssistantActivity()
Używanie metody onCreateContentView()
Jest to domyślny sposób wyświetlania płytki głosowej. Klasa bazowa VoiceInteractionSession
tworzy okno i zarządza jego cyklem życia przez cały czas trwania sesji głosowej. Aplikacje muszą zastąpić VoiceInteractionSession#onCreateContentView()
i zwracać widok dołączony do tego okna, gdy tylko zostanie utworzona sesja. Ten widok powinien być początkowo niewidoczny. Gdy rozpocznie się interakcja głosowa, ten widok powinien stać się widoczny na ekranie VoiceInteractionSession#onShow()
, a potem znów niewidoczny na ekranie 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); } … }
Podczas korzystania z tej metody warto dostosować VoiceInteractionSession#onComputeInsets()
, aby uwzględnić zasłonięte obszary interfejsu.
Używanie startAssistantActivity()
W tym przypadku VoiceInteractionSession
deleguje obsługę interfejsu Voiceplate do zwykłej aktywności. Gdy ta opcja jest używana, implementacja VoiceInteractionSession
musi wyłączyć tworzenie domyślnego okna treści (patrz Używanie metody onCreateContentView()) w wywołaniu onPrepareShow()
. O godz. VoiceInteractionSession#onShow()
sesja rozpocznie aktywność głosową za pomocą funkcji VoiceInteractionSession#startAssistantActivity()
. Ta metoda inicjuje interfejs z odpowiednimi ustawieniami okna i flagami aktywności.
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); } … }
Aby utrzymać komunikację między tą aktywnością a VoiceInteractionSession
, może być wymagany zestaw wewnętrznych intencji lub usług. Na przykład, gdy wywołana zostanie metoda VoiceInteractionSession#onHide()
, sesja musi mieć możliwość przekazania tego żądania do aktywności.
Ważne. W przypadku pojazdów tylko specjalnie oznaczone aktywności lub aktywności wymienione na liście dozwolonych przez UXR mogą być wyświetlane podczas jazdy. Dotyczy to również aktywności rozpoczętych za pomocą VoiceInteractionSession#startAssistantActivity()
. Pamiętaj, aby albo dodać adnotację do aktywności za pomocą klucza <meta-data
android:name="distractionOptimized" android:value="true"/>
, albo uwzględnić tę aktywność w kluczu systemActivityWhitelist
pliku /packages/services/Car/service/res/values/config.xml
. Więcej informacji znajdziesz w wytycznych dotyczących rozpraszania uwagi kierowcy.
Wdrożenie rozpoznawania głosu
Z tej sekcji dowiesz się, jak wdrażać rozpoznawanie głosu za pomocą wykrywania i rozpoznawania słów kluczowych. Słowo kluczowe to słowo, które uruchamia nowe zapytanie lub działanie głosowe. na przykład „OK Google” lub „Hej Google”.
Wykrywanie słów-kluczy przez DSP
Android zapewnia dostęp do zawsze włączonego wykrywania słów-kluczy na poziomie DSP za pomocą AlwaysOnHotwordDetector
.
sposób implementacji wykrywania słów-kluczy przy niskim wykorzystaniu procesora. Korzystanie z tej funkcji jest podzielone na 2 części:
- Tworzenie instancji
AlwaysOnHotwordDetector
. - Rejestrowanie modelu dźwiękowego wykrywania słów-kluczy.
Implementacja usługi VoiceInteractionService może utworzyć detektor słów kluczowych za pomocą funkcji VoiceInteractionService#createAlwaysOnHotwordDetector()
, przekazując frazę kluczową i lokalizację, których chce użyć do wykrywania. W efekcie aplikacja otrzymuje wywołanie zwrotne onAvailabilityChanged()
z jedną z tych wartości:
STATE_HARDWARE_UNAVAILABLE
. Urządzenie nie obsługuje funkcji DSP. W tym przypadku używane jest wykrywanie słów-kluczy w oprogramowaniu.STATE_HARDWARE_UNSUPPORTED
. Obsługa DSP nie jest ogólnie dostępna, ale DSP nie obsługuje danej kombinacji słów kluczowych i lokalizacji. Aplikacja może używać wykrywania słów-kluczy w oprogramowaniu.STATE_HARDWARE_ENROLLED
. Wykrywanie słów-kluczy jest gotowe i może zostać uruchomione przez wywołanie metodystartRecognition()
.STATE_HARDWARE_UNENROLLED
. Model dźwiękowy dla żądanej frazy kluczowej jest niedostępny, ale można go zarejestrować.
Rejestrowanie modeli dźwiękowych wykrywania słów-kluczy można wykonać za pomocą IVoiceInteractionManagerService#updateKeyphraseSoundModel()
.
W danym momencie w systemie może być zarejestrowanych wiele modeli, ale tylko jeden model jest powiązany z AlwaysOnHotwordDetector
.
Funkcja wykrywania słów-kluczy w usługach DSP może nie być dostępna na niektórych urządzeniach. Deweloperzy VIA powinni sprawdzić możliwości sprzętowe za pomocą metody getDspModuleProperties()
. Przykładowy kod pokazujący, jak rejestrować modele dźwiękowe, znajdziesz w artykule VoiceEnrollment/src/com/android/test/voiceenrollment/EnrollmentUtil.java
.
Informacje o jednoczesnym rozpoznawaniu słów kluczowych znajdziesz w sekcji Jednoczesne przechwytywanie.
Wykrywanie słów-kluczy przez oprogramowanie
Jak już wspomnieliśmy, wykrywanie słów kluczowych DSP może nie być dostępne na niektórych urządzeniach (np. emulator Androida nie zapewnia emulacji DSP). W takim przypadku jedyną alternatywą jest rozpoznawanie głosu za pomocą oprogramowania. Aby uniknąć zakłóceń w działaniu innych aplikacji, które mogą wymagać dostępu do mikrofonu, VIA musi mieć dostęp do wejścia audio za pomocą:
- Przechwytywanie dźwięku musi używać MediaRecorder.AudioSource.HOTWORD.
- Uprawnienia
android.Manifest.permission.CAPTURE_AUDIO_HOTWORD
.
Oba te ciągi są @hide
i są dostępne tylko dla aplikacji w pakiecie.
Zarządzanie wejściem audio i rozpoznawaniem głosu
Dane wejściowe audio można uzyskać za pomocą klasy MediaRecorder.
Więcej informacji o korzystaniu z tego interfejsu API znajdziesz w artykule MediaRecorder – przegląd. Usługi interakcji głosowej powinny też być implementowane zgodnie z wytycznymi RecognitionService
. Każda aplikacja w systemie, która wymaga rozpoznawania głosu, korzysta z tego uprawnienia. Aby rozpoznawać głos i mieć dostęp do mikrofonu, VIA musi przytrzymać android.permission.RECORD_AUDIO
.
Aplikacje, które uzyskują dostęp do implementacji RecognitionService
, powinny też mieć to uprawnienie.
Przed Androidem 10 dostęp do mikrofonu był przyznawany tylko jednej aplikacji naraz (z wyjątkiem wykrywania słów kluczowych, patrz wyżej). Począwszy od Androida 10, dostęp do mikrofonu można udostępniać. Więcej informacji znajdziesz w artykule Udostępnianie danych wejściowych audio.
Dostęp do wyjścia audio
Gdy VIA będzie gotowy do udzielania odpowiedzi werbalnych, należy przestrzegać tych wskazówek:
- Gdy aplikacja prosi o skupienie się na dźwięku lub zarządzanie wyjściem audio, musi używać atrybutów audio
AudioAttributes#USAGE_ASSISTANT
iAudioAttributes#CONTENT_TYPE_SPEECH
. - Podczas rozpoznawania mowy należy poprosić o skupienie się na dźwięku za pomocą
AudioManage#AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE
. Pamiętaj, że niektóre aplikacje multimedialne mogą nie reagować prawidłowo na polecenia multimedialne (patrz Realizowanie poleceń multimedialnych), gdy nie są one aktywne.