Google berkomitmen untuk mendorong terwujudnya keadilan ras bagi komunitas Kulit Hitam. Lihat caranya.

Membuat aplikasi media untuk mobil

Android Auto dan Android Automotive OS membantu Anda menghadirkan konten aplikasi media kepada pengguna di mobil mereka. Aplikasi media untuk mobil harus menyediakan layanan browser media sehingga Android Auto dan Android Automotive OS (atau aplikasi lain dengan browser media) dapat menemukan dan menampilkan konten Anda.

Panduan ini mengasumsikan bahwa Anda sudah memiliki aplikasi media yang memutar audio di ponsel, dan aplikasi media Anda sesuai dengan arsitektur aplikasi media Android.

Panduan ini menjelaskan komponen wajib MediaBrowserService dan MediaSession yang diperlukan aplikasi Anda agar berfungsi di Android Auto atau Android Automotive OS. Setelah menyelesaikan infrastruktur media inti, Anda dapat menambahkan dukungan untuk Android Auto dan menambahkan dukungan untuk Android Automotive OS ke aplikasi media Anda.

Sebelum memulai

  1. Pelajari Dokumentasi API media Android.
  2. Pelajari Pedoman desain aplikasi Android Automotive OS dan Pedoman desain aplikasi Android Auto.
  3. Pelajari istilah dan konsep utama yang tercantum dalam bagian ini.

Istilah dan konsep utama

Layanan Browser Media
Sebuah layanan Android yang diimplementasikan oleh aplikasi media Anda yang mematuhi MediaBrowserServiceCompat API. Aplikasi Anda menggunakan layanan ini untuk mengekspos kontennya.
Browser Media
Sebuah API yang digunakan oleh aplikasi media untuk menemukan layanan browser media dan menampilkan kontennya. Android Auto dan Android Automotive OS menggunakan browser media untuk menemukan layanan browser media aplikasi Anda.
Item Media

Browser media menyusun kontennya dalam hierarki objek MediaItem. Item media dapat memiliki salah satu atau kedua tanda berikut:

  • Dapat diputar: Tanda ini menunjukkan bahwa item adalah sebuah daun pada hierarki konten. Item tersebut merepresentasikan stream suara tunggal seperti lagu pada album, bab pada buku audio, atau episode pada podcast.
  • Dapat dijelajahi: Tanda ini menunjukkan bahwa item adalah suatu node pada hierarki konten dan memiliki turunan. Misalnya, item tersebut merepresentasikan suatu album dan turunannya adalah lagu pada album tersebut.

Suatu item media yang dapat dijelajahi dan diputar akan berperilaku seperti playlist. Anda dapat memilih item itu sendiri untuk memutar semua turunannya, atau menjelajahi turunannya.

Dioptimalkan untuk Kendaraan

Suatu aktivitas untuk aplikasi Android Automotive OS yang mematuhi Pedoman desain Android Automotive OS. Antarmuka untuk aktivitas ini tidak dibuat oleh Android Automotive OS; sehingga Anda harus memastikan bahwa aplikasi Anda mematuhi pedoman desain tersebut. Biasanya, antarmuka ini memiliki target ketuk dan ukuran font yang lebih besar, dukungan untuk mode siang serta malam, dan rasio kontras yang lebih tinggi.

Antarmuka pengguna yang dioptimalkan untuk kendaraan hanya boleh ditampilkan jika Car User Experience Restrictions (CUXR) tidak diberlakukan, karena antarmuka ini bisa saja mengharuskan perhatian atau interaksi yang lama dari pengguna. CUXR tidak diberlakukan saat mobil berhenti atau diparkir, tetapi selalu diberlakukan saat mobil bergerak.

Anda tidak perlu mendesain aktivitas untuk Android Auto karena Android Auto membuat sendiri antarmuka yang dioptimalkan untuk kendaraan menggunakan informasi dari layanan browser media Anda.

Mengonfigurasi file manifes aplikasi Anda

Sebelum membuat layanan browser media, Anda harus mengonfigurasi file manifes aplikasi Anda.

Mendeklarasikan layanan browser media Anda

Android Auto dan Android Automotive OS terhubung ke aplikasi Anda melalui layanan browser media agar dapat menjelajahi item media. Deklarasikan layanan Browser Media dalam manifes Anda agar Android Auto dan Android Automotive OS dapat menemukan layanan tersebut dan terhubung ke aplikasi Anda.

Cuplikan kode berikut menunjukkan cara mendeklarasikan layanan browser media dalam manifes Anda. Anda harus memasukkan kode ini ke dalam file manifes untuk modul Android Automotive OS dan di dalam file manifes untuk aplikasi ponsel Anda.

<application>
        ...
        <service android:name=".MyMediaBrowserService"
                 android:exported="true">
            <intent-filter>
                <action android:name="android.media.browse.MediaBrowserService"/>
            </intent-filter>
        </service>
        ...
    <application>
    

Menentukan ikon aplikasi

Anda perlu menentukan ikon aplikasi yang dapat digunakan Android Auto dan Android Automotive OS untuk merepresentasikan aplikasi Anda di UI sistem.

Anda dapat menentukan ikon yang digunakan untuk merepresentasikan aplikasi Anda menggunakan deklarasi manifes berikut:

<!--The android:icon attribute is used by Android Automotive OS-->
    <application
        ...
        android:icon="@mipmap/ic_launcher">
        ...
        <!--Used by Android Auto-->
        <meta-data android:name="com.google.android.gms.car.notification.SmallIcon"
                   android:resource="@drawable/ic_auto_icon" />
        ...
    <application>
    

Membuat layanan browser media

Buatlah layanan browser media dengan memperluas class MediaBrowserServiceCompat. Selanjutnya, Android Auto dan Android Automotive OS dapat menggunakan layanan Anda untuk melakukan hal berikut:

  • Menjelajahi hierarki konten aplikasi Anda untuk menampilkan menu kepada pengguna.
  • Mendapatkan token untuk objek MediaSessionCompat aplikasi Anda guna mengontrol pemutaran audio.

Alur kerja layanan browser media

Bagian ini menjelaskan cara Android Automotive OS dan Android Auto berinteraksi dengan layanan browser media Anda selama alur kerja pengguna standar.

  1. Pengguna meluncurkan aplikasi Anda di Android Automotive OS atau Android Auto.
  2. Android Automotive OS atau Android Auto menghubungi layanan browser media aplikasi Anda menggunakan metode onCreate(). Di dalam implementasi metode onCreate(), Anda harus membuat dan mendaftarkan objek MediaSessionCompat beserta objek callback-nya.
  3. Android Automotive OS atau Android Auto memanggil metode onGetRoot() layanan Anda untuk mendapatkan item media root dalam hierarki konten Anda. Item media root ini tidak ditampilkan; sebagai gantinya, item ini digunakan untuk mengambil lebih banyak konten dari aplikasi Anda.
  4. Android Automotive OS atau Android Auto memanggil metode onLoadChildren() layanan Anda untuk mendapatkan turunan item media root. Android Automotive OS dan Android Auto menampilkan item media ini sebagai item konten level atas. Item konten level atas harus dapat dijelajahi.
  5. Jika pengguna memilih item media yang dapat dijelajahi, metode onLoadChildren() layanan Anda akan dipanggil lagi untuk mengambil turunan item menu yang dipilih.
  6. Jika pengguna memilih item media yang dapat diputar, Android Automotive OS atau Android Auto akan memanggil metode callback sesi media yang sesuai untuk menjalankan tindakan tersebut.
  7. Jika didukung oleh aplikasi Anda, pengguna juga dapat menelusuri konten Anda. Dalam hal ini, Android Automotive OS atau Android Auto akan memanggil metode onSearch() layanan Anda.

Mem-build hierarki konten

Android Auto dan Android Automotive OS memanggil layanan browser media aplikasi Anda untuk mencari tahu konten apa saja yang tersedia. Anda harus mengimplementasikan dua metode di layanan browser media Anda untuk mendukung tindakan ini: onGetRoot() dan onLoadChildren().

Mengimplementasikan onGetRoot

Metode onGetRoot() layanan Anda akan menampilkan informasi tentang node root hierarki konten Anda. Android Auto dan Android Automotive OS menggunakan node root ini untuk meminta konten Anda lainnya menggunakan metode onLoadChildren().

Cuplikan kode berikut menunjukkan implementasi sederhana metode onGetRoot():

Kotlin

    override fun onGetRoot(
        clientPackageName: String,
        clientUid: Int,
        rootHints: Bundle?
    ): BrowserRoot? =
        // Verify that the specified package is allowed to access your
        // content! You'll need to write your own logic to do this.
        if (!isValid(clientPackageName, clientUid)) {
            // If the request comes from an untrusted package, return null.
            // No further calls will be made to other media browsing methods.

            null
        } else MediaBrowserServiceCompat.BrowserRoot(MY_MEDIA_ROOT_ID, null)
    

Java

    @Override
    public BrowserRoot onGetRoot(String clientPackageName, int clientUid,
        Bundle rootHints) {

        // Verify that the specified package is allowed to access your
        // content! You'll need to write your own logic to do this.
        if (!isValid(clientPackageName, clientUid)) {
            // If the request comes from an untrusted package, return null.
            // No further calls will be made to other media browsing methods.

            return null;
        }

        return new MediaBrowserServiceCompat.BrowserRoot(MY_MEDIA_ROOT_ID, null);
    }
    

Untuk contoh metode ini selengkapnya, lihat metode onGetRoot() pada contoh aplikasi Universal Android Music Player di GitHub.

Menambahkan validasi paket untuk onGetRoot()

Saat panggilan dilakukan ke metode onGetRoot() layanan Anda, paket panggilan ini meneruskan informasi pengidentifikasi ke layanan Anda. Layanan Anda dapat menggunakan informasi ini untuk menentukan apakah paket itu dapat mengakses konten Anda atau tidak. Misalnya, Anda dapat membatasi akses ke konten aplikasi hingga daftar paket yang disetujui dengan membandingkan clientPackageName dan daftar yang diizinkan, lalu memverifikasi sertifikat yang digunakan untuk menandatangani APK paket. Jika paket tidak dapat diverifikasi, tampilkan null untuk menolak akses ke konten Anda.

Agar aplikasi sistem (seperti Android Auto dan Android Automotive OS) dapat mengakses konten Anda, layanan Anda harus selalu menampilkan BrowserRoot non-null saat aplikasi sistem tersebut memanggil metode onGetRoot().

Cuplikan kode berikut menunjukkan bagaimana layanan Anda dapat memvalidasi bahwa paket panggilan adalah aplikasi sistem:

fun isKnownCaller(
        callingPackage: String,
        callingUid: Int
    ): Boolean {
        ...
        val isCallerKnown = when {
           // If the system is making the call, allow it.
           callingUid == Process.SYSTEM_UID -> true
           // If the app was signed by the same certificate as the platform
           // itself, also allow it.
           callerSignature == platformSignature -> true
           // ... more cases
        }
        return isCallerKnown
    }
    

Cuplikan kode ini adalah nukilan dari class PackageValidator pada contoh aplikasi Universal Music Player di GitHub. Pelajari class tersebut untuk melihat contoh selengkapnya tentang cara mengimplementasikan validasi paket untuk metode onGetRoot() layanan Anda.

Mengimplementasikan onLoadChildren()

Setelah menerima objek node root Anda, Android Auto dan Android Automotive OS akan membuat menu level atas dengan memanggil onLoadChildren() pada objek node root untuk memperoleh turunannya. Aplikasi klien mem-build submenu dengan memanggil metode yang sama ini menggunakan objek node turunan.

Setiap node dalam hierarki konten Anda direpresentasikan oleh objek MediaBrowserCompat.MediaItem. Masing-masing item media ini diidentifikasi oleh string ID unik. Aplikasi klien memperlakukan string ID ini sebagai token buram. Saat ingin menjelajah ke sebuah submenu, atau memutar item media, aplikasi klien akan meneruskan token ini. Aplikasi Anda harus mengaitkan token tersebut dengan item media yang sesuai.

Catatan: Android Auto dan Android Automotive OS memiliki batasan ketat terkait jumlah item media yang dapat ditampilkan di setiap level menu. Batasan ini meminimalkan gangguan bagi pengemudi dan membantu mereka mengoperasikan aplikasi Anda dengan perintah suara. Untuk informasi selengkapnya, lihat Menjelajahi detail konten dan Panel daftar aplikasi Android Auto.

Cuplikan kode berikut menunjukkan implementasi sederhana metode onLoadChildren():

Kotlin

    override fun onLoadChildren(
        parentMediaId: String,
        result: Result<List<MediaBrowserCompat.MediaItem>>
    ) {
        // Assume for example that the music catalog is already loaded/cached.

        val mediaItems: MutableList<MediaBrowserCompat.MediaItem> = mutableListOf()

        // Check if this is the root menu:
        if (MY_MEDIA_ROOT_ID == parentMediaId) {

            // build the MediaItem objects for the top level,
            // and put them in the mediaItems list
        } else {

            // examine the passed parentMediaId to see which submenu we're at,
            // and put the children of that menu in the mediaItems list
        }
        result.sendResult(mediaItems)
    }
    

Java

    @Override
    public void onLoadChildren(final String parentMediaId,
        final Result<List<MediaBrowserCompat.MediaItem>> result) {

        // Assume for example that the music catalog is already loaded/cached.

        List<MediaBrowserCompat.MediaItem> mediaItems = new ArrayList<>();

        // Check if this is the root menu:
        if (MY_MEDIA_ROOT_ID.equals(parentMediaId)) {

            // build the MediaItem objects for the top level,
            // and put them in the mediaItems list
        } else {

            // examine the passed parentMediaId to see which submenu we're at,
            // and put the children of that menu in the mediaItems list
        }
        result.sendResult(mediaItems);
    }
    

Untuk contoh lengkap metode ini, lihat metode onLoadChildren() pada contoh aplikasi Universal Android Music Player di GitHub.

Menerapkan gaya konten

Setelah mem-build hierarki konten menggunakan item yang dapat dijelajahi atau diputar, Anda dapat menerapkan gaya konten yang menentukan cara item tersebut ditampilkan di mobil.

Anda dapat menggunakan gaya konten berikut:

Item daftar

Gaya konten ini lebih memprioritaskan judul dan metadata daripada gambar.

Item petak

Gaya konten ini lebih memprioritaskan gambar daripada judul dan metadata.

Menetapkan gaya konten default

Anda dapat menetapkan gaya default global untuk mengatur cara menampilkan item media dengan menyertakan konstanta tertentu dalam paket tambahan BrowserRoot dari metode onGetRoot() layanan Anda. Android Auto dan Android Automotive OS membaca paket tambahan yang terkait dengan setiap item dalam hierarki penjelajahan dan mencari konstanta tersebut untuk menentukan gaya yang sesuai.

Gunakan kode berikut untuk mendeklarasikan konstanta ini dalam aplikasi Anda:

Kotlin

    /** Declares that ContentStyle is supported */
    val CONTENT_STYLE_SUPPORTED = "android.media.browse.CONTENT_STYLE_SUPPORTED"

    /**
    * Bundle extra indicating the presentation hint for playable media items.
    */
    val CONTENT_STYLE_PLAYABLE_HINT = "android.media.browse.CONTENT_STYLE_PLAYABLE_HINT"

    /**
    * Bundle extra indicating the presentation hint for browsable media items.
    */
    val CONTENT_STYLE_BROWSABLE_HINT = "android.media.browse.CONTENT_STYLE_BROWSABLE_HINT"

    /**
    * Specifies the corresponding items should be presented as lists.
    */
    val CONTENT_STYLE_LIST_ITEM_HINT_VALUE = 1

    /**
    * Specifies that the corresponding items should be presented as grids.
    */
    val CONTENT_STYLE_GRID_ITEM_HINT_VALUE = 2
    

Java

    /** Declares that ContentStyle is supported */
    public static final String CONTENT_STYLE_SUPPORTED =;
       "android.media.browse.CONTENT_STYLE_SUPPORTED";

    /**
    * Bundle extra indicating the presentation hint for playable media items.
    */
    public static final String CONTENT_STYLE_PLAYABLE_HINT =
       "android.media.browse.CONTENT_STYLE_PLAYABLE_HINT";

    /**
    * Bundle extra indicating the presentation hint for browsable media items.
    */
    public static final String CONTENT_STYLE_BROWSABLE_HINT =
       "android.media.browse.CONTENT_STYLE_BROWSABLE_HINT";

    /**
    * Specifies the corresponding items should be presented as lists.
    */
    public static final int CONTENT_STYLE_LIST_ITEM_HINT_VALUE = 1;

    /**
    * Specifies that the corresponding items should be presented as grids.
    */
    public static final int CONTENT_STYLE_GRID_ITEM_HINT_VALUE = 2;
    

Setelah dideklarasikan, sertakan konstanta tersebut dalam paket tambahan metode onGetRoot() layanan Anda untuk menetapkan gaya konten default. Cuplikan kode berikut menunjukkan cara menetapkan gaya konten default untuk item yang dapat dijelajahi ke petak, dan item yang dapat diputar ke daftar:

Kotlin

    @Nullable
    override fun onGetRoot(
        @NonNull clientPackageName: String,
        clientUid: Int,
        @Nullable rootHints: Bundle
    ): BrowserRoot {
        val extras = Bundle()
        extras.putBoolean(CONTENT_STYLE_SUPPORTED, true)
        extras.putInt(CONTENT_STYLE_BROWSABLE_HINT, CONTENT_STYLE_GRID_ITEM_HINT_VALUE)
        extras.putInt(CONTENT_STYLE_PLAYABLE_HINT, CONTENT_STYLE_LIST_ITEM_HINT_VALUE)
        return BrowserRoot(ROOT_ID, extras)
    }
    

Java

    @Nullable
    @Override
    public BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid,
       @Nullable Bundle rootHints) {
       Bundle extras = new Bundle();
       extras.putBoolean(CONTENT_STYLE_SUPPORTED, true);
       extras.putInt(CONTENT_STYLE_BROWSABLE_HINT, CONTENT_STYLE_GRID_ITEM_HINT_VALUE);
       extras.putInt(CONTENT_STYLE_PLAYABLE_HINT, CONTENT_STYLE_LIST_ITEM_HINT_VALUE);
       return new BrowserRoot(ROOT_ID, extras);
    }
    

Menetapkan gaya konten per item

Content Style API memungkinkan Anda mengganti gaya konten default untuk turunan mana pun dari item media yang dapat dijelajahi. Untuk mengganti gaya default, buat paket tambahan dalam MediaDescription item media.

Cuplikan kode berikut menunjukkan cara membuat MediaItem yang dapat dijelajahi yang akan mengganti gaya konten default:

Kotlin

    private fun createBrowsableMediaItem(
        mediaId: String,
        folderName: String,
        iconUri: Uri
    ): MediaBrowser.MediaItem {
        val mediaDescriptionBuilder = MediaDescription.Builder()
        mediaDescriptionBuilder.setMediaId(mediaId)
        mediaDescriptionBuilder.setTitle(folderName)
        mediaDescriptionBuilder.setIconUri(iconUri)
        val extras = Bundle()
        extras.putInt(CONTENT_STYLE_BROWSABLE_HINT, CONTENT_STYLE_LIST_ITEM_HINT_VALUE)
        extras.putInt(CONTENT_STYLE_PLAYABLE_HINT, CONTENT_STYLE_GRID_ITEM_HINT_VALUE)
        mediaDescriptionBuilder.setExtras(extras)
        return MediaBrowser.MediaItem(
            mediaDescriptionBuilder.build(), MediaBrowser.MediaItem.FLAG_BROWSABLE)
    }
    

