Na tej stronie dowiesz się, jak wykonywać polecenia za pomocą interakcji głosowej.
Wykonywanie poleceń dotyczących multimediów
Polecenia związane z multimediami można podzielić na 3 różne grupy:
- zewnętrzne źródła multimediów (np. Spotify zainstalowane w AAOS);
- źródła multimediów na serwerze (np. muzyka przesyłana strumieniowo przez VIA);
- lokalnych źródeł multimediów (np. radia samochodowego);
Obsługa poleceń zewnętrznego źródła multimediów
Zewnętrzne źródła multimediów to aplikacje na Androida, które obsługują interfejsy MediaSessionCompat
i MediaBrowseCompat
API (szczegółowe wyjaśnienie korzystania z tych interfejsów API znajdziesz w artykule Tworzenie aplikacji multimedialnych na samochody).
Ważne: aby aplikacja asystenta mogła połączyć się z MediaBrowseService wszystkich zainstalowanych aplikacji multimedialnych w systemie, musi:
- musi być zainstalowana jako aplikacja podpisana przez system (wytyczne dotyczące tworzenia aplikacji multimedialnych na AAOS i przykładowy
PackageValidatorkod); - mieć uprawnienia systemowe
android.permission.MEDIA_CONTENT_CONTROL(patrz Przyznawanie uprawnień systemowych);
Oprócz MediaBrowserCompat i MediaControllerCompat AAOS udostępnia:
CarMediaServicezawiera centralne informacje o aktualnie wybranym źródle multimediów. Jest ona również używana do wznowienia odtwarzania wcześniej odtwarzanego źródła multimediów po wyłączeniu i ponownym uruchomieniu samochodu.car-media-commonudostępnia wygodne metody wyświetlania listy aplikacji multimedialnych, łączenia się z nimi i korzystania z nich.
Poniżej znajdziesz wytyczne dotyczące wdrażania typowych poleceń interakcji głosowych.
Pobieranie listy zainstalowanych źródeł multimediów
Źródła multimediów można wykrywać za pomocą PackageManager i filtrować usługi pasujące do MediaBrowserService.SERVICE_INTERFACE.
W niektórych samochodach mogą występować specjalne implementacje usługi przeglądarki multimediów, które należy wykluczyć. Oto przykład tej logiki:
private Map<String, MediaSource> getAvailableMediaSources() { List<String> customMediaServices = Arrays.asList(mContext.getResources() .getStringArray(R.array.custom_media_packages)); List<ResolveInfo> mediaServices = mPackageManager.queryIntentServices( new Intent(MediaBrowserService.SERVICE_INTERFACE), PackageManager.GET_RESOLVED_FILTER); Map<String, MediaSource> result = new HashMap<>(); for (ResolveInfo info : mediaServices) { String packageName = info.serviceInfo.packageName; if (customMediaServices.contains(packageName)) { // Custom media sources should be ignored, as they might have a // specialized handling (e.g., radio). continue; } String className = info.serviceInfo.name; ComponentName componentName = new ComponentName(packageName, className); MediaSource source = MediaSource.create(mContext, componentName); result.put(source.getDisplayName().toString().toLowerCase(), source); } return result; }
Pamiętaj, że źródła multimediów można w każdej chwili zainstalować lub odinstalować. Aby zachować dokładność listy, zalecamy wdrożenie instancji BroadcastReceiver w przypadku działań związanych z intencjami ACTION_PACKAGE_ADDED, ACTION_PACKAGE_CHANGED, ACTION_PACKAGE_REPLACED i ACTION_PACKAGE_REMOVED.
Łączenie z aktualnie odtwarzanym źródłem multimediów
CarMediaService
udostępnia metody pobierania aktualnie wybranego źródła multimediów i informowania o zmianie tego źródła. Zmiany te mogą być spowodowane bezpośrednią interakcją użytkownika z interfejsem lub użyciem przycisków sprzętowych w samochodzie. Z drugiej strony biblioteka car-media-common oferuje wygodne sposoby łączenia się z danym źródłem multimediów. Oto uproszczony fragment kodu pokazujący, jak połączyć się z obecnie wybraną aplikacją multimedialną:
public class MediaActuator implements MediaBrowserConnector.onConnectedBrowserChanged { private final Car mCar; private CarMediaManager mCarMediaManager; private MediaBrowserConnector mBrowserConnector; … public void initialize(Context context) { mCar = Car.createCar(context); mBrowserConnector = new MediaBrowserConnector(context, this); mCarMediaManager = (CarMediaManager) mCar.getCarManager(Car.CAR_MEDIA_SERVICE); mBrowserConnector.connectTo(mCarMediaManager.getMediaSource()); … } @Override public void onConnectedBrowserChanged( @Nullable MediaBrowserCompat browser) { // TODO: Handle connected/disconnected browser } … }
sterować odtwarzaniem aktualnie odtwarzanego źródła multimediów,
Po połączeniu MediaBrowserCompat możesz łatwo wysyłać do aplikacji docelowej polecenia sterowania transportem. Oto uproszczony przykład:
public class MediaActuator … { … private MediaControllerCompat mMediaController; @Override public void onConnectedBrowserChanged( @Nullable MediaBrowserCompat browser) { if (browser != null && browser.isConnected()) { mMediaController = new MediaControllerCompat(mContext, browser.getSessionToken()); } else { mMediaController = null; } } private boolean playSongOnCurrentSource(String song) { if (mMediaController == null) { // No source selected. return false; } MediaControllerCompat.TransportControls controls = mMediaController.getTransportControls(); PlaybackStateCompat state = controller.getPlaybackState(); if (state == null || ((state.getActions() & PlaybackStateCompat.ACTION_PLAY_FROM_SEARCH) == 0)) { // Source can't play from search return false; } controls.playFromSearch(query, null); return true; } … }
Obsługa poleceń lokalnych źródeł multimediów (radio, odtwarzacz CD, Bluetooth, USB)
Lokalne źródła multimediów udostępniają swoje funkcje systemowi za pomocą tych samych interfejsów MediaSession i MediaBrowse API, które zostały opisane powyżej. Aby uwzględnić specyfikę każdego typu sprzętu, te usługi MediaBrowse używają określonych konwencji do organizowania informacji i poleceń multimedialnych.
Obsługa radia
Usługę Radio MediaBrowseService można zidentyfikować za pomocą filtra intencji ACTION_PLAY_BROADCASTRADIO. Powinny one korzystać z elementów sterujących odtwarzaniem i struktury przeglądania multimediów opisanych w artykule Implementowanie radia. AAOS udostępnia bibliotekęcar-broadcastradio-support zawierającą stałe i metody, które pomagają producentom OEM tworzyć implementacje MediaBrowseService dla własnych usług radiowych zgodne z określonym protokołem. Zapewnia też obsługę aplikacji korzystających z drzewa przeglądania (np. VIA).
obsługiwać wejście AUX, dźwięk z płyty CD i multimedia z USB;
W ramach AOSP nie ma domyślnej implementacji tych źródeł multimediów. Sugerowane podejście:
- Poproś producentów OEM o wdrożenie usług multimedialnych dla każdego z nich. Więcej informacji znajdziesz w artykule Tworzenie aplikacji multimedialnych na samochody.
- Te implementacje MediaBrowseService będą identyfikowane i obsługiwane w ramach działań intencji zdefiniowanych w sekcji Ogólne intencje odtwarzania.
- Takie usługi udostępniałyby drzewo przeglądania zgodnie z wytycznymi opisanymi w sekcji Inne typy źródeł.
Obsługa Bluetootha
Treści multimedialne Bluetooth są udostępniane za pomocą profilu Bluetooth AVRCP. Aby ułatwić dostęp do tej funkcji, AAOS zawiera implementację MediaBrowserService i MediaSession, która abstrahuje szczegóły komunikacji (patrz packages/apps/Bluetooth).
Odpowiednia struktura drzewa przeglądarki multimediów jest zdefiniowana w klasie BrowseTree. Polecenia sterowania odtwarzaniem mogą być dostarczane podobnie jak w przypadku innych aplikacji, za pomocą implementacji MediaSession.
Obsługa poleceń dotyczących strumieniowania multimediów
Aby zaimplementować przesyłanie strumieniowe multimediów po stronie serwera, VIA musi stać się źródłem multimediów, implementując interfejsy MediaBrowse i MediaSession API. Zapoznaj się z artykułem Tworzenie aplikacji multimedialnych na samochody. Dzięki wdrożeniu tych interfejsów API aplikacja do sterowania głosowego będzie mogła (między innymi):
- bezproblemowo uczestniczyć w wyborze źródła multimediów,
- automatycznie wznawiane po ponownym uruchomieniu samochodu;
- zapewniać sterowanie odtwarzaniem i przeglądaniem za pomocą interfejsu Centrum multimediów,
- Odbieranie standardowych zdarzeń przycisków multimedialnych sprzętu
Wykonywanie poleceń nawigacyjnych
Nie ma standardowego sposobu interakcji ze wszystkimi aplikacjami do nawigacji. W przypadku integracji z Mapami Google zapoznaj się z intencjami Map Google na Androida Automotive. W przypadku integracji z innymi aplikacjami skontaktuj się bezpośrednio z ich deweloperami. Przed uruchomieniem intencji w dowolnej aplikacji (w tym w Mapach Google) sprawdź, czy można ją rozwiązać (patrz Intencje Map Google). Dzięki temu możesz poinformować użytkownika, jeśli docelowa aplikacja jest niedostępna.
Wykonywanie poleceń dotyczących pojazdu
Dostęp do właściwości pojazdu z możliwością odczytu i zapisu jest zapewniany przez interfejs CarPropertyManager.
Typy właściwości pojazdu, ich implementacja i inne szczegóły są wyjaśnione w artykule Konfiguracje właściwości. Aby uzyskać dokładny opis właściwości obsługiwanych przez Androida, najlepiej zapoznać się bezpośrednio z hardware/interfaces/automotive/vehicle/2.0/types.hal.
Zdefiniowany tam wyliczenie VehicleProperty zawiera zarówno standardowe, jak i specyficzne dla dostawcy właściwości, typy danych, tryb zmiany, jednostki oraz definicję dostępu do odczytu i zapisu.
Aby uzyskać dostęp do tych samych stałych z poziomu Javy, możesz użyć klasy VehiclePropertyIds i jej klas towarzyszących. Poszczególne usługi mają różne uprawnienia Androida, które kontrolują do nich dostęp. Te uprawnienia są zadeklarowane w pliku manifestu CarService, a mapowanie między właściwościami i uprawnieniami jest opisane w dokumentacji Javadoc VehiclePropertyIds i wymuszane w PropertyHalServiceIds.
Odczytywanie właściwości pojazdu
Poniżej znajdziesz przykład odczytywania prędkości pojazdu:
public class CarActuator ... { private final Car mCar; private final CarPropertyManager mCarPropertyManager; private final TextToSpeech mTTS; /** Global VHAL area id */ public static final int GLOBAL_AREA_ID = 0; public CarActuator(Context context, TextToSpeech tts) { mCar = Car.createCar(context); mCarPropertyManager = (CarPropertyManager) mCar.getCarManager(Car.PROPERTY_SERVICE); mTTS = tts; ... } @Nullable private void getSpeedInMetersPerSecond() { if (!mCarPropertyManager.isPropertyAvailable(VehiclePropertyIds.PERF_VEHICLE_SPEED, GLOBAL_AREA_ID)) { mTTS.speak("I'm sorry, but I can't read the speed of this vehicle"); return; } // Data type and unit can be found in // automotive/vehicle/2.0/types.hal float speedInMps = mCarPropertyManager.getFloatProperty( VehiclePropertyIds.PERF_VEHICLE_SPEED, GLOBAL_AREA_ID); int speedInMph = (int)(speedInMetersPerSecond * 2.23694f); mTTS.speak(String.format("Sure. Your current speed is %d miles " + "per hour", speedInUserUnit); } ... }
Ustawianie właściwości pojazdu
Poniżej znajdziesz przykład włączania i wyłączania klimatyzacji z przodu.
public class CarActuator … {
…
private void changeFrontAC(boolean turnOn) {
List<CarPropertyConfig> configs = mCarPropertyManager
.getPropertyList(new ArraySet<>(Arrays.asList(
VehiclePropertyIds.HVAC_AC_ON)));
if (configs == null || configs.size() != 1) {
mTTS.speak("I'm sorry, but I can't control the AC of your vehicle");
return;
}
// Find the front area Ids for the AC property.
int[] areaIds = configs.get(0).getAreaIds();
List<Integer> areasToChange = new ArrayList<>();
for (int areaId : areaIds) {
if ((areaId & (VehicleAreaSeat.SEAT_ROW_1_CENTER
| VehicleAreaSeat.SEAT_ROW_1_LEFT
| VehicleAreaSeat.SEAT_ROW_1_RIGHT)) == 0) {
continue;
}
boolean isACInAreaAlreadyOn = mCarPropertyManager
.getBooleanProperty(VehiclePropertyIds.HVAC_AC_ON, areaId);
if ((!isACInAreaAlreadyOn && turnOn) || (isACInAreaAlreadyOn && !turnOn)) {
areasToChange.add(areaId);
}
}
if (areasToChange.isEmpty()) {
mTTS.speak(String.format("The AC is already %s", turnOn ? "on" : "off"));
return;
}
for (int areaId : areasToChange) {
mCarPropertyManager.setBooleanProperty(
VehiclePropertyIds.HVAC_AC_ON, areaId, turnOn);
}
mTTS.speak(String.format("Okay, I'm turning your front AC %s",
turnOn ? "on" : "off"));
}
…
}Wykonywanie poleceń komunikacyjnych
Obsługa poleceń dotyczących wiadomości
VIA musi obsługiwać wiadomości przychodzące zgodnie z procedurą „kliknij, aby przeczytać” opisaną w artykule Asystent głosowy – kliknij, aby przeczytać. Opcjonalnie może też wysyłać odpowiedzi do nadawcy wiadomości przychodzącej.
Dodatkowo VIAs mogą używać SmsManager (część pakietu android.telephony) do tworzenia i wysyłania SMS-ów bezpośrednio z samochodu lub przez Bluetooth.
Obsługa poleceń dotyczących połączeń
Podobnie VIA mogą używać TelephonyManager
do wykonywania połączeń telefonicznych i dzwonienia na numer poczty głosowej użytkownika. W takich przypadkach VIA będzie wchodzić w interakcję bezpośrednio ze stosem telefonicznym lub z aplikacją Car Dialer. W każdym przypadku to aplikacja Car Dialer powinna wyświetlać użytkownikowi interfejs związany z połączeniami głosowymi.
Realizowanie innych poleceń
Listę innych możliwych punktów integracji między interfejsem VIA a systemem znajdziesz na liście znanych intencji Androida. Wiele poleceń użytkownika można rozwiązać po stronie serwera (np. odczytywanie e-maili i wydarzeń w kalendarzu użytkowników), co nie wymaga żadnych interakcji z systemem poza samą interakcją głosową.
Działania wciągające (wyświetlanie treści wizualnych)
Gdy VIA ułatwia użytkownikowi wykonanie działania lub zrozumienie czegoś, może wyświetlać dodatkowe treści wizualne na ekranie samochodu. Aby nie rozpraszać uwagi kierowcy, takie treści powinny być proste, krótkie i zawierać konkretne działania. Szczegółowe informacje o wytycznych dotyczących interfejsu użytkownika i UX w przypadku działań immersyjnych znajdziesz w artykule Preloaded Assistants: UX Guidance (w języku angielskim).
Aby umożliwić dostosowywanie i zapewnić spójność z pozostałą częścią projektu konsoli centralnej, interfejsy VIAs powinny korzystać z komponentów biblioteki Car UI w przypadku większości elementów interfejsu. Więcej informacji znajdziesz w sekcji Dostosowywanie.