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ń. Zobacz te treści w sekcji Wykonywanie 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, dlatego 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 to VIA jest aktywny. Na przykład wykrywanie słów-kluczy.
  • Raportuje obsługiwane komendy głosowe (patrz Asystent głosowy – funkcja „Kliknij, aby przeczytać”).
  • Uruchamiaj sesje interakcji głosowej z poziomu ekranu blokady (keyguard).

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 dotknij, aby przeczytać Asystenta głosowego. Usługa VoiceInteractionSessionService jest używana przez system do tworzenia sesji VoiceInteractionSession i wchodzenia z nią 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);
    }
}

VoiceInteractionSession wykonywana jest większość pracy. Jedno wystąpienie sesji może być ponownie użyte do wykonania wielu interakcji użytkownika. W AAOS istnieje pomocnik CarVoiceInteractionSession , który pomaga wdrażać niektóre unikalne funkcje motoryzacyjne.

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ł VIA inne niż skonfigurowane 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 próbuje z niej skorzystać.

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 umożliwienie użytkownikom 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:

  • Asystenci głosowi powinni 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ć spójne 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 otwarcie 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 głosami

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łosami

Rysunek 6. Wyświetlanie tabliczki z głosami

Ten interfejs użytkownika można 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 tabliczki z głosem. 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 urządzeniu VoiceInteractionSession#onShow(), a potem ponownie niewidoczny na urządzeniu 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 funkcji startAssistantActivity()

W takim przypadku VoiceInteractionSession przekazuje obsługę interfejsu tablicy głosowej do zwykłej aktywności. Gdy ta opcja jest używana, implementacja VoiceInteractionSession musi wyłączyć tworzenie domyślnego okna treści (patrz Using onCreateContentView()) w wywołaniu zwrotnym onPrepareShow(). 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 aktywności.

Ważne: W przypadku motoryzacji 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 dodać do aktywności adnotację <meta-data android:name="distractionOptimized" android:value="true"/> lub 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.

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łowa-klucza 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 aktywujących za pomocą VoiceInteractionService#createAlwaysOnHotwordDetector(), przekazując kluczową frazę i ustawienia regionalne, które mają być używane 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-kluczy przez oprogramowanie.
  • STATE_HARDWARE_UNSUPPORTED. Obsługa platformy DSP nie jest dostępna w ogóle, ale platforma 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-kluczy 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 procesor DSP może nie być dostępne na wszystkich urządzeniach (np. emulator Androida nie zapewnia emulacji procesora 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 artykule MediaRecorder – omówienie. Usługi interakcji głosowej również powinny być 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, VIA musi 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 aktywujących – 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: