Menampilkan kartu now playing

Aplikasi TV harus menampilkan kartu Now Playing saat memutar media di belakang peluncur atau di latar belakang. Kartu ini memungkinkan pengguna kembali ke aplikasi yang sedang memutar media.

Framework Android menampilkan kartu Now Playing di layar utama ketika ada MediaSession yang aktif. Kartu ini mencakup metadata media, seperti gambar album, judul, dan ikon aplikasi. Saat pengguna memilih kartu, sistem akan membuka aplikasi.

Tutorial ini menunjukkan cara menggunakan kelas MediaSession untuk mengimplementasikan kartu Now Playing.

Gambar 1. Menampilkan kartu Now Playing ketika memutar media di latar belakang.

Memulai sesi media

Buat MediaSession ketika aplikasi sedang bersiap untuk memutar media. Cuplikan kode berikut adalah contoh cara menyetel callback dan tanda yang sesuai:

Kotlin

    session = MediaSession(this, "MusicService").apply {
        setCallback(MediaSessionCallback())
        setFlags(
                MediaSession.FLAG_HANDLES_MEDIA_BUTTONS or MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS
        )
    }
    

Java

    session = new MediaSession(this, "MusicService");
    session.setCallback(new MediaSessionCallback());
    session.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS |
            MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);
    

Catatan: Kartu Now Playing hanya akan ditampilkan untuk sesi media dengan tanda FLAG_HANDLES_TRANSPORT_CONTROLS yang disetel.

Menampilkan kartu now playing

Kartu Now Playing hanya akan muncul untuk sesi yang aktif. Anda harus memanggil setActive(true) saat pemutaran dimulai. Aplikasi juga harus meminta fokus audio, seperti yang dijelaskan dalam Mengelola fokus audio.

Kotlin

    private fun handlePlayRequest() {

        tryToGetAudioFocus()

        if (!session.isActive) {
            session.isActive = true
        }
        ...
    }
    

Java

    private void handlePlayRequest() {

        tryToGetAudioFocus();

        if (!session.isActive()) {
            session.setActive(true);
        }
        ...
    }
    

Kartu disingkirkan dari layar peluncur ketika panggilan setActive(false) menonaktifkan sesi media, atau ketika aplikasi lain memulai pemutaran media. Jika pemutaran dihentikan sepenuhnya dan tidak ada media yang aktif, aplikasi harus langsung menonaktifkan sesi media. Jika pemutaran dijeda, aplikasi harus menonaktifkan sesi media setelah penundaan, biasanya antara 5 hingga 30 menit.

Memperbarui status pemutaran

Perbarui status pemutaran dalam MediaSession sehingga kartu bisa menampilkan status media yang sedang berjalan.

Kotlin

    private fun updatePlaybackState() {
        val position: Long =
                mediaPlayer
                        ?.takeIf { it.isPlaying }
                        ?.currentPosition?.toLong()
                        ?: PlaybackState.PLAYBACK_POSITION_UNKNOWN

        val stateBuilder = PlaybackState.Builder()
                .setActions(getAvailableActions()).apply {
                    setState(mState, position, 1.0f)
                }
        session.setPlaybackState(stateBuilder.build())
    }

    private fun getAvailableActions(): Long {
        var actions = (PlaybackState.ACTION_PLAY_PAUSE
                or PlaybackState.ACTION_PLAY_FROM_MEDIA_ID
                or PlaybackState.ACTION_PLAY_FROM_SEARCH)

        playingQueue?.takeIf { it.isNotEmpty() }?.apply {
            actions = if (mState == PlaybackState.STATE_PLAYING) {
                actions or PlaybackState.ACTION_PAUSE
            } else {
                actions or PlaybackState.ACTION_PLAY
            }
            if (currentIndexOnQueue > 0) {
                actions = actions or PlaybackState.ACTION_SKIP_TO_PREVIOUS
            }
            if (currentIndexOnQueue < size - 1) {
                actions = actions or PlaybackState.ACTION_SKIP_TO_NEXT
            }
        }
        return actions
    }
    

