Erfülle Befehle

Auf dieser Seite wird beschrieben, wie Sie Befehle mit Sprachinteraktion ausführen.

Erfüllen Sie Medienbefehle

Medienbezogene Befehle können in drei verschiedene Gruppen unterteilt werden:

  • Externe Medienquellen (z. B. Spotify, installiert in AAOS).
  • Backend-Medienquellen (z. B. über VIA gestreamte Musik).
  • Lokale Medienquellen (z. B. Autoradio).

Behandeln Sie Befehle für externe Medienquellen

Externe Medienquellen werden als Android-Apps definiert, die die APIs MediaSessionCompat und MediaBrowseCompat unterstützen (eine ausführliche Erläuterung zur Verwendung dieser APIs finden Sie unter Erstellen von Medien-Apps für Autos ).

Wichtig: Damit eine Assistenten-App eine Verbindung zum MediaBrowseService aller im System installierten Medien-Apps herstellen kann, muss sie:

  1. Muss systemsigniert installiert werden (siehe Richtlinien zur Medienanwendungsentwicklung für AAOS und den Beispiel- PackageValidator Code).
  2. Halten Sie die systemprivilegierte Berechtigung android.permission.MEDIA_CONTENT_CONTROL (siehe Erteilen systemprivilegierter Berechtigungen ).

Zusätzlich zu MediaBrowserCompat und MediaControllerCompat bietet AAOS Folgendes:

  • CarMediaService stellt zentralisierte Informationen zur aktuell ausgewählten Medienquelle bereit. Dies wird auch verwendet, um eine zuvor wiedergegebene Medienquelle nach dem Herunterfahren und Neustarten des Fahrzeugs fortzusetzen.
  • car-media-common bietet praktische Methoden zum Auflisten, Verbinden und Interagieren mit Medien-Apps.

Nachfolgend finden Sie Richtlinien speziell für die Implementierung allgemeiner Sprachinteraktionsbefehle.

Rufen Sie eine Liste der installierten Medienquellen ab

Medienquellen können mithilfe von PackageManager erkannt werden und nach Diensten gefiltert werden, die dem MediaBrowserService.SERVICE_INTERFACE entsprechen. In einigen Autos gibt es möglicherweise spezielle Implementierungen von Medienbrowserdiensten, die ausgeschlossen werden sollten. Hier ist ein Beispiel für diese Logik:

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

Beachten Sie, dass Medienquellen jederzeit installiert oder deinstalliert werden können. Um eine genaue Liste zu verwalten, wird empfohlen, eine BroadcastReceiver Instanz für die Intent-Aktionen ACTION_PACKAGE_ADDED , ACTION_PACKAGE_CHANGED , ACTION_PACKAGE_REPLACED und ACTION_PACKAGE_REMOVED zu implementieren.

Stellen Sie eine Verbindung zur aktuell wiedergegebenen Medienquelle her

CarMediaService stellt Methoden bereit, um die aktuell ausgewählte Medienquelle abzurufen und wenn sich diese Medienquelle ändert. Diese Änderungen können auftreten, weil der Benutzer direkt mit der Benutzeroberfläche interagiert oder Hardwaretasten im Auto verwendet. Andererseits bietet die Car-Media-Common-Bibliothek bequeme Möglichkeiten, eine Verbindung zu einer bestimmten Medienquelle herzustellen. Hier ist ein vereinfachter Ausschnitt zum Herstellen einer Verbindung mit der aktuell ausgewählten Medien-App:

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
    }

    …
}

Steuern Sie die Wiedergabe der aktuell wiedergegebenen Medienquelle

Mit einem verbundenen MediaBrowserCompat ist es einfach , Transportsteuerungsbefehle an die Ziel-App zu senden. Hier ist ein vereinfachtes Beispiel:

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

    …
}

Behandeln Sie lokale Medienquellenbefehle (Radio, CD-Player, Bluetooth, USB).

Lokale Medienquellen stellen ihre Funktionalität dem System über dieselben MediaSession- und MediaBrowse-APIs zur Verfügung, die oben beschrieben wurden. Um den Besonderheiten jedes Hardwaretyps gerecht zu werden, verwenden diese MediaBrowse-Dienste bestimmte Konventionen, um ihre Informationen und Medienbefehle zu organisieren.

Griffradio

Radio MediaBrowseService kann durch den Absichtsfilter ACTION_PLAY_BROADCASTRADIO identifiziert werden. Von ihnen wird erwartet, dass sie den Wiedergabesteuerungen und der Mediensuchstruktur folgen, die unter „Radio implementieren“ beschrieben sind. AAOS bietet die Bibliothek car-broadcastradio-support mit Konstanten und Methoden, die OEMs bei der Erstellung von MediaBrowseService-Implementierungen für ihre eigenen Radiodienste unterstützen, die dem definierten Protokoll folgen, und bietet Unterstützung für Apps, die ihren Suchbaum nutzen (z. B. VIAs).

Behandelt Aux-Eingang, CD-Audio und USB-Medien

Es gibt keine Standardimplementierung dieser Medienquellen als Teil von AOSP. Der vorgeschlagene Ansatz ist:

Behandeln Sie Bluetooth

Bluetooth-Medieninhalte werden über das AVRCP-Bluetooth-Profil verfügbar gemacht. Um den Zugriff auf diese Funktionalität zu erleichtern, enthält AAOS eine MediaBrowserService- und MediaSession-Implementierung, die die Kommunikationsdetails abstrahiert (siehe Pakete/Apps/Bluetooth ).

