Befehle ausführen

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

Media-Befehle ausführen

Media-bezogene Befehle lassen sich in drei verschiedene Gruppen unterteilen:

  • Externe Medienquellen wie Spotify, das in AAOS installiert ist.
  • Backend-Media-Quellen (z. B. Musik, die über den VIA gestreamt wird).
  • Lokale Medienquellen wie das Autoradio.

Befehle für externe Medienquellen verarbeiten

Externe Media-Quellen werden als Android-Apps definiert, die die APIs MediaSessionCompat und MediaBrowseCompat unterstützen. Eine detaillierte Erklärung zur Verwendung dieser APIs finden Sie unter Media-Apps für Autos entwickeln.

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

  1. Muss als systemsigniert installiert werden (siehe Richtlinien für die Entwicklung von Media-Apps für AAOS und den PackageValidator-Beispielcode).
  2. Sie haben die android.permission.MEDIA_CONTENT_CONTROL-Berechtigung mit Systemprivilegien (siehe Berechtigungen mit Systemprivilegien erteilen).

Zusätzlich zu MediaBrowserCompat und MediaControllerCompat bietet AAOS Folgendes:

  • CarMediaService bietet zentrale Informationen zur aktuell ausgewählten Medienquelle. Diese Funktion wird auch verwendet, um eine zuvor wiedergegebene Media-Quelle nach dem Herunterfahren und Neustarten des Fahrzeugs fortzusetzen.
  • car-media-common bietet praktische Methoden zum Auflisten, Verbinden und Interagieren mit Media-Apps.

Im Folgenden finden Sie Richtlinien für die Implementierung häufig verwendeter Sprachinteraktionsbefehle.

Liste der installierten Media-Quellen abrufen

Media-Quellen können mit PackageManager erkannt werden. Filtern Sie dazu nach Diensten, die mit MediaBrowserService.SERVICE_INTERFACE übereinstimmen. In einigen Autos gibt es möglicherweise spezielle Implementierungen des Media Browser-Dienstes, 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;
}

Mediendatenquellen können jederzeit installiert oder deinstalliert werden. Damit die Liste korrekt bleibt, empfiehlt es sich, eine BroadcastReceiver-Instanz für die Intent-Aktionen ACTION_PACKAGE_ADDED, ACTION_PACKAGE_CHANGED, ACTION_PACKAGE_REPLACED und ACTION_PACKAGE_REMOVED zu implementieren.

Mit der aktuell wiedergegebenen Medienquelle verbinden

CarMediaService bietet Methoden zum Abrufen der aktuell ausgewählten Media-Quelle und zum Erkennen von Änderungen an dieser Media-Quelle. Diese Änderungen können auftreten, weil der Nutzer direkt mit der Benutzeroberfläche interagiert hat oder weil er Hardwaretasten im Auto verwendet hat. Die Bibliothek „car-media-common“ bietet dagegen praktische Möglichkeiten, eine Verbindung zu einer bestimmten Medienquelle herzustellen. Hier ist ein vereinfachtes Snippet, das zeigt, wie du eine Verbindung zur aktuell ausgewählten Media-App herstellst:

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

Mit einem verbundenen MediaBrowserCompat ist es ganz einfach, Befehle zur Transportsteuerung 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;
    }

    
}

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

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

Radio bedienen

Der Radio MediaBrowseService kann anhand des Intent-Filters ACTION_PLAY_BROADCASTRADIO identifiziert werden. Sie müssen die in Radiosender implementieren beschriebenen Wiedergabesteuerelemente und die Struktur für das Durchsuchen von Medien verwenden. AAOS bietet die Bibliothek car-broadcastradio-support mit Konstanten und Methoden, die OEMs dabei helfen, MediaBrowseService-Implementierungen für ihre eigenen Radiodienste zu erstellen, die dem definierten Protokoll entsprechen. Außerdem wird Unterstützung für Apps bereitgestellt, die ihren Browsing-Baum nutzen (z. B. VIAs).

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

Es gibt keine Standardimplementierung dieser Media-Quellen als Teil von AOSP. So gehen Sie vor:

  • Lassen Sie OEMs Medienservices für jedes Gerät implementieren. Weitere Informationen finden Sie unter Medien-Apps für Autos entwickeln.
  • Diese MediaBrowseService-Implementierungen werden in den Intent-Aktionen, die unter Allgemeine Play-Intents definiert sind, erkannt und darauf wird reagiert.
  • Diese Dienste würden einen Browse-Baum gemäß den Richtlinien unter Other source types (Andere Quelltypen) bereitstellen.

Bluetooth verwalten

