Memenuhi Perintah

Pelajari cara memenuhi jenis perintah ini dengan interaksi suara:

Memenuhi Perintah Media

Perintah terkait media dapat dibagi menjadi tiga kelompok berbeda:

  • Sumber media eksternal (seperti Spotify yang diinstal di AAOS).
  • Sumber media backend (seperti musik yang dialirkan melalui VIA).
  • Sumber media lokal (seperti radio mobil).

Menangani Perintah Sumber Media Eksternal

Sumber media eksternal didefinisikan sebagai aplikasi Android yang mendukung MediaSession dan MediaBrowse API (lihat Membuat aplikasi media untuk mobil tentang penjelasan mendetail tentang penggunaan API ini).

Penting. Agar aplikasi asisten dapat terhubung ke MediaBrowseService dari semua aplikasi media yang terinstal di sistem, aplikasi tersebut harus:

  1. Diinstal sebagai sistem yang ditandatangani (lihat pedoman Pengembangan Aplikasi Media untuk AAOS dan contoh kode PackageValidator ).
  2. Tahan android.permission.MEDIA_CONTENT_CONTROL izin sistem-hak istimewa (lihat Izin Sistem-Hak Istimewa ).

Selain MediaBrowserCompat dan MediaControllerCompat , AAOS menyediakan hal berikut:

  • CarMediaService menyediakan informasi terpusat pada sumber media yang dipilih saat ini. Ini juga digunakan untuk melanjutkan sumber media yang diputar sebelumnya setelah shutdown-restart mobil.
  • car-media-common menyediakan metode yang mudah untuk membuat daftar, menghubungkan, dan berinteraksi dengan aplikasi media.

Di bawah ini adalah panduan khusus untuk penerapan perintah interaksi suara yang umum.

Dapatkan Daftar Sumber Media yang Diinstal

Sumber media dapat dideteksi menggunakan PackageManager , dan memfilter layanan yang cocok dengan MediaBrowserService.SERVICE_INTERFACE . Di beberapa mobil mungkin ada beberapa implementasi layanan browser media khusus, yang harus dikecualikan. Di bawah ini adalah contoh dari logika ini:

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

Ketahuilah bahwa sumber media mungkin dipasang atau dicopot kapan saja. Untuk mempertahankan daftar yang akurat, direkomendasikan untuk menerapkan BroadcastReceiver untuk tindakan maksud berikut: ACTION_PACKAGE_ADDED , ACTION_PACKAGE_CHANGED , ACTION_PACKAGE_REPLACED , ACTION_PACKAGE_REMOVED .

Hubungkan ke Sumber Media yang Sedang Diputar

CarMediaService menyediakan metode untuk mendapatkan sumber media yang dipilih saat ini, dan ketika sumber media ini berubah. Perubahan ini bisa terjadi karena pengguna berinteraksi dengan UI secara langsung, atau karena penggunaan tombol perangkat keras di dalam mobil. Di sisi lain, perpustakaan umum-media-mobil menawarkan cara mudah untuk terhubung ke sumber media tertentu. Berikut adalah cuplikan sederhana tentang cara menghubungkan ke aplikasi media yang dipilih saat ini:

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
    }

    …
}

Kontrol Pemutaran Sumber Media yang Sedang Diputar

Dengan MediaBrowserCompat yang terhubung, sangat mudah untuk mengirim perintah "kontrol transportasi" ke aplikasi target. Berikut adalah contoh yang disederhanakan:

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

    …
}

Menangani Perintah Sumber Media Lokal (Radio, Pemutar CD, Bluetooth, USB)

Sumber media lokal mengekspos fungsionalitasnya ke sistem menggunakan MediaSession dan MediaBrowse API yang sama seperti yang dijelaskan di atas. Untuk mengakomodasi kekhasan setiap jenis perangkat keras, layanan MediaBrowse ini menggunakan konvensi khusus untuk mengatur informasi dan perintah medianya.

Menangani Radio

Radio MediaBrowseService dapat diidentifikasi dengan filter maksud ACTION_PLAY_BROADCASTRADIO . Mereka diharapkan mengikuti kontrol pemutaran dan struktur penelusuran media yang dijelaskan di sini: Menerapkan Radio dengan Media . AAOS menawarkan pustaka dukungan radio siaran mobil yang berisi konstanta dan metode untuk membantu OEM membuat implementasi MediaBrowseService untuk layanan radio mereka sendiri yang mengikuti protokol yang ditentukan, dan menyediakan dukungan untuk aplikasi yang menggunakan pohon penelusuran mereka (misalnya, VIA).

Menangani Input Tambahan, Audio CD, dan Media USB

Tidak ada implementasi default dari sumber media ini sebagai bagian dari AOSP. Pendekatan yang disarankan adalah:

  • Mintalah OEM mengimplementasikan layanan media untuk masing-masing dari mereka. Untuk detailnya, lihat Membuat aplikasi media untuk mobil .
  • Implementasi MediaBrowseService ini akan diidentifikasi dan ditanggapi dalam tindakan Intent yang ditentukan di maksud General Play .
  • Layanan ini akan mengekspos pohon penelusuran mengikuti panduan yang dijelaskan di Jenis sumber lain .

Menangani Bluetooth

