Befehle ausführen

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

Medienbefehle ausführen

Medienbezogene Befehle lassen sich in drei verschiedene Gruppen unterteilen:

  • Externe Medienquellen (z. B. Spotify, das in AAOS installiert ist)
  • Back-End-Medienquellen (z. B. Musik, die über die VIA gestreamt wird)
  • Lokale Medienquellen (z. B. Autoradio)

Befehle für externe Medienquellen verarbeiten

Externe Medienquellen sind Android-Apps, die die MediaSessionCompat- und MediaBrowseCompat-APIs unterstützen. Eine ausführliche Erklärung zur Verwendung dieser APIs finden Sie unter Medien-Apps für Autos entwickeln.

Wichtig:Damit eine Assistant-App eine Verbindung zu den MediaBrowseService der im System installierten Medien-Apps herstellen kann, muss sie folgende Anforderungen erfüllen:

  1. Sie müssen als systemsigniert installiert werden (siehe Richtlinien für die Entwicklung von Medienanwendungen für AAOS und den Beispiel-PackageValidator-Code).
  2. Sie haben die Berechtigung android.permission.MEDIA_CONTENT_CONTROL (siehe Systemberechtigungen gewähren).

Zusätzlich zu MediaBrowserCompat und MediaControllerCompat bietet AAOS Folgendes:

  • CarMediaService bietet zentrale Informationen zur aktuell ausgewählten Medienquelle. Diese Funktion wird auch verwendet, um die Wiedergabe einer zuvor wiedergegebenen Medienquelle nach dem Aus- und Wiedereinschalten des Fahrzeugs fortzusetzen.
  • car-media-common bietet praktische Methoden zum Auflisten, Verbinden und Interagieren mit Medien-Apps.

Im Folgenden finden Sie Richtlinien speziell für die Implementierung gängiger Befehle für die Sprachinteraktion.

Liste der installierten Medienquellen abrufen

Medienquellen können mit PackageManager erkannt und nach Diensten gefiltert werden, die mit MediaBrowserService.SERVICE_INTERFACE übereinstimmen. In einigen Autos gibt es möglicherweise spezielle Implementierungen von Medienbrowserdiensten, die ausgeschlossen werden sollten. Hier 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;
}

Medienquellen können jederzeit installiert oder deinstalliert werden. Um eine korrekte Liste zu erhalten, 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.

Verbindung zur aktuell wiedergegebenen Medienquelle herstellen

CarMediaService bietet Methoden, um die aktuell ausgewählte Medienquelle abzurufen und zu erfahren, wann sich diese Medienquelle ändert. Diese Änderungen können auftreten, wenn der Nutzer direkt mit der Benutzeroberfläche interagiert oder Hardwareschaltflächen im Auto verwendet. Die Bibliothek „car-media-common“ bietet hingegen praktische Möglichkeiten, eine Verbindung zu einer bestimmten Medienquelle herzustellen. Hier ist ein vereinfachtes Snippet 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
    }

    
}

Wiedergabe der aktuell wiedergegebenen Medienquelle steuern

Wenn eine MediaBrowserCompat verbunden ist, können Sie ganz einfach Transportsteuerungsbefehle an die Ziel-App senden. Hier 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;
    }

    
}

Befehle für lokale Medienquellen (Radio, CD-Player, Bluetooth, USB) verarbeiten

Lokale Medienquellen stellen ihre Funktionen dem System mit den oben beschriebenen MediaSession- und MediaBrowse-APIs zur Verfügung. Um den Besonderheiten der einzelnen Hardwaretypen gerecht zu werden, verwenden diese MediaBrowse-Dienste bestimmte Konventionen, um ihre Informationen und Medienbefehle zu organisieren.

Radio steuern

Der Radio MediaBrowseService kann über den Intent-Filter ACTION_PLAY_BROADCASTRADIO identifiziert werden. Sie müssen die Wiedergabesteuerung und die Mediensuchstruktur einhalten, die unter Radio implementieren beschrieben sind. AAOS bietet die Bibliothek car-broadcastradio-support mit Konstanten und Methoden, mit denen OEMs MediaBrowseService-Implementierungen für ihre eigenen Radiodienste erstellen können, die dem definierten Protokoll entsprechen. Außerdem bietet sie Unterstützung für Apps, die ihren Navigationsbaum verwenden (z. B. VIAs).

AUX-Eingang, CD-Audio und USB-Medien verarbeiten

Diese Medienquellen sind nicht standardmäßig in AOSP implementiert. Wir empfehlen Folgendes:

  • OEMs bitten, für jeden von ihnen Mediendienste zu implementieren. Weitere Informationen finden Sie unter Medien-Apps für Autos entwickeln.
  • Diese MediaBrowseService-Implementierungen werden in den Intent-Aktionen erkannt und beantwortet, die unter Allgemeine Wiedergabe-Intents definiert sind.
  • Diese Dienste stellen einen Navigationsbaum gemäß den unter Andere Quellentypen beschriebenen Richtlinien bereit.

Bluetooth-Verbindungen verwalten

