Tworzenie aplikacji

Aby wdrożyć aplikację do interakcji głosowych (VIA), wykonaj te czynności:

  1. Utwórz szkielet VIA.
  2. (opcjonalnie) Wdróż proces konfiguracji lub logowania.
  3. (Opcjonalnie) Wdróż ekran Ustawienia.
  4. Zadeklaruj wymagane uprawnienia w pliku manifestu.
  5. Wdróż interfejs płyty głosowej.
  6. Wdróż rozpoznawanie głosu (musi obejmować implementację interfejsu RecognitionService API).
  7. Zaimplementuj wypowiedź (opcjonalnie możesz zaimplementować interfejs TextToSpeech API).
  8. Wdrożenie realizacji poleceń. Więcej informacji znajdziesz w sekcji Realizowanie poleceń.

W sekcjach poniżej znajdziesz opis każdego z wymienionych wyżej 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:

  • Asystenci głosowi muszą udostępniać usługę, która rozszerza VoiceInteractionService, z filtrem intencji dla działania VoiceInteractionService.SERVICE_INTERFACE ("android.service.voice.VoiceInteractionService").
  • Ta usługa musi mieć uprawnienie do podpisu systemowego BIND_VOICE_INTERACTION.
  • Ta usługa powinna zawierać android.voice_interactionplik metadanych, który zawiera te informacje:

    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 poszczególnych polach znajdziesz w sekcji R.styleable#VoiceInteractionService. Wszystkie usługi VIA są też usługami rozpoznawania głosu, więc w pliku manifestu musisz też uwzględnić te informacje:

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

Poniższy diagram przedstawia cykl życia każdego z tych elementów:

Cykle życia

Rysunek 1. Cykle życia

Jak już wspomnieliśmy, VoiceInteractionService to punkt wejścia do VIA. Główne obowiązki tego zespołu to:

  • Inicjowanie procesów, które powinny być uruchomione tak długo, jak długo ten interfejs VIA jest aktywny. Na przykład wykrywanie słów-kluczy.
  • Raportuje obsługiwane komendy głosowe (patrz Asystent głosowy – czytanie na głos).
  • Uruchamiaj sesje interakcji głosowej z poziomu ekranu blokady.

W najprostszej postaci implementacja VoiceInteractionService wyglądałaby 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 Czytaj po kliknięciu w Asystencie głosowym. System używa VoiceInteractionSessionService do tworzenia VoiceInteractionSession i wchodzenia z nim w interakcje. Ma tylko jedno zadanie: rozpoczynać nowe sesje na żądanie.

public class MyVoiceInteractionSessionService extends VoiceInteractionSessionService {
    @Override
    public VoiceInteractionSession onNewSession(Bundle args) {
        return new MyVoiceInteractionSession(this);
    }
}

Większość pracy odbywa się w ramach VoiceInteractionSession. Jedno wystąpienie sesji może być ponownie użyte do wykonania wielu interakcji użytkownika. W AAOS istnieje pomocnik CarVoiceInteractionSession , który ułatwia wdrażanie niektórych unikalnych funkcji motoryzacyjnych.

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 sekcjach poniżej. Pełną listę znajdziesz w dokumentacji VoiceInteractionSession.

Wdrażanie procesu konfiguracji lub logowania

Konfigurowanie i logowanie może odbywać się:

  • Podczas konfigurowania urządzenia (w kreatorze konfiguracji).
  • Podczas przełączania usług interakcji głosowej (Ustawienia).
  • Przy pierwszym uruchomieniu po wybraniu aplikacji.

Szczegółowe informacje o zalecanej wygodzie użytkownika i wskazówki wizualne znajdziesz w artykule Wstępnie załadowani asystenci: wskazówki dotyczące UX.

Konfiguracja podczas przełączania usługi głosowej

Użytkownik zawsze może wybrać VIA, który nie został prawidłowo skonfigurowany. Może się tak zdarzyć, ponieważ:

  • Użytkownik całkowicie pominął Kreatora konfiguracji lub pominął krok konfiguracji interakcji głosowej.
  • Użytkownik wybrał inny adres VIA niż ten skonfigurowany podczas wprowadzania urządzenia.

W każdym przypadku VoiceInteractionService może zachęcić użytkownika do dokończenia konfiguracji na kilka sposobów:

  • Przypomnienie o powiadomieniu.
  • Automatyczna odpowiedź głosowa, gdy użytkownik spróbuje jej użyć.

Uwaga: zdecydowanie odradzamy wyświetlanie 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 w wyniku przełączenia lub odblokowania przez użytkownika.

Przypomnienie o powiadomieniu