Java

    private MediaBrowser.MediaItem createBrowsableMediaItem(String mediaId,
       String folderName, Uri iconUri) {
       MediaDescription.Builder mediaDescriptionBuilder = new MediaDescription.Builder();
       mediaDescriptionBuilder.setMediaId(mediaId);
       mediaDescriptionBuilder.setTitle(folderName);
       mediaDescriptionBuilder.setIconUri(iconUri);
       Bundle extras = new Bundle();
       extras.putInt(CONTENT_STYLE_BROWSABLE_HINT, CONTENT_STYLE_LIST_ITEM_HINT_VALUE);
       extras.putInt(CONTENT_STYLE_PLAYABLE_HINT, CONTENT_STYLE_GRID_ITEM_HINT_VALUE);
       mediaDescriptionBuilder.setExtras(extras);
       return new MediaBrowser.MediaItem(
           mediaDescriptionBuilder.build(), MediaBrowser.MediaItem.FLAG_BROWSABLE);
    }
    

Mengelompokkan item menggunakan petunjuk judul

Untuk mengelompokkan item media terkait, gunakan petunjuk per item. Setiap item media dalam grup harus mendeklarasikan paket tambahan dalam MediaDescription yang menggunakan string identik. String ini digunakan sebagai judul grup dan dapat dilokalkan.

Cuplikan kode berikut menunjukkan cara membuat MediaItem dengan judul subgrup "Songs":

Kotlin

    val EXTRA_CONTENT_STYLE_GROUP_TITLE_HINT = "android.media.browse.CONTENT_STYLE_GROUP_TITLE_HINT"

    private fun createMediaItem(
        mediaId: String,
        folderName: String,
        iconUri: Uri
    ): MediaBrowser.MediaItem {
        val mediaDescriptionBuilder = MediaDescription.Builder()
        mediaDescriptionBuilder.setMediaId(mediaId)
        mediaDescriptionBuilder.setTitle(folderName)
        mediaDescriptionBuilder.setIconUri(iconUri)
        val extras = Bundle()
        extras.putString(EXTRA_CONTENT_STYLE_GROUP_TITLE_HINT, "Songs")
        mediaDescriptionBuilder.setExtras(extras)
        return MediaBrowser.MediaItem(
            mediaDescriptionBuilder.build(), /* playable or browsable flag*/)
    }
    

Java

    public static final String EXTRA_CONTENT_STYLE_GROUP_TITLE_HINT =
      "android.media.browse.CONTENT_STYLE_GROUP_TITLE_HINT";

    private MediaBrowser.MediaItem createMediaItem(String mediaId, String folderName, Uri iconUri) {
       MediaDescription.Builder mediaDescriptionBuilder = new MediaDescription.Builder();
       mediaDescriptionBuilder.setMediaId(mediaId);
       mediaDescriptionBuilder.setTitle(folderName);
       mediaDescriptionBuilder.setIconUri(iconUri);
       Bundle extras = new Bundle();
       extras.putString(EXTRA_CONTENT_STYLE_GROUP_TITLE_HINT, "Songs");
       mediaDescriptionBuilder.setExtras(extras);
       return new MediaBrowser.MediaItem(
           mediaDescriptionBuilder.build(), /* playable or browsable flag*/);
    }
    

Aplikasi Anda harus meneruskan semua item media yang ingin dikelompokkan bersama sebagai blok yang berdekatan. Misalnya, anggaplah Anda ingin menampilkan dua grup item media, "Songs" dan "Albums" (dalam urutan tersebut), dan aplikasi Anda meneruskan lima item media dengan urutan sebagai berikut:

  1. Item media A dengan extras.putString(EXTRA_CONTENT_STYLE_GROUP_TITLE_HINT, "Songs")
  2. Item media B dengan extras.putString(EXTRA_CONTENT_STYLE_GROUP_TITLE_HINT, "Albums")
  3. Item media C dengan extras.putString(EXTRA_CONTENT_STYLE_GROUP_TITLE_HINT, "Songs")
  4. Item media D dengan extras.putString(EXTRA_CONTENT_STYLE_GROUP_TITLE_HINT, "Songs")
  5. Item media E dengan extras.putString(EXTRA_CONTENT_STYLE_GROUP_TITLE_HINT, "Albums")

Karena item media untuk grup "Songs" dan grup "Albums" tidak disimpan bersamaan dalam blok yang berdekatan, Android Auto dan Android Automotive OS akan menafsirkan ini sebagai empat grup berikut:

  • Grup 1 disebut "Songs" yang berisi item media A
  • Grup 2 disebut "Albums" yang berisi item media B
  • Grup 3 disebut "Songs" yang berisi item media C dan D
  • Grup 4 disebut "Albums" yang berisi item media E

Untuk menampilkan item tersebut dalam dua grup, aplikasi Anda seharusnya meneruskan aplikasi dalam urutan berikut:

  1. Item media A dengan extras.putString(EXTRA_CONTENT_STYLE_GROUP_TITLE_HINT, "Songs")
  2. Item media C dengan extras.putString(EXTRA_CONTENT_STYLE_GROUP_TITLE_HINT, "Songs")
  3. Item media D dengan extras.putString(EXTRA_CONTENT_STYLE_GROUP_TITLE_HINT, "Songs")
  4. Item media B dengan extras.putString(EXTRA_CONTENT_STYLE_GROUP_TITLE_HINT, "Albums")
  5. Item media E dengan extras.putString(EXTRA_CONTENT_STYLE_GROUP_TITLE_HINT, "Albums")

Menampilkan indikator metadata tambahan

Gambar 3. Pemutaran dengan metadata yang mengidentifikasi lagu dan artis

Anda dapat menyertakan indikator metadata tambahan untuk menambahkan informasi sekilas bagi konten dalam hierarki browser media dan selama pemutaran. Di dalam hierarki penjelajahan, Android Auto dan Android Automotive OS membaca tambahan yang terkait dengan item dan mencari konstanta tertentu untuk menentukan indikator mana yang akan ditampilkan. Selama media diputar, Android Auto dan Android Automotive OS membaca metadata untuk sesi media tersebut dan mencari konstanta tertentu untuk menentukan indikator yang akan ditampilkan.

Gunakan kode berikut untuk mendeklarasikan konstanta indikator metadata dalam aplikasi Anda:

Kotlin

    // Bundle extra indicating that a song contains explicit content.
    var EXTRA_IS_EXPLICIT = "android.media.IS_EXPLICIT"

    /**
    * Bundle extra indicating that a media item is available offline.
    * Same as MediaDescriptionCompat.EXTRA_DOWNLOAD_STATUS.
    */
    var EXTRA_IS_DOWNLOADED = "android.media.extra.DOWNLOAD_STATUS"

    /**
    * Bundle extra value indicating that an item should show the corresponding
    * metadata.
    */
    var EXTRA_METADATA_ENABLED_VALUE:Long = 1

    /**
    * Bundle extra indicating the played state of long-form content (such as podcast
    * episodes or audiobooks).
    */
    var EXTRA_PLAY_COMPLETION_STATE = "android.media.extra.PLAYBACK_STATUS"

    /**
    * Value for EXTRA_PLAY_COMPLETION_STATE that indicates the media item has
    * not been played at all.
    */
    var STATUS_NOT_PLAYED = 0

    /**
    * Value for EXTRA_PLAY_COMPLETION_STATE that indicates the media item has
    * been partially played (i.e. the current position is somewhere in the middle).
    */
    var STATUS_PARTIALLY_PLAYED = 1

    /**
    * Value for EXTRA_PLAY_COMPLETION_STATE that indicates the media item has
    * been completed.
    */
    var STATUS_FULLY_PLAYED = 2
    

