Wykonuj polecenia

Na tej stronie opisano, jak wykonywać polecenia za pomocą interakcji głosowej.

Wykonuj polecenia multimedialne

Polecenia związane z multimediami można podzielić na trzy różne grupy:

  • Zewnętrzne źródła multimediów (takie jak Spotify zainstalowany w AAOS).
  • Źródła multimediów zaplecza (takie jak muzyka przesyłana strumieniowo przez VIA).
  • Lokalne źródła medialne (takie jak radio samochodowe).

Obsługuj polecenia zewnętrznego źródła multimediów

Zewnętrzne źródła multimediów definiuje się jako aplikacje dla systemu Android obsługujące interfejsy API MediaSessionCompat i MediaBrowseCompat (szczegółowe wyjaśnienie dotyczące korzystania z tych interfejsów API można znaleźć 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. Należy zainstalować jako podpisany przez system (patrz Wytyczne dotyczące tworzenia aplikacji multimedialnych dla AAOS i przykładowy kod PackageValidator ).
  2. Trzymaj android.permission.MEDIA_CONTENT_CONTROL uprawnienia uprzywilejowane systemowo (zobacz Przyznawanie uprawnień uprzywilejowanych systemowo ).

Oprócz MediaBrowserCompat i MediaControllerCompat AAOS udostępnia następujące funkcje:

  • CarMediaService zapewnia scentralizowaną informację o aktualnie wybranym źródle multimediów. Służy także do wznawiania odtwarzanego wcześniej źródła multimediów po wyłączeniu i ponownym uruchomieniu samochodu.
  • car-media-common zapewnia wygodne metody tworzenia list, łączenia się i interakcji z aplikacjami multimedialnymi.

Poniżej znajdują się wytyczne dotyczące implementacji typowych poleceń interakcji głosowych.

Uzyskaj listę zainstalowanych źródeł multimediów

Źródła multimediów można wykryć za pomocą PackageManager i filtrowania usług pasujących do MediaBrowserService.SERVICE_INTERFACE . W niektórych samochodach mogą istnieć 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;
}

Należy pamiętać, że źródła multimediów mogą zostać zainstalowane lub odinstalowane w dowolnym momencie. Aby zachować dokładną listę, zaleca się zaimplementowanie instancji BroadcastReceiver dla zamierzonych akcji ACTION_PACKAGE_ADDED , ACTION_PACKAGE_CHANGED , ACTION_PACKAGE_REPLACED i ACTION_PACKAGE_REMOVED .

Połącz się z aktualnie odtwarzanym źródłem multimediów

CarMediaService udostępnia metody umożliwiające uzyskanie aktualnie wybranego źródła multimediów oraz informacji o zmianie tego źródła multimediów. Zmiany te mogą nastąpić, ponieważ użytkownik bezpośrednio wszedł w interakcję z interfejsem użytkownika lub w wyniku użycia przycisków sprzętowych w samochodzie. Z kolei biblioteka car-media-common oferuje wygodne sposoby łączenia się z danym źródłem multimediów. Oto uproszczony fragment połączenia z aktualnie 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
    }

    …
}

Steruj odtwarzaniem aktualnie odtwarzanego źródła multimediów

Dzięki podłączonemu MediaBrowserCompat łatwo jest wysyłać polecenia sterujące 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ługuj polecenia lokalnego źródła multimediów (radio, odtwarzacz CD, Bluetooth, USB)

Lokalne źródła multimediów udostępniają swoją funkcjonalność systemowi przy użyciu tych samych interfejsów API MediaSession i MediaBrowse, które opisano powyżej. Aby uwzględnić specyfikę każdego typu sprzętu, usługi MediaBrowse korzystają z określonych konwencji w celu uporządkowania informacji i poleceń multimedialnych.

Uchwyt radia

Radio MediaBrowseService można rozpoznać po filtrze intencji ACTION_PLAY_BROADCASTRADIO . Oczekuje się, że będą przestrzegać elementów sterujących odtwarzaniem i struktury przeglądania multimediów opisanych w sekcji Implementowanie radia . AAOS oferuje bibliotekę car-broadcastradio-support zawierającą stałe i metody, które pomagają producentom OEM tworzyć implementacje MediaBrowseService dla własnych usług radiowych zgodnych ze zdefiniowanym protokołem, a także zapewnia obsługę aplikacji korzystających z ich drzewa przeglądania (na przykład VIA).

Obsługuje wejście pomocnicze, dźwięk CD i nośniki USB

Nie ma domyślnej implementacji tych źródeł multimediów w ramach AOSP. Sugerowane podejście polega na:

Obsługuj Bluetooth

Treści multimedialne Bluetooth są udostępniane za pośrednictwem profilu Bluetooth AVRCP. Aby ułatwić dostęp do tej funkcjonalności, AAOS zawiera implementację MediaBrowserService i MediaSession, która wyodrębnia szczegóły komunikacji (patrz pakiety/aplikacje/Bluetooth ).

Odpowiednia struktura drzewa przeglądarki multimediów jest zdefiniowana w klasie BrowseTree . Polecenia sterujące odtwarzaniem można dostarczać podobnie do dowolnej innej aplikacji, korzystając z jej implementacji MediaSession.

Obsługuj polecenia dotyczące multimediów strumieniowych

Aby zaimplementować strumieniowe przesyłanie multimediów po stronie serwera, VIA musi sama stać się źródłem multimediów, wdrażając interfejsy API MediaBrowse i MediaSession. Zobacz Tworzenie aplikacji multimedialnych dla samochodów . Implementując te interfejsy API, aplikacja do sterowania głosowego będzie mogła (między innymi):

  • Weź udział w wyborze źródła multimediów
  • Automatyczne wznowienie po ponownym uruchomieniu samochodu
  • Zapewnij kontrolę nad odtwarzaniem i przeglądaniem za pomocą interfejsu użytkownika Media Center
  • Otrzymuj standardowe zdarzenia sprzętowego przycisku multimedialnego

Nie ma ujednoliconego sposobu interakcji ze wszystkimi aplikacjami nawigacyjnymi. Informacje na temat integracji z Mapami Google można znaleźć w artykule Mapy Google dla Androida Automotive Intents . W sprawie integracji z innymi aplikacjami skontaktuj się bezpośrednio z twórcami aplikacji. Przed uruchomieniem intencji w dowolnej aplikacji (w tym w Mapach Google) sprawdź, czy intencja może zostać rozwiązana (zobacz Żądania dotyczące intencji ). Stwarza to możliwość poinformowania użytkownika w przypadku, gdy docelowa aplikacja jest niedostępna.

Wykonuj polecenia pojazdu

Dostęp do właściwości pojazdu w trybie odczytu i zapisu zapewnia CarPropertyManager . Typy właściwości pojazdu, ich implementacja i inne szczegóły są wyjaśnione w Konfiguracje właściwości . Aby uzyskać dokładny opis właściwości obsługiwanych przez Androida, najlepiej odwołać się bezpośrednio do hardware/interfaces/automotive/vehicle/2.0/types.hal . Zdefiniowane tam wyliczenie VehicleProperty zawiera zarówno właściwości standardowe, jak i specyficzne dla dostawcy, typy danych, tryb zmiany, jednostki i definicję dostępu do odczytu/zapisu.

Aby uzyskać dostęp do tych samych stałych z poziomu Java, możesz użyć VehiclePropertyIds i klas towarzyszących. Różne właściwości mają różne uprawnienia Androida kontrolujące ich dostęp. Uprawnienia te są deklarowane w manifeście CarService , a mapowanie pomiędzy właściwościami i uprawnieniami jest opisane w dokumentacji Javadoc VehiclePropertyIds i egzekwowane w PropertyHalServiceIds .

Przeczytaj właściwość pojazdu

Poniżej znajduje się przykład pokazujący, jak odczytać prędkość 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);
    }

    ...
}

Ustaw właściwość pojazdu

Poniżej znajduje się przykład pokazujący, jak włączyć i wyłączyć przedni AC.

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"));
    }

    …
}

Wykonuj polecenia komunikacyjne

Obsługuj polecenia przesyłania wiadomości

VIA muszą obsługiwać wiadomości przychodzące zgodnie z procedurą „dotknij, aby przeczytać” opisaną w Asystencie głosowym „Dotknij, aby przeczytać” , który opcjonalnie może obsługiwać wysyłanie odpowiedzi z powrotem do nadawcy wiadomości przychodzącej. Dodatkowo VIA mogą używać SmsManager (część pakietu android.telephony ) do tworzenia i wysyłania wiadomości SMS bezpośrednio z samochodu lub przez Bluetooth.

Obsługuj polecenia połączeń

W podobny sposób VIA mogą używać TelephonyManager do wykonywania połączeń telefonicznych i dzwonienia na numer poczty głosowej użytkownika. W takich przypadkach VIA będą wchodzić w interakcję bezpośrednio ze stosem telefonicznym lub z aplikacją Car Dialer. W każdym razie aplikacja Car Dialer powinna wyświetlać użytkownikowi interfejs związany z połączeniami głosowymi.

Wykonuj inne polecenia

Listę innych możliwych punktów integracji VIA z systemem znajdziesz na liście znanych intencji Androida . Wiele poleceń użytkownika można rozwiązać po stronie serwera (na przykład czytanie e-maili użytkowników i wydarzeń w kalendarzu) i nie wymagają one żadnej interakcji z systemem poza samą interakcją głosową.

Wciągające akcje (wyświetlanie treści wizualnych)

Tam, gdzie usprawnia to działania użytkownika lub jego zrozumienie, VIA może zapewnić dodatkową treść wizualną na ekranie samochodu. Aby zminimalizować rozpraszanie kierowcy, staraj się, aby takie treści były proste, krótkie i przydatne. Aby uzyskać szczegółowe informacje na temat wytycznych dotyczących interfejsu użytkownika/UX dotyczących działań immersyjnych, zobacz Wstępnie załadowani asystenci: wskazówki dotyczące UX .

Aby umożliwić dostosowanie i spójność z resztą projektu jednostki głównej (HU), VIA powinny używać komponentów biblioteki Car UI dla większości elementów interfejsu użytkownika. Aby uzyskać szczegółowe informacje, zobacz Dostosowywanie .