Realizowanie poleceń

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:

  1. być instalowane jako aplikacje podpisane przez system (patrz wskazówki dotyczące tworzenia aplikacji multimedialnych na AAOS oraz przykładowy kod PackageValidator);
  2. Posiadać uprawnienia android.permission.MEDIA_CONTENT_CONTROL (patrz Przyznawanie uprawnień systemowych).

Oprócz MediaBrowserCompat i MediaControllerCompat AAOS udostępnia te funkcje:

  • CarMediaServicezawiera 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_REPLACEDACTION_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

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ć TelephonyManagerdo 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.