Java

    // Bundle extra indicating that a song contains explicit content.
    String EXTRA_IS_EXPLICIT = "android.media.IS_EXPLICIT";

    /**
     * Bundle extra indicating that a media item is available offline.
     * Same as MediaDescriptionCompat.EXTRA_DOWNLOAD_STATUS.
     */
    String EXTRA_IS_DOWNLOADED = "android.media.extra.DOWNLOAD_STATUS";

    /**
     * Bundle extra value indicating that an item should show the corresponding
     * metadata.
     */
    long EXTRA_METADATA_ENABLED_VALUE = 1;

    /**
     * Bundle extra indicating the played state of long-form content (such as podcast
     * episodes or audiobooks).
     */
    String EXTRA_PLAY_COMPLETION_STATE = "android.media.extra.PLAYBACK_STATUS";

    /**
     * Value for EXTRA_PLAY_COMPLETION_STATE that indicates the media item has
     * not been played at all.
     */
    int STATUS_NOT_PLAYED = 0;

    /**
     * Value for EXTRA_PLAY_COMPLETION_STATE that indicates the media item has
     * been partially played (i.e. the current position is somewhere in the middle).
     */
    int STATUS_PARTIALLY_PLAYED = 1;

    /**
     * Value for EXTRA_PLAY_COMPLETION_STATE that indicates the media item has
     * been completed.
     */
    int STATUS_FULLY_PLAYED = 2;
    

Setelah mendeklarasikan konstanta ini, Anda dapat menggunakannya untuk menampilkan indikator metadata. Agar indikator ditampilkan saat pengguna menjelajahi hierarki browser media, buat paket tambahan yang menyertakan satu atau beberapa konstanta tersebut dan teruskan paket itu ke metode MediaDescription.Builder.setExtras().

Cuplikan kode berikut menunjukkan cara menampilkan indikator untuk item media eksplisit yang diputar sebagian:

Kotlin

    val extras = Bundle()
    extras.putLong(EXTRA_IS_EXPLICIT, 1)
    extras.putInt(EXTRA_PLAY_COMPLETION_STATE, STATUS_PARTIALLY_PLAYED)
    val description = MediaDescriptionCompat.Builder()
    .setMediaId(/*...*/)
    .setTitle(resources.getString(/*...*/))
    .setExtras(extras)
    .build()
    return MediaBrowserCompat.MediaItem(description, /* flags */)
    

Java

    Bundle extras = new Bundle();
    extras.putLong(EXTRA_IS_EXPLICIT, 1);
    extras.putInt(EXTRA_PLAY_COMPLETION_STATE, STATUS_PARTIALLY_PLAYED);

    MediaDescriptionCompat description = new MediaDescriptionCompat.Builder()
      .setMediaId(/*...*/)
      .setTitle(resources.getString(/*...*/))
      .setExtras(extras)
      .build();
    return new MediaBrowserCompat.MediaItem(description, /* flags */);
    

Jika ingin menampilkan indikator untuk item media yang sedang diputar, Anda dapat mendeklarasikan nilai Long untuk EXTRA_IS_EXPLICIT atau EXTRA_IS_DOWNLOADED dalam metode MediaMetadata.Builder() dari mediaSession Anda. Anda tidak dapat menampilkan indikator EXTRA_PLAY_COMPLETION_STATE pada tampilan pemutaran.

Cuplikan kode berikut mengilustrasikan cara menunjukkan bahwa lagu saat ini di tampilan pemutaran bersifat eksplisit dan telah didownload:

Kotlin

    mediaSession.setMetadata(
      MediaMetadata.Builder()
      .putString(
        MediaMetadata.METADATA_KEY_DISPLAY_TITLE, "Song Name")
      .putString(
        MediaMetadata.METADATA_KEY_DISPLAY_SUBTITLE, "Artist name")
      .putString(MediaMetadata.METADATA_KEY_ALBUM_ART_URI, albumArtUri.toString())
      .putLong(
        EXTRA_IS_EXPLICIT, EXTRA_METADATA_ENABLED_VALUE)
      .putLong(
        EXTRA_IS_DOWNLOADED, EXTRA_METADATA_ENABLED_VALUE)
      .build())
    

Java

    mediaSession.setMetadata(
        new MediaMetadata.Builder()
            .putString(
                MediaMetadata.METADATA_KEY_DISPLAY_TITLE, "Song Name")
            .putString(
                MediaMetadata.METADATA_KEY_DISPLAY_SUBTITLE, "Artist name")
            .putString(MediaMetadata.METADATA_KEY_ALBUM_ART_URI, albumArtUri.toString())
            .putLong(
                EXTRA_IS_EXPLICIT, EXTRA_METADATA_ENABLED_VALUE)
            .putLong(
                EXTRA_IS_DOWNLOADED, EXTRA_METADATA_ENABLED_VALUE)
            .build());
    

Untuk memudahkan pengguna menjelajahi konten, aplikasi Anda dapat mengizinkan pengguna menjelajahi sekelompok hasil penelusuran yang terkait dengan kueri penelusurannya setiap kali pengguna tersebut melakukan penelusuran suara. Android Auto dan Android Automotive OS menampilkan hasil ini dalam kolom "Tampilkan hasil lainnya" di antarmuka.

Gambar 4. Opsi "Hasil lainnya" untuk melihat hasil penelusuran terkait

Untuk menampilkan hasil penelusuran yang dapat dijelajahi, Anda harus membuat suatu konstanta dan menyertakannya dalam paket tambahan dari metode onGetRoot() layanan Anda.

Cuplikan kode berikut menunjukkan cara mengaktifkan dukungan dalam metode onGetRoot():

Kotlin

    // Bundle extra indicating that onSearch() is supported
    val EXTRA_MEDIA_SEARCH_SUPPORTED = "android.media.browse.SEARCH_SUPPORTED"

    @Nullable
    fun onGetRoot(
        @NonNull clientPackageName: String,
        clientUid: Int,
        @Nullable rootHints: Bundle
    ): BrowserRoot {
        val extras = Bundle()
        extras.putBoolean(EXTRA_MEDIA_SEARCH_SUPPORTED, true)
        return BrowserRoot(ROOT_ID, extras)
    }
    