Java

    private void updatePlaybackState() {
        long position = PlaybackState.PLAYBACK_POSITION_UNKNOWN;
        if (mediaPlayer != null && mediaPlayer.isPlaying()) {
            position = mediaPlayer.getCurrentPosition();
        }
        PlaybackState.Builder stateBuilder = new PlaybackState.Builder()
                .setActions(getAvailableActions());
        stateBuilder.setState(mState, position, 1.0f);
        session.setPlaybackState(stateBuilder.build());
    }

    private long getAvailableActions() {
        long actions = PlaybackState.ACTION_PLAY_PAUSE |
                PlaybackState.ACTION_PLAY_FROM_MEDIA_ID |
                PlaybackState.ACTION_PLAY_FROM_SEARCH;
        if (playingQueue == null || playingQueue.isEmpty()) {
            return actions;
        }
        if (mState == PlaybackState.STATE_PLAYING) {
            actions |= PlaybackState.ACTION_PAUSE;
        } else {
            actions |= PlaybackState.ACTION_PLAY;
        }
        if (currentIndexOnQueue > 0) {
            actions |= PlaybackState.ACTION_SKIP_TO_PREVIOUS;
        }
        if (currentIndexOnQueue < playingQueue.size() - 1) {
            actions |= PlaybackState.ACTION_SKIP_TO_NEXT;
        }
        return actions;
    }
    

Menampilkan metadata media

Setel MediaMetadata dengan metode setMetadata(). Metode objek sesi media ini memungkinkan Anda menyediakan informasi pada kartu Now Playing tentang lagu tersebut, seperti judul, subjudul, dan berbagai ikon. Contoh berikut menganggap data lagu Anda disimpan di kelas data khusus, MediaData.

Kotlin

    private fun updateMetadata(myData: MediaData) {
        val metadataBuilder = MediaMetadata.Builder().apply {
            // To provide most control over how an item is displayed set the
            // display fields in the metadata
            putString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE, myData.displayTitle)
            putString(MediaMetadata.METADATA_KEY_DISPLAY_SUBTITLE, myData.displaySubtitle)
            putString(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI, myData.artUri)
            // And at minimum the title and artist for legacy support
            putString(MediaMetadata.METADATA_KEY_TITLE, myData.title)
            putString(MediaMetadata.METADATA_KEY_ARTIST, myData.artist)
            // A small bitmap for the artwork is also recommended
            putBitmap(MediaMetadata.METADATA_KEY_ART, myData.artBitmap)
            // Add any other fields you have for your data as well
        }
        session.setMetadata(metadataBuilder.build())
    }
    

Java

    private void updateMetadata(MediaData myData) {
        MediaMetadata.Builder metadataBuilder = new MediaMetadata.Builder();
        // To provide most control over how an item is displayed set the
        // display fields in the metadata
        metadataBuilder.putString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE,
                myData.displayTitle);
        metadataBuilder.putString(MediaMetadata.METADATA_KEY_DISPLAY_SUBTITLE,
                myData.displaySubtitle);
        metadataBuilder.putString(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI,
                myData.artUri);
        // And at minimum the title and artist for legacy support
        metadataBuilder.putString(MediaMetadata.METADATA_KEY_TITLE,
                myData.title);
        metadataBuilder.putString(MediaMetadata.METADATA_KEY_ARTIST,
                myData.artist);
        // A small bitmap for the artwork is also recommended
        metadataBuilder.putBitmap(MediaMetadata.METADATA_KEY_ART,
                myData.artBitmap);
        // Add any other fields you have for your data as well
        session.setMetadata(metadataBuilder.build());
    }
    

Merespons tindakan pengguna

Ketika pengguna memilih kartu Now Playing , sistem akan membuka aplikasi yang memiliki sesi tersebut. Jika aplikasi memberikan PendingIntent ke setSessionActivity(), sistem akan meluncurkan aktivitas yang Anda tentukan, seperti yang ditunjukkan di bawah ini. Jika tidak, intent sistem default akan terbuka. Aktivitas yang ditentukan harus menyediakan kontrol pemutaran yang memungkinkan pengguna menjeda atau menghentikan pemutaran.

Kotlin

    val pi: PendingIntent = Intent(context, MyActivity::class.java).let { intent ->
        PendingIntent.getActivity(
                context, 99 /*request code*/,
                intent,
                PendingIntent.FLAG_UPDATE_CURRENT
        )
    }
    session.setSessionActivity(pi)
    

Java

    Intent intent = new Intent(context, MyActivity.class);
    PendingIntent pi = PendingIntent.getActivity(context, 99 /*request code*/,
            intent, PendingIntent.FLAG_UPDATE_CURRENT);
    session.setSessionActivity(pi);