Bluetooth-Medieninhalte werden über das Bluetooth-Profil AVRCP bereitgestellt. 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 über die MediaSession-Implementierung übermittelt werden.

Streamingmediabefehle verarbeiten

Um serverseitiges Media-Streaming zu implementieren, muss das VIA selbst zu einer Media-Quelle werden, die die MediaBrowse- und MediaSession-API implementiert. Weitere Informationen finden Sie unter Medien-Apps für Autos entwickeln. Durch die Implementierung dieser APIs kann eine Sprachsteuerungs-App unter anderem Folgendes tun:

  • Nahtlose Teilnahme an der Auswahl der Media-Quelle
  • Nach dem Neustart des Autos automatisch fortgesetzt werden
  • Wiedergabe und Browsing über die Media Center-Benutzeroberfläche steuern
  • Standardmäßige Hardware-Media-Button-Ereignisse empfangen

Es gibt keine standardisierte Methode für die Interaktion mit allen Navigations-Apps. 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 einen Intent für eine beliebige App (einschließlich Google Maps) starten, prüfen Sie, ob der Intent aufgelöst werden kann (siehe Google Maps Intents). So können Sie den Nutzer informieren, falls die Ziel-App nicht verfügbar ist.

Fahrzeugbefehle ausführen

Der Zugriff auf Fahrzeugeigenschaften zum Lesen und Schreiben erfolgt über CarPropertyManager. Fahrzeugeigenschaftstypen, ihre Implementierung und andere Details werden unter Eigenschaftskonfigurationen beschrieben. Eine genaue Beschreibung der von Android unterstützten Eigenschaften finden Sie am besten direkt unter hardware/interfaces/automotive/vehicle/2.0/types.hal. Das dort definierte Enum VehicleProperty enthält sowohl Standard- als auch anbieterspezifische Attribute, Datentypen, Änderungsmodus, Einheiten und Definitionen für Lese-/Schreibzugriff.

Wenn Sie von Java aus auf diese Konstanten zugreifen möchten, können Sie VehiclePropertyIds und die zugehörigen Klassen verwenden. Für den Zugriff auf die verschiedenen Eigenschaften sind unterschiedliche Android-Berechtigungen erforderlich. Diese Berechtigungen werden im CarService-Manifest deklariert. Die Zuordnung zwischen Eigenschaften und Berechtigungen wird im Javadoc zu VehiclePropertyIds beschrieben und in PropertyHalServiceIds erzwungen.

Fahrzeugeigenschaft lesen

Das folgende Beispiel zeigt, 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

Das folgende Beispiel zeigt, wie die Klimaanlage vorne 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

Messaging-Befehle verarbeiten

VIAs müssen eingehende Nachrichten gemäß dem unter Sprachassistent – Tap-to-Read beschriebenen Ablauf verarbeiten. Optional können sie auch Antworten an den Absender der eingehenden Nachricht senden. Außerdem können VIAs SmsManager (Teil des android.telephony-Pakets) verwenden, um SMS-Nachrichten direkt über das Auto oder über Bluetooth zu verfassen und zu senden.

Anruf-Befehle verarbeiten

Auf ähnliche Weise können VIAs TelephonyManager verwenden, um Telefonanrufe zu tätigen und die Mailboxnummer des Nutzers anzurufen. In diesen Fällen interagieren die VIAs direkt mit dem Telefonie-Stack oder mit der Car Dialer App. In jedem Fall sollte die Car Dialer App die Benutzeroberfläche für Sprachanrufe für den Nutzer anzeigen.

Andere Befehle ausführen

Eine Liste anderer möglicher Integrationspunkte zwischen dem VIA und dem System finden Sie in der Liste der bekannten Android-Intents. Viele Nutzerbefehle können serverseitig ausgeführt werden, z. B. das Lesen von E‑Mails und Kalenderterminen. Dafür sind keine Interaktionen mit dem System erforderlich, die über die Sprachinteraktion hinausgehen.

Immersive Aktionen (visuelle Inhalte anzeigen)

Wenn es Nutzeraktionen oder das Verständnis verbessert, kann ein VIA zusätzliche visuelle Inhalte auf dem Display des Autos bereitstellen. Um Ablenkungen für den Fahrer zu minimieren, sollten solche Inhalte einfach, kurz und umsetzbar sein. Weitere Informationen zu UI/UX-Richtlinien für immersive Aktionen finden Sie unter Vorinstallierte Assistenten: UX-Leitfaden.

Damit die VIA-Benutzeroberfläche an das Design der Head-Unit angepasst werden kann und einheitlich aussieht, sollten für die meisten UI-Elemente Komponenten der Car UI-Bibliothek verwendet werden. Weitere Informationen finden Sie unter Anpassung.