Przypomnienie w formie powiadomienia to nienachalny sposób na poinformowanie o konieczności konfiguracji i zapewnienie użytkownikom możliwości przejścia do procesu konfiguracji asystenta.

Przypomnienie o powiadomieniu

Rysunek 2. Przypomnienie o powiadomieniu

Proces ten wyglądałby tak:

Proces przypominania o powiadomieniach

Rysunek 3. Proces przypominania o powiadomieniach

Odpowiedź głosowa

Jest to najprostszy proces do wdrożenia. Rozpoczyna się on od wywołania zwrotnego VoiceInteractionSession#onShow(), wyjaśnia użytkownikowi, co należy zrobić, a następnie pyta go (jeśli konfiguracja jest dozwolona w danym stanie ograniczeń UX), czy chce rozpocząć proces konfiguracji. Jeśli konfiguracja nie jest w danym momencie możliwa, również to wyjaśnij.

Konfiguracja przy pierwszym użyciu

Użytkownik zawsze może wywołać VIA, która nie została prawidłowo skonfigurowana. W takich przypadkach:

  1. Poinformuj użytkownika o tej sytuacji (np. „Aby działać prawidłowo, muszę wykonać kilka czynności…”).
  2. Jeśli silnik ograniczeń UX na to pozwala (patrz UX_RESTRICTIONS_NO_SETUP), zapytaj użytkownika, czy chce rozpocząć proces konfiguracji, a następnie otwórz ekran Ustawienia dla VIA.
  3. W innych przypadkach (np. gdy użytkownik prowadzi samochód) pozostaw powiadomienie, aby użytkownik mógł kliknąć opcję, gdy będzie to bezpieczne.

Tworzenie ekranów konfiguracji interakcji głosowych

Ekrany konfiguracji i logowania powinny być opracowane jako zwykłe aktywności. Zapoznaj się z wskazówkami dotyczącymi UX i wyglądu interfejsu w preinstalowanych asystentach.

Ogólne wskazówki:

  • VIA powinny 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 każdego pojazdu. Ogólny układ ekranu, ikony, kolory i inne aspekty powinny być zgodne z pozostałą częścią interfejsu. Szczegóły znajdziesz w sekcji Dostosowywanie.

Implementowanie ekranu ustawień

Integracja ustawień

Rysunek 4. Integracja ustawień

Ekran ustawień to zwykła aktywność na Androidzie. Jeśli punkt wejścia jest zaimplementowany, musi być zadeklarowany w res/xml/interaction_service.xml w ramach manifestów VIA (patrz Manifesty). Sekcja Ustawienia to dobre miejsce, aby kontynuować konfigurację i logowanie (jeśli użytkownik nie zakończył tych czynności) lub w razie potrzeby zaoferować opcję wylogowania lub przełączenia użytkownika. Podobnie jak opisane powyżej ekrany konfiguracji, te ekrany powinny:

  • Zapewnij możliwość powrotu do poprzedniego ekranu w stosie ekranów (np. do ustawień samochodu).
  • nie może być dozwolone podczas jazdy; Szczegółowe informacje znajdziesz we wskazówkach dotyczących rozpraszania uwagi kierowcy.
  • Dopasuj każdy system projektowania pojazdów. Więcej informacji znajdziesz w sekcji Dostosowywanie.

Zadeklaruj wymagane uprawnienia w pliku manifestu.

Uprawnienia wymagane przez dostawcę usług weryfikacji tożsamości można podzielić na 3 kategorie:

  • Uprawnienia do podpisu systemowego Są to uprawnienia przyznawane tylko wstępnie zainstalowanym plikom APK podpisanym przez system. Użytkownicy nie mogą przyznawać tych uprawnień. Mogą to robić tylko producenci OEM podczas tworzenia obrazów systemu. Więcej informacji o uzyskiwaniu uprawnień do podpisu znajdziesz w artykule Przyznawanie uprawnień systemowych.
  • Uprawnienia niebezpieczne Są to uprawnienia, które użytkownik musi przyznać w oknie PermissionsController. Producenci OEM mogą wstępnie przyznawać niektóre z tych uprawnień domyślnej usłudze VoiceInteractionService. Jednak domyślne ustawienia mogą się różnić w zależności od urządzenia, dlatego aplikacje powinny mieć możliwość proszenia o te uprawnienia w razie potrzeby.
  • Inne uprawnienia Są to wszystkie inne uprawnienia, które nie wymagają interwencji użytkownika. Te uprawnienia są przyznawane automatycznie przez system.

W związku z tym w sekcji poniżej skupimy się tylko na żądaniu uprawnień niebezpiecznych. O uprawnienia należy prosić tylko wtedy, gdy użytkownik znajduje się na ekranie logowania lub ustawień.

