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

Kontrol Media Baru

Android 11 memperbarui cara kontrol media ditampilkan, menggunakan MediaSession dan MediaRouter2 API untuk merender kontrol dan informasi output audio.

Kontrol media di Android 11 terletak di dekat Setelan Cepat. Sesi dari beberapa aplikasi disusun dalam carousel yang dapat digeser. Carousel ini mencantumkan sesi dalam urutan berikut:

  • Streaming yang diputar secara lokal di ponsel
  • Streaming jarak jauh, seperti yang terdeteksi pada perangkat eksternal atau sesi transmisi
  • Sesi sebelumnya yang dapat dilanjutkan, sesuai urutan pemutaran terakhirnya

Pengguna dapat memulai ulang sesi sebelumnya dari carousel tanpa harus memulai aplikasi. Saat pemutaran dimulai, pengguna berinteraksi dengan kontrol media seperti biasa.

Mendukung pelanjutan pemutaran

Untuk menggunakan fitur ini, Anda harus mengaktifkan Pelanjutan media dalam setelan Opsi Developer.

Agar aplikasi pemutar media muncul di area setelan cepat, Anda harus membuat notifikasi MediaStyle dengan token MediaSession yang valid.

Untuk menampilkan ikon merek bagi pemutar media, gunakan NotificationBuilder.setSmallIcon().

Untuk mendukung pelanjutan pemutaran, aplikasi harus mengimplementasikan MediaBrowserService dan MediaSession.

Implementasi MediaBrowserService

Setelah perangkat melakukan booting, sistem akan mencari lima aplikasi media yang terakhir digunakan, lalu menyediakan kontrol yang dapat digunakan untuk memulai ulang pemutaran dari setiap aplikasi.

Sistem akan mencoba menghubungi MediaBrowserService dengan koneksi dari SystemUI. Aplikasi Anda harus mengizinkan koneksi semacam ini, karena jika tidak, aplikasi tidak dapat mendukung pelanjutan pemutaran.

Koneksi dari SystemUI dapat diidentifikasi dan diverifikasi menggunakan nama paket com.android.systemui dan tanda tangan. SystemUI ditandatangani dengan tanda tangan platform. Lihat contoh cara memeriksa tanda tangan platform di aplikasi UAMP.

Untuk mendukung pelanjutan pemutaran, MediaBrowserService harus mengimplementasikan perilaku berikut:

  • onGetRoot() harus menampilkan root non-null dengan cepat. Logika kompleks lainnya harus ditangani di onLoadChildren()

  • Saat onLoadChildren() dipanggil pada ID media root, hasilnya harus memuat turunan FLAG_PLAYABLE.

  • MediaBrowserService harus menampilkan item media yang terakhir diputar saat menerima kueri EXTRA_RECENT. Nilai yang dihasilkan harus berupa item media aktual, bukan fungsi generik.

  • MediaBrowserService harus menyediakan MediaDescription yang sesuai, dengan judul dan subjudul yang tidak kosong. Class ini juga harus menetapkan URI ikon atau bitmap ikon.

Contoh kode berikut ini menggambarkan cara mengimplementasikan onGetRoot().

Kotlin

override fun onGetRoot(
    clientPackageName: String,
    clientUid: Int,
    rootHints: Bundle?
): BrowserRoot? {
    ...
    // Verify that the specified package is SystemUI. You'll need to write your
    // own logic to do this.
    if (isSystem(clientPackageName, clientUid)) {
        rootHints?.let {
            if (it.getBoolean(BrowserRoot.EXTRA_RECENT)) {
                // Return a tree with a single playable media item for resumption.
                return BrowserRoot(MY_RECENTS_ROOT_ID, null)
            }
        }
        // You can return your normal tree if the EXTRA_RECENT flag is not present.
        return BrowserRoot(MY_MEDIA_ROOT_ID, null)
    }
    // Return an empty tree to disallow browsing.
    return BrowserRoot(MY_EMPTY_ROOT_ID, null)

Java

@Override
public BrowserRoot onGetRoot(String clientPackageName, int clientUid,
    Bundle rootHints) {
    ...
    // Verify that the specified package is SystemUI. You'll need to write your
    // own logic to do this.
    if (isSystem(clientPackageName, clientUid)) {
        if (rootHints != null) {
            if (rootHints.getBoolean(BrowserRoot.EXTRA_RECENT)) {
                // Return a tree with a single playable media item for resumption.
                return new BrowserRoot(MY_RECENTS_ROOT_ID, null);
            }
        }
        // You can return your normal tree if the EXTRA_RECENT flag is not present.
        return new BrowserRoot(MY_MEDIA_ROOT_ID, null);
    }
    // Return an empty tree to disallow browsing.
    return new BrowserRoot(MY_EMPTY_ROOT_ID, null);
}

Implementasi MediaSession

Sistem mengambil informasi berikut dari MediaMetadata MediaSession, lalu menampilkannya saat tersedia:

  • METADATA_KEY_ALBUM_ART_URI
  • METADATA_KEY_TITLE
  • METADATA_KEY_ARTIST
  • METADATA_KEY_DURATION (Jika durasi tidak ditetapkan, kolom pencari tidak akan menampilkan progres)

Untuk mendukung pelanjutan pemutaran, MediaSession harus mengimplementasikan callback MediaSession untuk onPlay().

Pemutar media menampilkan waktu berlalu untuk media yang sedang diputar, beserta kolom pencari yang dipetakan ke MediaSession PlaybackState.

Agar kolom pencari berfungsi dengan benar, Anda harus mengimplementasikan PlaybackState.Builder#setActions dan menyertakan ACTION_SEEK_TO. Jika tidak, pemutar hanya akan menampilkan waktu berlalu dan durasi.

Untuk menentukan kontrol pemutar, gunakan Notification.Builder#setCustomActions. Hanya tindakan yang ditunjukkan dengan Notification.MediaStyle#setShowsActionsInCompactView yang akan ditampilkan pada pemutar media dalam setelan cepat yang diciutkan.