Die jeweilige Baumstruktur des Medienbrowsers wird in der Klasse BrowseTree definiert. Befehle zur Wiedergabesteuerung können mithilfe der MediaSession-Implementierung ähnlich wie bei jeder anderen App bereitgestellt werden.

Behandeln Sie Streaming-Medienbefehle

Um serverseitiges Medienstreaming zu implementieren, muss die VIA selbst zu einer Medienquelle werden und MediaBrowse und MediaSession API implementieren. Siehe Erstellen von Medien-Apps für Autos . Durch die Implementierung dieser APIs wäre eine Sprachsteuerungs-App (unter anderem) in der Lage:

  • Beteiligen Sie sich nahtlos an der Auswahl der Medienquelle
  • Wird nach dem Neustart des Fahrzeugs automatisch fortgesetzt
  • Bieten Sie Wiedergabe- und Browsing-Steuerung über die Media Center-Benutzeroberfläche
  • Empfangen Sie Standard-Hardware-Medientastenereignisse

Es gibt keine standardisierte Art der Interaktion mit allen Navigations-Apps. Informationen zur Integration mit Google Maps finden Sie unter Google Maps für Android Automotive Intents . Für Integrationen mit anderen Apps wenden Sie sich direkt an die App-Entwickler. Bevor Sie eine Absicht für eine App (einschließlich Google Maps) starten, überprüfen Sie, ob die Absicht aufgelöst werden kann (siehe Absichtsanfragen ). Dadurch besteht die Möglichkeit, den Benutzer zu informieren, falls die Ziel-App nicht verfügbar ist.

Fahrzeugbefehle ausführen

Der Lese- und Schreibzugriff auf Fahrzeugeigenschaften erfolgt über CarPropertyManager . Fahrzeugeigenschaftentypen, ihre Implementierung und andere Details werden in Eigenschaftskonfigurationen erläutert. Eine genaue Beschreibung der von Android unterstützten Eigenschaften finden Sie am besten direkt unter hardware/interfaces/automotive/vehicle/2.0/types.hal . Die dort definierte VehicleProperty- Enumeration enthält sowohl Standard- als auch herstellerspezifische Eigenschaften, Datentypen, Änderungsmodus, Einheiten und Lese-/Schreibzugriffsdefinition.

Um von Java aus auf dieselben Konstanten zuzugreifen, können Sie VehiclePropertyIds und die dazugehörigen Klassen verwenden. Verschiedene Eigenschaften verfügen über unterschiedliche Android-Berechtigungen, die ihren Zugriff steuern. Diese Berechtigungen werden im CarService-Manifest deklariert und die Zuordnung zwischen Eigenschaften und Berechtigungen wird im Javadoc VehiclePropertyIds beschrieben und in PropertyHalServiceIds erzwungen.

Lesen Sie eine Fahrzeugeigenschaft

Das folgende Beispiel zeigt, wie die Fahrzeuggeschwindigkeit abgelesen werden kann:

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

    ...
}

Legen Sie eine Fahrzeugeigenschaft fest

Das folgende Beispiel zeigt, wie die vordere Klimaanlage ein- und ausgeschaltet wird.

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

    …
}

Kommunikationsbefehle ausführen

Behandeln Sie Messaging-Befehle

VIAs müssen eingehende Nachrichten nach dem im Sprachassistenten „Tap-to-Read“ beschriebenen „Tap-to-Read “-Ablauf verarbeiten, der optional das Zurücksenden von Antworten an den Absender der eingehenden Nachricht übernehmen kann. Darüber hinaus können VIAs SmsManager (Teil des android.telephony Pakets) verwenden, um SMS-Nachrichten direkt aus dem Auto oder über Bluetooth zu verfassen und zu versenden.

Behandeln Sie Anrufbefehle

Auf ähnliche Weise können VIAs TelephonyManager verwenden, um Telefonanrufe zu tätigen und die Voicemail-Nummer des Benutzers anzurufen. In diesen Fällen interagieren VIAs direkt mit dem Telefonie-Stack oder mit der Car Dialer-App. In jedem Fall sollte die Car Dialer-App diejenige sein, die dem Benutzer eine Benutzeroberfläche für Sprachanrufe anzeigt.

Erfülle andere Befehle

Eine Liste weiterer möglicher Integrationspunkte zwischen VIA und dem System finden Sie in der Liste bekannter Android-Intents . Viele Benutzerbefehle können serverseitig aufgelöst werden (z. B. das Lesen von Benutzer-E-Mails und Kalenderereignissen) und erfordern außer der Sprachinteraktion selbst keine Interaktionen mit dem System.

Immersive Aktionen (visuelle Inhalte anzeigen)

Wo es die Aktionen oder das Verständnis des Benutzers verbessert, kann ein VIA zusätzliche visuelle Inhalte auf dem Autobildschirm bereitstellen. Halten Sie solche Inhalte einfach, kurz und umsetzbar, um die Ablenkung des Fahrers zu minimieren. Einzelheiten zu UI/UX-Richtlinien für immersive Aktionen finden Sie unter Vorinstallierte Assistenten: UX-Anleitung .

Um eine individuelle Anpassung und Konsistenz mit dem restlichen Design der Head Unit (HU) zu ermöglichen, sollten VIAs für die meisten UI-Elemente Komponenten der Car UI Library verwenden. Einzelheiten finden Sie unter Anpassung .