Na tej stronie znajdziesz informacje o wykonywaniu poleceń za pomocą interakcji głosowej.
Realizowanie poleceń dotyczących multimediów
Polecenia związane z multimediami można podzielić na 3 grupy:
- zewnętrzne źródła multimediów (np. Spotify zainstalowany w AAOS).
- Źródła multimediów w backendzie (np. muzyka przesyłana strumieniowo przez VIA).
- lokalne źródła mediów (np. radio samochodowe);
Obsługa poleceń dotyczących zewnętrznych źródeł multimediów
Zewnętrzne źródła multimediów to aplikacje na Androida, które obsługują interfejsy API MediaSessionCompat
i MediaBrowseCompat
(szczegółowe informacje o korzystaniu z tych interfejsów API znajdziesz w artykule Tworzenie aplikacji multimedialnych dla samochodów).
Ważne: aby aplikacja asystenta mogła połączyć się z MediaBrowseService
wszystkich zainstalowanych aplikacji multimedialnych w systemie, musi:
- być instalowane jako aplikacje podpisane przez system (patrz wskazówki dotyczące tworzenia aplikacji multimedialnych na AAOS oraz przykładowy kod
PackageValidator
); - Posiadać uprawnienia
android.permission.MEDIA_CONTENT_CONTROL
(patrz Przyznawanie uprawnień systemowych).
Oprócz MediaBrowserCompat
i MediaControllerCompat
AAOS udostępnia te funkcje:
CarMediaService
zawiera scentralizowane informacje o obecnie wybranym źródle multimediów. Służy on również do wznowienia odtwarzania z poprzednio odtwarzanego źródła multimediów po wyłączeniu i ponownie włączeniu samochodu.car-media-common
udostępnia wygodne metody wyświetlania listy aplikacji multimedialnych, łączenia się z nimi i interagowania z nimi.
Poniżej znajdziesz wskazówki dotyczące implementacji poleceń związanych z częstymi interakcjami głosowymi.
Pobieranie listy zainstalowanych źródeł multimediów
Źródła multimediów można wykrywać za pomocą PackageManager
, filtrując usługi pasujące do MediaBrowserService.SERVICE_INTERFACE
.
W niektórych samochodach mogą występować specjalne implementacje przeglądarek multimedialnych, które należy wykluczyć. Oto przykład takiej 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 dowolnym momencie zainstalować lub odinstalować. Aby mieć dokładną listę, zalecamy wdrożenie instancji BroadcastReceiver
dla działań związanych z zamiarem ACTION_PACKAGE_ADDED
, ACTION_PACKAGE_CHANGED
, ACTION_PACKAGE_REPLACED
i ACTION_PACKAGE_REMOVED
.
Łączenie z obecnie odtwarzanym źródłem multimediów
CarMediaService
zawiera metody uzyskiwania obecnie wybranego źródła multimediów oraz informacje o tym, kiedy to źródło się zmienia. Zmiany te mogły nastąpić, ponieważ użytkownik wszedł w bezpośrednią interakcję z interfejsem użytkownika lub użył przycisków sprzętowych w samochodzie. Z kolei biblioteka car-media-common umożliwia wygodne połączenie z danym źródłem multimediów. Oto uproszczony fragment kodu, który umożliwia połączenie z obecnie wybraną aplikacją do multimediów:
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 z MediaBrowserCompat
można łatwo wysyłać polecenia sterowania transportem do aplikacji docelowej. 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ń dotyczących 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, o których mowa powyżej. Aby uwzględnić specyfikę poszczególnych typów sprzętu, te usługi przeglądania multimediów używają określonych konwencji do porządkowania informacji i poleceń multimediów.
Obsługa radia
Usługę MediaBrowseService można zidentyfikować na podstawie filtra intencji ACTION_PLAY_BROADCASTRADIO
. Muszą one stosować elementy sterujące odtwarzaniem i strukturę przeglądania multimediów opisane w artykule Wdrażanie radia. AAOS udostępnia bibliotekę car-broadcastradio-support
zawierającą stałe i metody, które pomagają producentom urządzeń tworzyć implementacje MediaBrowseService dla własnych usług radiowych zgodnych z określonym protokołem. Zapewnia też obsługę aplikacji korzystających z ich drzewa przeglądania (np. VIA).
Obsługa wejścia pomocniczego, płyt CD i multimediów USB
Domyślna implementacja tych źródeł multimediów nie jest częścią AOSP. Sugerowane podejście:
- OEM muszą wdrożyć usługi multimedialne dla każdego z nich. Szczegółowe informacje znajdziesz w artykule Tworzenie aplikacji multimedialnych na samochody.
- W przypadku tych implementacji MediaBrowseService działania związane z zamierzami są określane i realizowane w ramach działań związanych z zamierzami określonych w sekcji Ogólne intencje odtwarzania.
- Te usługi udostępniają drzewo wyszukiwania zgodnie z wytycznymi opisanymi w sekcji Inne typy źródeł.
Obsługa Bluetooth
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ć przesyłane podobnie jak w innych aplikacjach za pomocą implementacji MediaSession.
Obsługa poleceń dotyczących strumieniowania multimediów
Aby móc przesyłać strumieniowo treści po stronie serwera, VIA musi stać się źródłem multimediów i zaimplementować interfejsy MediaBrowse i MediaSession API. Zapoznaj się z artykułem Tworzenie aplikacji multimedialnych na samochody. Dzięki wdrożeniu tych interfejsów API aplikacja sterowania głosem będzie mogła między innymi:
- bezproblemowo uczestniczyć w wybieraniu źródeł multimediów;
- automatycznie wznawiana po ponownym uruchomieniu samochodu;
- zapewniać sterowanie odtwarzaniem i przeglądaniem za pomocą interfejsu Media Center;
- Odbieranie standardowych zdarzeń przycisku multimediów
Realizowanie poleceń nawigacji
Nie ma ujednoliconego sposobu interakcji z wszystkimi aplikacjami do nawigacji. Informacje o integracji z Mapami Google znajdziesz w artykule Mapy Google na potrzeby Androida Automotive. W przypadku integracji z innymi aplikacjami skontaktuj się bezpośrednio z ich deweloperami. Zanim uruchomisz intencję w dowolnej aplikacji (w tym w Mapach Google), sprawdź, czy intencję można zrealizować (patrz żądania intencji). Dzięki temu możesz poinformować użytkownika, jeśli aplikacja docelowa jest niedostępna.
Realizacja poleceń dotyczących pojazdu
Dostęp do właściwości pojazdu do odczytu i zapisu jest zapewniany przez CarPropertyManager.
Typy właściwości pojazdu, ich implementacja i inne szczegóły są opisane w konfiguracjach właściwości. Aby uzyskać dokładny opis właściwości obsługiwanych przez Androida, najlepiej zapoznać się bezpośrednio z dokumentacją hardware/interfaces/automotive/vehicle/2.0/types.hal
.
Zdefiniowany tam enumeracyjny typ danych VehicleProperty zawiera zarówno standardowe, jak i specyficzne dla dostawcy właściwości, typy danych, tryb zmiany, jednostki i definicję dostępu do odczytu/zapisu.
Aby uzyskać dostęp do tych samych stałych wartości w języku Java, możesz użyć VehiclePropertyIds i powiązanych z nim klas. Różne usługi mają różne uprawnienia Androida, które kontrolują ich dostęp. Te uprawnienia są deklarowane w pliku manifestu usługi CarService, a mapowanie między właściwościami a uprawnieniami jest opisane w dokumentacji Javadoc VehiclePropertyIds i wymagane w PropertyHalServiceIds.
Odczytywanie właściwości pojazdu
Poniżej przedstawiamy przykład odczytania 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 przedstawiamy 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")); } … }
Realizowanie poleceń dotyczących komunikacji
Obsługa poleceń w wiadomościach
Interfejsy głosowe muszą obsługiwać przychodzące wiadomości zgodnie z procesem „dotknij, aby przeczytać” opisanym w artykule Asystent głosowy – dotknij, aby przeczytać. Interfejsy głosowe mogą też opcjonalnie wysyłać odpowiedzi do nadawcy wiadomości.
Dodatkowo VIA może 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ń
W podobny sposób VIA może używać TelephonyManager
do nawiązywania połączeń telefonicznych i dzwonienia na numer poczty głosowej użytkownika. W takich przypadkach VIA będzie wchodzić w interakcje bezpośrednio z komunikacją telefoniczną lub z aplikacją Dialer w samochodzie. W każdym przypadku aplikacja Dialer w samochodzie powinna wyświetlać użytkownikowi interfejs związany z rozmową głosową.
Realizowanie innych poleceń
Listę innych możliwych punktów integracji VIA z systemem znajdziesz na liście dobrze znanych intencji Androida. Wiele poleceń użytkownika może być przetwarzanych po stronie serwera (np. odczytywanie e-maili i wydarzeń w kalendarzu) i nie wymaga interakcji z systemem poza samą interakcją głosową.
Wciągające działania (wyświetlanie treści wizualnych)
W przypadku, gdy poprawia ona działania lub zrozumienie użytkownika, może wyświetlać dodatkowe treści wizualne na ekranie samochodu. Aby zminimalizować rozpraszanie uwagi kierowcy, trzymaj się prostych, krótkich i użytecznych treści. Szczegółowe informacje o wytycznych dotyczących UI/UX w przypadku działań w trybie pełnoekranowym znajdziesz w artykule Wstępnie zainstalowane asystenty: wskazówki dotyczące UX.
Aby umożliwić dostosowywanie i utrzymanie spójności z pozostałymi elementami konsoli głównej, w przypadku większości elementów interfejsu VIA powinny używać komponentów z biblioteki UI samochodu. Więcej informacji znajdziesz w artykule Dostosowywanie.