Bluetooth-Medieninhalte werden über das Bluetooth-Profil AVRCP freigegeben. Um den Zugriff auf diese Funktion zu erleichtern, enthält AAOS eine MediaBrowserService- und MediaSession-Implementierung, die die Kommunikationsdetails abstrahiert (siehe packages/apps/Bluetooth).

Die entsprechende Medienbrowser-Baumstruktur wird in der Klasse BrowseTree definiert. Befehle zur Wiedergabesteuerung können ähnlich wie bei jeder anderen App mithilfe der MediaSession-Implementierung gesendet werden.

Befehle für Streamingmedien verarbeiten

Um serverseitiges Medienstreaming zu implementieren, muss die VIA selbst eine Medienquelle werden und die MediaBrowse- und MediaSession API implementieren. Weitere Informationen finden Sie unter Medien-Apps für Autos entwickeln. Durch die Implementierung dieser APIs kann eine Sprachsteuerungs-App unter anderem:

  • Nahtlose Teilnahme an der Auswahl der Mediaquelle
  • Nach dem Neustart des Autos automatisch fortgesetzt werden
  • Wiedergabe und Suche über die Media Center-Benutzeroberfläche steuern
  • Standardereignisse der Hardware-Medienschaltfläche empfangen

Es gibt keine standardisierte Möglichkeit, mit allen Navigations-Apps zu interagieren. Informationen zur Integration mit Google Maps finden Sie unter Google Maps for Android Automotive Intents. Bei Integrationen mit anderen Apps wenden Sie sich bitte direkt an die App-Entwickler. Bevor Sie eine Intent-Anfrage an eine App senden (einschließlich Google Maps), prüfen Sie, ob der Intent aufgelöst werden kann (siehe Intent-Anfragen). So können Sie den Nutzer informieren, falls die Ziel-App nicht verfügbar ist.

Fahrzeugbefehle ausführen

Über CarPropertyManager können Sie Lese- und Schreibzugriff auf Fahrzeugeigenschaften erhalten. Die Fahrzeugeigenschaftstypen, ihre Implementierung und weitere Details werden unter Property-Konfigurationen erläutert. Eine genaue Beschreibung der von Android unterstützten Properties finden Sie direkt unter hardware/interfaces/automotive/vehicle/2.0/types.hal. Das dort definierte Enum VehicleProperty enthält sowohl standard- als auch anbieterspezifische Eigenschaften, Datentypen, Änderungsmodus, Einheiten und Definitionen für Lese-/Schreibzugriff.

Wenn Sie in Java auf diese Konstanten zugreifen möchten, können Sie VehiclePropertyIds und die zugehörigen Klassen verwenden. Für verschiedene Properties gelten unterschiedliche Android-Berechtigungen, die den Zugriff steuern. Diese Berechtigungen werden im CarService-Manifest deklariert. Die Zuordnung zwischen Properties und Berechtigungen wird in der VehiclePropertyIds-Javadoc beschrieben und in PropertyHalServiceIds erzwungen.

Fahrzeugeigenschaft lesen

Im folgenden Beispiel wird gezeigt, wie die Fahrzeuggeschwindigkeit gelesen wird:

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

    ...
}

Fahrzeugeigenschaft festlegen

Im folgenden Beispiel wird gezeigt, 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

Umgang mit Befehlen für Nachrichten

Sprachassistenten müssen eingehende Nachrichten gemäß dem Ablauf „Zum Lesen antippen“ verarbeiten, der unter Zum Lesen antippen beschrieben ist. Optional kann auch das Senden von Antworten an den Absender der eingehenden Nachricht verarbeitet werden. Darüber hinaus können VIAs SmsManager (Teil des Pakets android.telephony) verwenden, um SMS direkt über das Auto oder über Bluetooth zu verfassen und zu senden.

Anrufbefehle verarbeiten

In ähnlicher Weise können VIAs TelephonyManager verwenden, um Telefonanrufe zu starten und die Mailboxnummer des Nutzers anzurufen. In diesen Fällen interagieren VIAs direkt mit dem Telefoniestack oder mit der Car Dialer App. In jedem Fall sollte die Car Dialer App die Benutzeroberfläche für Sprachanrufe anzeigen.

Andere Befehle ausführen

Eine Liste weiterer möglicher Integrationspunkte zwischen der VIA und dem System findest du in der Liste der bekannten Android-Intents. Viele Nutzerbefehle können serverseitig verarbeitet werden (z. B. das Lesen von E-Mails und Kalenderterminen von Nutzern) und erfordern keine Interaktionen mit dem System, abgesehen von der Sprachinteraktion selbst.

Immersive Aktionen (visuelle Inhalte anzeigen)

Wenn sie die Nutzeraktionen oder das Verständnis verbessern, kann eine visuelle Zusatzinformation auf dem Autodisplay angezeigt werden. Halten Sie solche Inhalte einfach, kurz und umsetzbar, um Ablenkungen für Fahrer zu minimieren. Weitere Informationen zu UI/UX-Richtlinien für immersive Aktionen finden Sie unter Vorinstallierte Assistenten: UX-Richtlinien.

Für eine Anpassung und Einheitlichkeit mit dem Rest des Designs der Headunit (HU) sollten VIAs für die meisten UI-Elemente Komponenten aus der Car UI Library verwenden. Weitere Informationen finden Sie unter Anpassung.