Konten media Bluetooth diekspos melalui profil Bluetooth AVRCP. Untuk memfasilitasi akses ke fungsi ini, AAOS menyertakan implementasi MediaBrowserService dan MediaSession yang mengabstraksi detail komunikasi (lihat package/apps/Bluetooth ).

Struktur pohon browser media masing-masing didefinisikan di kelas BrowseTree . Perintah kontrol pemutaran dapat dikirimkan dengan cara yang sama ke aplikasi lain, dengan menggunakan implementasi MediaSession-nya.

Menangani Perintah Media Streaming

Untuk mengimplementasikan streaming media sisi server, VIA harus menjadi sumber media itu sendiri, mengimplementasikan MediaBrowse dan MediaSession API. Lihat Membangun aplikasi media untuk mobil . Dengan menerapkan API ini, aplikasi kontrol suara akan dapat (antara lain):

  • Berpartisipasi dengan mulus dalam pemilihan sumber media
  • Dilanjutkan secara otomatis setelah restart mobil
  • Berikan kontrol pemutaran dan penelusuran menggunakan Media Center UI
  • Terima acara tombol media perangkat keras standar

Tidak ada cara standar untuk berinteraksi dengan semua aplikasi navigasi. Untuk integrasi dengan Google Maps, lihat Google Maps untuk Android Automotive Intents . Untuk integrasi dengan aplikasi lain, hubungi pengembang aplikasi secara langsung. Sebelum meluncurkan maksud ke aplikasi apa pun (termasuk Google Maps), verifikasi bahwa maksud tersebut dapat diselesaikan (lihat Permintaan maksud ). Ini menciptakan peluang untuk memberi tahu pengguna jika aplikasi target tidak tersedia.

Memenuhi Perintah Kendaraan

Akses ke properti kendaraan untuk membaca dan menulis disediakan melalui CarPropertyManager . Jenis properti kendaraan, implementasinya dan detail lainnya dijelaskan di sini: AOSP/Develop/Automotive - Vehicle Properties . Untuk deskripsi akurat tentang properti yang didukung oleh Android, yang terbaik adalah merujuk langsung ke hardware/interfaces/automotive/vehicle/2.0/types.hal . Enum VehicleProperty yang didefinisikan di sana berisi properti standar dan khusus vendor, tipe data, mode perubahan, unit, dan definisi akses baca/tulis.

Untuk mengakses konstanta yang sama ini dari Java, Anda dapat menggunakan VehiclePropertyIds dan kelas pendampingnya. Properti yang berbeda memiliki izin Android yang berbeda yang mengontrol aksesnya. Izin ini dideklarasikan dalam manifes CarService , dan pemetaan antara properti dan izin yang dijelaskan dalam Javadoc VehiclePropertyIds dan diterapkan di PropertyHalServiceIds .

Membaca Properti Kendaraan

Berikut ini adalah contoh yang menunjukkan cara membaca kecepatan kendaraan.

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

    ...
}

Mengatur Properti Kendaraan

Berikut ini adalah contoh yang menunjukkan cara menghidupkan dan mematikan AC depan.

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

    …
}

Memenuhi Perintah Komunikasi

Menangani Perintah Pesan

VIA harus menangani pesan masuk dengan mengikuti alur "ketuk untuk membaca" yang dijelaskan di Asisten Suara Ketuk-untuk-Baca , yang secara opsional dapat menangani pengiriman balasan kembali ke pengirim pesan masuk. Selain itu, VIA dapat menggunakan SmsManager (bagian dari paket android.telephony ) untuk menulis dan mengirim pesan SMS langsung dari mobil atau melalui Bluetooth.

Menangani Perintah Panggilan

Dengan cara yang sama, VIA dapat menggunakan TelephonyManager untuk melakukan panggilan telepon dan menelepon ke nomor pesan suara pengguna. Dalam kasus ini, VIA akan berinteraksi dengan tumpukan telepon secara langsung atau dengan aplikasi Dialer Mobil. Bagaimanapun, aplikasi Car Dialer harus menjadi aplikasi yang menampilkan UI terkait panggilan suara kepada pengguna.

Memenuhi Perintah Lainnya

Untuk daftar kemungkinan titik integrasi lainnya antara VIA dan sistem, periksa daftar Intent Android yang terkenal . Banyak perintah pengguna dapat diselesaikan di sisi server (misalnya, membaca email pengguna dan acara kalender) dan tidak memerlukan interaksi apa pun dengan sistem selain interaksi suara itu sendiri.

Tindakan Immersive (Menampilkan Konten Visual)

Jika meningkatkan tindakan atau pemahaman pengguna, VIA dapat menyediakan konten visual tambahan di layar mobil. Untuk meminimalkan gangguan pengemudi, buat konten seperti itu tetap sederhana, singkat, dan dapat ditindaklanjuti. Untuk detail tentang pedoman UI/UX tentang tindakan imersif, lihat Asisten yang Dimuat Sebelumnya: Panduan UX .

Untuk mengaktifkan penyesuaian dan konsistensi dengan desain head unit (HU) lainnya, VIA harus menggunakan komponen Perpustakaan UI Mobil untuk sebagian besar elemen UI. Untuk detailnya, lihat Penyesuaian .