Jeśli aplikacja nie ma uprawnień potrzebnych do działania, zalecamy użycie komunikatu głosowego, aby wyjaśnić sytuację użytkownikowi, oraz powiadomienia, które umożliwi użytkownikowi powrót do ekranów ustawień VIA. Więcej informacji znajdziesz w sekcji 1. przypomnienie o powiadomieniu.

Prośba o uprawnienia na ekranie ustawień

O uprawnienia określane jako niebezpieczne należy prosić za pomocą zwykłej metody ActivityCompat#requestPermission() (lub równoważnej). Szczegółowe informacje o tym, jak poprosić o uprawnienia, znajdziesz w artykule Przekazywanie próśb o uprawnienia aplikacji.

Prośba o uprawnienia

Rysunek 5. Prośba o uprawnienia

Zgoda na odbieranie powiadomień

Aby wdrożyć proces TTR, dostawcy usług weryfikacji tożsamości muszą być wyznaczeni jako odbiorcy powiadomień. Nie jest to samo w sobie uprawnienie, ale konfiguracja, która umożliwia systemowi wysyłanie powiadomień do zarejestrowanych odbiorców. Aby sprawdzić, czy wirtualny asystent otrzymał dostęp do tych informacji, aplikacje mogą:

Jeśli dostęp nie został wcześniej przyznany, VIA powinna skierować użytkownika do sekcji Dostęp do powiadomień w Ustawieniach samochodu, używając kombinacji wypowiedzi i powiadomień. Poniższy kod umożliwia otwieranie odpowiedniej sekcji aplikacji Ustawienia:

private void requestNotificationListenerAccess() {
    Intent intent = new Intent(Settings
        .ACTION_NOTIFICATION_LISTENER_SETTINGS);
    intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName());
    startActivity(intent);
}

Wdrażanie interfejsu tabliczki z informacjami o głosie

Gdy VoiceInteractionSession otrzyma wywołanie zwrotne onShow(), może wyświetlić interfejs użytkownika z informacjami głosowymi. Wskazówki dotyczące interfejsu i wrażeń użytkownika w przypadku implementacji modułu głosowego znajdziesz w artykule Preloaded Assistants: UX Guidance (Wstępnie załadowani asystenci: wskazówki dotyczące wrażeń użytkownika).

Wyświetlanie tabliczki z głosem

Rysunek 6. Wyświetlanie tabliczki z głosem

Ten interfejs możesz wdrożyć na 2 sposoby:

  • Zastąp VoiceInteractionSession#onCreateContentView()
  • Uruchamianie aktywności przy użyciu dodatku VoiceInteractionSession#startAssistantActivity()

Używanie metody onCreateContentView()

Jest to domyślny sposób prezentowania płyty głosowej. Klasa bazowa VoiceInteractionSessiontworzy okno i zarządza jego cyklem życia tak długo, jak trwa sesja głosowa. Aplikacje muszą zastąpić VoiceInteractionSession#onCreateContentView() i zwrócić widok dołączony do tego okna natychmiast po utworzeniu sesji. Ten widok powinien być początkowo niewidoczny. Gdy rozpocznie się interakcja głosowa, ten widok powinien być widoczny na VoiceInteractionSession#onShow(), a potem ponownie niewidoczny na 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);
    }
    
}

Jeśli używasz tej metody, możesz dostosować VoiceInteractionSession#onComputeInsets(), aby uwzględnić zasłonięte obszary interfejsu.

Używanie metody startAssistantActivity()

W takim przypadku VoiceInteractionSession przekazuje obsługę interfejsu tabliczki głosowej do zwykłej aktywności. Gdy ta opcja jest używana, implementacja musi wyłączyć tworzenie domyślnego okna treści (patrz Using onCreateContentView()) w wywołaniu zwrotnym onPrepareShow().VoiceInteractionSession O godzinie VoiceInteractionSession#onShow() sesja rozpocznie aktywność związaną z komendami głosowymi przy użyciu usługi 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 powiązanie usługi. Gdy na przykład wywoływana jest funkcja VoiceInteractionSession#onHide(), sesja musi być w stanie przekazać to żądanie do działania.

Ważne: W przypadku branży motoryzacyjnej podczas jazdy mogą być wyświetlane tylko specjalnie oznaczone aktywności lub aktywności wymienione na „białej liście” UXR. Dotyczy to również aktywności rozpoczętych za pomocą VoiceInteractionSession#startAssistantActivity(). Pamiętaj, aby oznaczyć aktywność symbolem <meta-data android:name="distractionOptimized" android:value="true"/> lub uwzględnić ją w kluczu systemActivityWhitelist pliku /packages/services/Car/service/res/values/config.xml. Więcej informacji znajdziesz w wytycznych dotyczących rozpraszania uwagi kierowcy.