Java

    public static final String EXTRA_MEDIA_SEARCH_SUPPORTED =
       "android.media.browse.SEARCH_SUPPORTED";

    @Nullable
    @Override
    public BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid,
       @Nullable Bundle rootHints) {
       Bundle extras = new Bundle();
       extras.putBoolean(EXTRA_MEDIA_SEARCH_SUPPORTED, true);
       return new BrowserRoot(ROOT_ID, extras);
    }
    

Untuk mulai menyajikan hasil penelusuran, ganti metode onSearch() di layanan browser media Anda. Android Auto dan Android Automotive OS meneruskan istilah penelusuran pengguna ke metode ini setiap kali pengguna memanggil properti "Tampilkan hasil lainnya". Anda dapat mengatur hasil penelusuran dari metode onSearch() layanan Anda menggunakan item judul agar lebih mudah dijelajahi. Misalnya, jika aplikasi Anda memutar musik, Anda dapat mengatur hasil penelusuran menurut "Album", "Artis", dan "Lagu".

Cuplikan kode berikut menunjukkan implementasi sederhana metode onSearch():

Kotlin

    fun onSearch(query: String, extras: Bundle) {
      // Detach from results to unblock the caller (if a search is expensive)
      result.detach()
      object:AsyncTask() {
        internal var searchResponse:ArrayList
        internal var succeeded = false
        protected fun doInBackground(vararg params:Void):Void {
          searchResponse = ArrayList()
          if (doSearch(query, extras, searchResponse))
          {
            succeeded = true
          }
          return null
        }
        protected fun onPostExecute(param:Void) {
          if (succeeded)
          {
            // Sending an empty List informs the caller that there were no results.
            result.sendResult(searchResponse)
          }
          else
          {
            // This invokes onError() on the search callback
            result.sendResult(null)
          }
          return null
        }
      }.execute()
    }
    // Populates resultsToFill with search results. Returns true on success or false on error
    private fun doSearch(
        query: String,
        extras: Bundle,
        resultsToFill: ArrayList
    ): Boolean {
      // Implement this method
    }
    

Java

    @Override
    public void onSearch(final String query, final Bundle extras,
                            Result<ArrayList<MediaItem>> result) {

      // Detach from results to unblock the caller (if a search is expensive)
      result.detach();

      new AsyncTask<Void, Void, Void>() {
        ArrayList<MediaItem> searchResponse;
        boolean succeeded = false;
        @Override
        protected Void doInBackground(Void... params) {
          searchResponse = new ArrayList<MediaItem>();
          if (doSearch(query, extras, searchResponse)) {
            succeeded = true;
          }
          return null;
        }

        @Override
        protected void onPostExecute(Void param) {
          if (succeeded) {
           // Sending an empty List informs the caller that there were no results.
           result.sendResult(searchResponse);
          } else {
            // This invokes onError() on the search callback
            result.sendResult(null);
          }
          return null;
        }
      }.execute()
    }

    /** Populates resultsToFill with search results. Returns true on success or false on error */
    private boolean doSearch(String query, Bundle extras, ArrayList<MediaItem> resultsToFill) {
        // Implement this method
    }
    

Mengaktifkan kontrol pemutaran

Android Auto dan Android Automotive OS mengirimkan perintah kontrol pemutaran melalui MediaSessionCompat layanan Anda. Anda harus mendaftarkan sesi dan mengimplementasikan metode callback yang terkait.

Mendaftarkan sesi media

Dalam metode onCreate() layanan browser media Anda, buat MediaSessionCompat, lalu daftarkan sesi media tersebut dengan memanggil setSessionToken().

Cuplikan kode berikut menunjukkan cara membuat dan mendaftarkan sesi media:

Kotlin

    override fun onCreate() {
        super.onCreate()

        ...
        // Start a new MediaSession
        val session = MediaSessionCompat(this, "session tag").apply {
            // Set a callback object to handle play control requests, which
            // implements MediaSession.Callback
            setCallback(MyMediaSessionCallback())
        }
        sessionToken = session.sessionToken

        ...
    }
    

Java

    public void onCreate() {
        super.onCreate();

        ...
        // Start a new MediaSession
        MediaSessionCompat session = new MediaSessionCompat(this, "session tag");
        setSessionToken(session.getSessionToken());

        // Set a callback object to handle play control requests, which
        // implements MediaSession.Callback
        session.setCallback(new MyMediaSessionCallback());

        ...
    }
    

Saat Anda membuat objek sesi media, tetapkan objek callback yang digunakan untuk menangani permintaan kontrol pemutaran. Objek ini dibuat dengan memberikan implementasi class MediaSessionCompat.Callback untuk aplikasi Anda. Bagian selanjutnya membahas cara mengimplementasikan objek ini.

Mengimplementasikan perintah putar

Saat pengguna meminta pemutaran untuk item media dari aplikasi Anda, Android Automotive OS dan Android Auto menggunakan class MediaSessionCompat.Callback dari objek MediaSessionCompat aplikasi Anda yang diperoleh dari layanan browser media aplikasi Anda. Saat pengguna ingin mengontrol pemutaran konten, seperti menjeda pemutaran atau melewati ke lagu berikutnya, Android Auto dan Android Automotive OS akan memanggil salah satu metode objek callback.

Untuk menangani pemutaran konten, aplikasi Anda harus memperluas class MediaSessionCompat.Callback abstrak dan mengimplementasikan metode yang didukung aplikasi Anda.

Anda harus mengimplementasikan semua metode callback berikut yang sesuai untuk jenis konten yang ditawarkan aplikasi Anda:

onPrepare()
Dipanggil saat sumber media berubah. Android Automotive OS juga memanggil metode ini segera setelah booting. Aplikasi media Anda harus mengimplementasikan metode ini.
onPlay()
Dipanggil jika pengguna memilih untuk memutar item media tanpa memilih item tertentu. Aplikasi Anda akan memutar konten default-nya. Jika pemutaran dijeda dengan onPause(), aplikasi Anda akan melanjutkan pemutaran.

Catatan: Aplikasi Anda tidak boleh otomatis mulai memutar musik saat Android Automotive OS atau Android Auto terhubung ke layanan browser media Anda. Untuk informasi selengkapnya, baca Menetapkan status pemutaran awal.

onPlayFromMediaId()
Dipanggil saat pengguna memilih untuk memutar item tertentu. Metode ini diteruskan ID yang ditetapkan layanan browser media Anda ke item media tersebut dalam hierarki konten Anda.
onPlayFromSearch()
Dipanggil saat pengguna memilih untuk memutar item media dari kueri penelusuran. Aplikasi harus membuat pilihan yang tepat berdasarkan string penelusuran yang diteruskan.
onPause()
Dipanggil saat pengguna memilih untuk menjeda pemutaran.
onSkipToNext()
Dipanggil saat pengguna memilih untuk melewati ke item berikutnya.
onSkipToPrevious()
Dipanggil saat pengguna memilih untuk melewati ke item sebelumnya.
onStop()
Dipanggil saat pengguna memilih untuk menghentikan pemutaran.

Aplikasi Anda harus mengganti metode ini untuk menyediakan fungsionalitas yang diinginkan. Anda tidak perlu mengimplementasikan metode yang tidak didukung oleh aplikasi Anda. Misalnya, jika aplikasi Anda memutar live stream (seperti siaran olahraga), metode onSkipToNext() tidak akan sesuai, dan sebagai gantinya Anda dapat menggunakan implementasi default onSkipToNext().

Aplikasi Anda tidak memerlukan logika khusus untuk memutar konten melalui speaker mobil. Saat menerima permintaan untuk memutar konten, aplikasi Anda akan memutar audio seperti biasanya (misalnya, memutar konten melalui speaker atau headphone ponsel pengguna). Android Auto dan Android Automotive OS akan otomatis mengirim konten audio ke sistem mobil untuk diputar melalui speaker mobil.

Untuk informasi selengkapnya tentang memutar konten audio, lihat Pemutaran media, Mengelola pemutaran audio, dan ExoPlayer.

Menetapkan tindakan pemutaran standar

Android Auto dan Android Automotive OS menampilkan kontrol pemutaran berdasarkan tindakan yang diaktifkan dalam objek PlaybackStateCompat.

Secara default, aplikasi Anda harus mendukung tindakan berikut:

Selain itu, sebaiknya Anda membuat antrean pemutaran untuk ditampilkan kepada pengguna. Untuk melakukannya, Anda perlu memanggil metode setQueue() dan setQueueTitle(), mengaktifkan tindakan ACTION_SKIP_TO_QUEUE_ITEM, dan menentukan callback onSkipToQueueItem().

Android Auto dan Android Automotive OS menampilkan tombol untuk setiap tindakan yang diaktifkan, serta antrean pemutaran jika Anda memilih untuk membuatnya.

Mencadangkan ruang yang tidak terpakai

Android Auto dan Android Automotive OS mencadangkan ruang pada UI untuk tindakan ACTION_SKIP_TO_PREVIOUS dan ACTION_SKIP_TO_NEXT. Selain itu, Android Auto mencadangkan ruang untuk antrean pemutaran. Jika aplikasi Anda tidak mendukung salah satu fungsi tersebut, Android Auto dan Android Automotive OS akan menggunakan ruang itu untuk menampilkan tindakan kustom apa pun yang Anda buat.

Jika tidak ingin mengisi ruang tersebut dengan tindakan kustom, Anda dapat mencadangkannya sehingga Android Auto dan Android Automotive OS akan mengosongkan ruang itu setiap kali aplikasi Anda tidak mendukung fungsi yang sesuai. Untuk melakukannya, panggil metode setExtras() beserta paket tambahan yang berisi konstanta yang terkait dengan setiap fungsi yang dicadangkan. Tetapkan setiap konstanta yang ingin Anda cadangkan ruang ke true.

Cuplikan kode berikut menunjukkan konstanta yang dapat Anda gunakan untuk mencadangkan ruang yang tidak terpakai:

Kotlin

    // Use these extras to show the transport control buttons for the corresponding actions,
    // even when they are not enabled in the PlaybackState.
    private const val PLAYBACK_SLOT_RESERVATION_SKIP_TO_NEXT =
            "android.media.playback.ALWAYS_RESERVE_SPACE_FOR.ACTION_SKIP_TO_NEXT"
    private const val PLAYBACK_SLOT_RESERVATION_SKIP_TO_PREV =
            "android.media.playback.ALWAYS_RESERVE_SPACE_FOR.ACTION_SKIP_TO_PREVIOUS"
    private const val PLAYBACK_SLOT_RESERVATION_QUEUE =
            "android.media.playback.ALWAYS_RESERVE_SPACE_FOR.ACTION_QUEUE"
    

Java

    // Use these extras to show the transport control buttons for the corresponding actions,
    // even when they are not enabled in the PlaybackState.
    private static final String PLAYBACK_SLOT_RESERVATION_SKIP_TO_NEXT =
        "android.media.playback.ALWAYS_RESERVE_SPACE_FOR.ACTION_SKIP_TO_NEXT";
    private static final String PLAYBACK_SLOT_RESERVATION_SKIP_TO_PREV =
        "android.media.playback.ALWAYS_RESERVE_SPACE_FOR.ACTION_SKIP_TO_PREVIOUS";
    private static final String PLAYBACK_SLOT_RESERVATION_QUEUE =
        "android.media.playback.ALWAYS_RESERVE_SPACE_FOR.ACTION_QUEUE";
    

Menetapkan PlaybackState awal

Saat Android Auto dan Android Automotive OS berkomunikasi dengan layanan browser media Anda, sesi media Anda mengomunikasikan status pemutaran konten menggunakan PlaybackState. Aplikasi Anda tidak boleh otomatis mulai memutar musik saat Android Automotive OS atau Android Auto terhubung ke layanan browser media. Sebagai gantinya, andalkan Android Auto dan Android Automotive OS untuk melanjutkan atau memulai pemutaran berdasarkan keadaan mobil atau tindakan pengguna.

Untuk melakukannya, tetapkan PlaybackState awal dari sesi media Anda ke STATE_STOPPED, STATE_PAUSED, STATE_NONE, atau STATE_ERROR.

Menambahkan tindakan pemutaran kustom

Anda dapat menambahkan tindakan pemutaran kustom untuk menampilkan tindakan tambahan yang didukung aplikasi media Anda. Jika ruangnya memungkinkan (dan tidak dicadangkan), Android akan menambahkan tindakan kustom ke kontrol transport. Jika tidak, tindakan kustom akan ditampilkan di menu tambahan. Tindakan kustom ditampilkan sesuai urutan penambahannya ke PlaybackState.

Anda dapat menambahkan tindakan ini menggunakan metode addCustomAction() di class PlaybackStateCompat.Builder.

Cuplikan kode berikut menunjukkan cara menambahkan tindakan kustom "Mulai saluran radio":

Kotlin

    stateBuilder.addCustomAction(
            PlaybackStateCompat.CustomAction.Builder(
                    CUSTOM_ACTION_START_RADIO_FROM_MEDIA,
                    resources.getString(R.string.start_radio_from_media),
                    startRadioFromMediaIcon
            ).run {
                setExtras(customActionExtras)
                build()
            }
    )
    

Java

    stateBuilder.addCustomAction(new PlaybackStateCompat.CustomAction.Builder(
        CUSTOM_ACTION_START_RADIO_FROM_MEDIA,
        resources.getString(R.string.start_radio_from_media), startRadioFromMediaIcon)
        .setExtras(customActionExtras)
        .build());
    

Untuk contoh metode ini selengkapnya, lihat metode setCustomAction() pada contoh aplikasi Universal Android Music Player di GitHub.

Setelah membuat tindakan kustom, sesi media Anda dapat merespons tindakan tersebut dengan mengganti metode onCustomAction().

Cuplikan kode berikut menunjukkan cara aplikasi Anda merespons tindakan "Mulai saluran radio":

Kotlin

    override fun onCustomAction(action: String, extras: Bundle?) {
        when(action) {
            CUSTOM_ACTION_START_RADIO_FROM_MEDIA -> {
                ...
            }
        }
    }
    

Java

    @Override
    public void onCustomAction(@NonNull String action, Bundle extras) {
        if (CUSTOM_ACTION_START_RADIO_FROM_MEDIA.equals(action)) {
            ...
        }
    }
    

Untuk contoh metode ini selengkapnya, lihat metode onCustomAction pada contoh aplikasi Universal Android Music Player di GitHub.

Ikon untuk tindakan kustom

Setiap tindakan kustom yang Anda buat memerlukan resource ikon. Aplikasi untuk mobil dapat berjalan di berbagai ukuran dan kepadatan layar, sehingga ikon yang Anda sediakan haruslah berupa vector drawable. Vector drawable memungkinkan Anda mengubah skala aset tanpa kehilangan detailnya. Vector drawable juga memudahkan penyelarasan tepi dan sudut dengan batas piksel pada resolusi yang lebih kecil.

Menyediakan gaya ikon alternatif untuk tindakan yang dinonaktifkan

Apabila tindakan kustom tidak tersedia untuk konteks yang sedang aktif, tukar ikon tindakan kustom dengan ikon alternatif yang menunjukkan bahwa tindakan dinonaktifkan.

Gambar 5. Contoh ikon tindakan kustom gaya tidak aktif.

Mendukung tindakan suara

Aplikasi media Anda harus mendukung voice action untuk memberi pengemudi pengalaman yang aman dan nyaman serta minim gangguan. Misalnya, saat aplikasi Anda sedang memutar satu item media, pengguna dapat mengucapkan "Putar Bohemian Rhapsody" untuk meminta aplikasi tersebut memutar lagu lain tanpa melihat atau menyentuh layar mobil.

Untuk contoh selengkapnya tentang cara menerapkan tindakan pemutaran yang diaktifkan dengan suara di aplikasi Anda, lihat Asisten Google dan aplikasi media.

Mengimplementasikan pengamanan dari gangguan

Karena ponsel pengguna terhubung ke speaker mobil saat menggunakan Android Auto, Anda harus mengambil tindakan pencegahan tambahan untuk meminimalkan gangguan bagi pengemudi.

Mendeteksi mode mobil

Aplikasi media Android Auto tidak boleh memulai pemutaran audio melalui speaker mobil kecuali jika pengguna memulai pemutaran dengan sengaja (misalnya dengan mengetuk tombol putar di aplikasi Anda). Bahkan alarm yang dijadwalkan pengguna dari aplikasi media pun tidak boleh mulai memutar musik melalui speaker mobil. Untuk memenuhi persyaratan ini, aplikasi Anda harus menentukan apakah ponsel sedang dalam mode mobil sebelum memutar audio apa pun. Untuk memeriksa apakah ponsel dalam mode mobil atau tidak, aplikasi Anda dapat memanggil metode getCurrentModeType().

Jika ponsel pengguna sedang dalam mode mobil, aplikasi media yang mendukung alarm harus melakukan salah satu tindakan berikut:

  • Menonaktifkan alarm.
  • Memutar alarm melalui STREAM_ALARM, dan menyediakan UI pada layar ponsel untuk menonaktifkan alarm.

Cuplikan kode berikut menunjukkan cara memeriksa apakah aplikasi berjalan dalam mode mobil:

Kotlin

    fun isCarUiMode(c: Context): Boolean {
        val uiModeManager = c.getSystemService(Context.UI_MODE_SERVICE) as UiModeManager
        return if (uiModeManager.currentModeType == Configuration.UI_MODE_TYPE_CAR) {
            LogHelper.d(TAG, "Running in Car mode")
            true
        } else {
            LogHelper.d(TAG, "Running in a non-Car mode")
            false
        }
    }
    

Java

     public static boolean isCarUiMode(Context c) {
          UiModeManager uiModeManager = (UiModeManager) c.getSystemService(Context.UI_MODE_SERVICE);
          if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_CAR) {
                LogHelper.d(TAG, "Running in Car mode");
                return true;
          } else {
              LogHelper.d(TAG, "Running in a non-Car mode");
              return false;
            }
      }
    

Menangani iklan media

Secara default, Android Auto menampilkan notifikasi saat metadata media berubah selama sesi pemutaran audio. Saat aplikasi media beralih dari memutar musik ke menjalankan iklan, akan sangat mengganggu (dan tidak perlu) jika notifikasi ditampilkan kepada pengguna. Untuk mencegah Android Auto menampilkan notifikasi dalam kasus ini, Anda harus menetapkan kunci metadata media android.media.metadata.ADVERTISEMENT ke 1, seperti yang ditunjukkan dalam cuplikan kode berikut:

Kotlin

    const val EXTRA_METADATA_ADVERTISEMENT = "android.media.metadata.ADVERTISEMENT"
    ...
    override fun onPlayFromMediaId(mediaId: String, extras: Bundle?) {
        MediaMetadataCompat.Builder().apply {
            // ...
            if (isAd(mediaId)) {
                putLong(EXTRA_METADATA_ADVERTISEMENT, 1)
            }
            // ...
            mediaSession.setMetadata(build())
        }
    }
    

Java

    public static final String EXTRA_METADATA_ADVERTISEMENT =
        "android.media.metadata.ADVERTISEMENT";

    @Override
    public void onPlayFromMediaId(String mediaId, Bundle extras) {
        MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder();
        // ...
        if (isAd(mediaId)) {
            builder.putLong(EXTRA_METADATA_ADVERTISEMENT, 1);
        }
        // ...
        mediaSession.setMetadata(builder.build());
    }
    

Menangani error umum

Saat aplikasi mengalami error, Anda harus menetapkan status pemutarannya ke STATE_ERROR dan menampilkan pesan error menggunakan metode setErrorMessage(). Pesan error harus terlihat oleh pengguna dan dilokalkan sesuai bahasa pengguna saat ini. Selanjutnya Android Auto dan Android Automotive OS dapat menampilkan pesan error kepada pengguna.

Untuk informasi selengkapnya tentang status error, lihat Menangani sesi media: Status dan error.

Jika pengguna Android Auto perlu membuka aplikasi ponsel Anda untuk menyelesaikan error, pesan Anda harus menyampaikan informasi itu kepada pengguna. Misalnya, pesan error Anda seharusnya terlihat "Login ke [nama aplikasi Anda]", bukan "Harap login".

Referensi lainnya