Wdrażanie rozpoznawania głosu

Z tej sekcji dowiesz się, jak wdrożyć rozpoznawanie głosu za pomocą wykrywania i rozpoznawania słów aktywujących. Słowo aktywujące to słowo wyzwalające używane do rozpoczęcia nowego zapytania lub działania za pomocą głosu. na przykład „OK Google” lub „Hej Google”.

Wykrywanie słów-kluczy przez procesor DSP

Android zapewnia dostęp do zawsze włączonego detektora słów kluczowych na poziomie procesora DSP za pomocą interfejsu AlwaysOnHotwordDetector. sposób wdrożenia wykrywania słów-kluczy przy niskim wykorzystaniu procesora. Korzystanie z tej funkcji dzieli się na 2 części:

Implementacja VoiceInteractionService może utworzyć detektor słów kluczowych za pomocą VoiceInteractionService#createAlwaysOnHotwordDetector(), przekazując frazę kluczową i ustawienia regionalne, których chce używać do wykrywania. W rezultacie aplikacja otrzymuje wywołanie zwrotne onAvailabilityChanged() z jedną z tych wartości:

  • STATE_HARDWARE_UNAVAILABLE. Funkcja DSP jest niedostępna na tym urządzeniu. W tym przypadku używane jest wykrywanie słów kluczowych przez oprogramowanie.
  • STATE_HARDWARE_UNSUPPORTED. Obsługa DSP nie jest dostępna w ogóle, ale DSP nie obsługuje podanej kombinacji słów kluczowych i języka. Aplikacja może korzystać z programowego wykrywania słów kluczowych.
  • STATE_HARDWARE_ENROLLED. Wykrywanie słów-kluczy jest gotowe i można je uruchomić, wywołując metodę startRecognition().
  • STATE_HARDWARE_UNENROLLED. Model dźwiękowy dla żądanej kluczowej frazy jest niedostępny, ale rejestracja jest możliwa.

Rejestracja modeli dźwiękowych wykrywania słów kluczowych może odbywać się za pomocą IVoiceInteractionManagerService#updateKeyphraseSoundModel(). W systemie może być zarejestrowanych wiele modeli, ale tylko jeden z nich jest powiązany z AlwaysOnHotwordDetector. Wykrywanie słów kluczowych przez procesor DSP może nie być dostępne na wszystkich urządzeniach. Deweloperzy VIA powinni sprawdzać możliwości sprzętowe za pomocą metody getDspModuleProperties(). Przykładowy kod pokazujący, jak rejestrować modele dźwiękowe, znajdziesz w VoiceEnrollment/src/com/android/test/voiceenrollment/EnrollmentUtil.java. Więcej informacji o jednoczesnym rozpoznawaniu słów aktywujących znajdziesz w sekcji Jednoczesne przechwytywanie.

Wykrywanie słów-kluczy przez oprogramowanie

Jak wspomnieliśmy powyżej, wykrywanie słowa aktywacyjnego przez DSP może nie być dostępne na wszystkich urządzeniach (np. emulator Androida nie zapewnia emulacji DSP). W takim przypadku jedyną alternatywą jest rozpoznawanie głosu przez oprogramowanie. Aby uniknąć zakłóceń w działaniu innych aplikacji, które mogą potrzebować dostępu do mikrofonu, wirtualni asystenci muszą uzyskiwać dostęp do wejścia audio za pomocą:

Obie te stałe mają wartość @hide i są dostępne tylko dla aplikacji w pakiecie.

Zarządzanie danymi wejściowymi audio i rozpoznawaniem głosu

Wejście audio będzie realizowane za pomocą klasy MediaRecorder. Więcej informacji o korzystaniu z tego interfejsu API znajdziesz w omówieniu MediaRecorder. Usługi interakcji głosowej powinny być też implementacjami klasy RecognitionService. Każda aplikacja w systemie, która wymaga rozpoznawania głosu, korzysta z tej funkcji. Aby korzystać z rozpoznawania głosu i mieć dostęp do mikrofonu, urządzenia VIA muszą mieć android.permission.RECORD_AUDIO. Aplikacje korzystające z implementacji RecognitionService również powinny mieć to uprawnienie.

Przed Androidem 10 dostęp do mikrofonu miała tylko jedna aplikacja naraz (z wyjątkiem wykrywania słów kluczowych – patrz wyżej). Od Androida 10 dostęp do mikrofonu może być udostępniany. Więcej informacji znajdziesz w artykule Udostępnianie wejścia audio.

Dostęp do wyjścia audio

Gdy wirtualny asystent jest gotowy do udzielania odpowiedzi głosowych, ważne jest, aby przestrzegać tych wytycznych: