Search code examples
androidnotificationsandroid-mediaplayermediaplayback

Android 13 playbackstate callback not called ( from notification buttons)


For mediaplayer, ACTION_SKIP_TO_NEXT and ACTION_SKIP_TO_PREVIOUS both are working fine from notification buttons for android 12 and below. it seems that android 13 has a different behavior according to this.

to be clear, below buttons in the pictures are not working in android 13 only. enter image description here

Android developer mentioned that playbackstate should be used for android 13

"For apps targeting Android 13 (API level 33) and higher, the system derives media controls from PlaybackState actions."

the problem is that in android 13 playstechange is never called, even public int onStartCommand is never called.

tried below code but even no use

        ComponentName receiver = new ComponentName(this, MediaButtonReceiver.class);
    mediaSession = new MediaSessionCompat(getApplicationContext(), "MediaSession", receiver, null);
    mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
            MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);

    mediaSession.setPlaybackState(new PlaybackStateCompat.Builder()
            .setState(PlaybackStateCompat.STATE_PAUSED, 0, 0)
            .setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE)
            .setActions(PlaybackStateCompat.ACTION_SKIP_TO_NEXT)                .setActions(PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS)
            .build());

    mediaSession.setActive(true);

 mediaSession.setCallback(new MediaSessionCompat.Callback() {
        // Implement callbacks

        @Override
        public boolean onMediaButtonEvent(Intent mediaButtonEvent) {
            final String intentAction = mediaButtonEvent.getAction();

            if (Intent.ACTION_MEDIA_BUTTON.equals(intentAction)) {
                final KeyEvent event = mediaButtonEvent.getParcelableExtra(
                        Intent.EXTRA_KEY_EVENT);
                if (event == null) {
                    return super.onMediaButtonEvent(mediaButtonEvent);
                }
                final int keycode = event.getKeyCode();
                final int action = event.getAction();
                if (event.getRepeatCount() == 0 && action == KeyEvent.ACTION_DOWN) {
                    switch (keycode) {
                        case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
                            if (mediaPlayer != null) {
                                if (isPlaying()) {
                                    playbackAction(1);                                        
                                    pauseMedia();                                        
                                    updateMetaData();
                                } else { // want to continue playing
                                    playbackAction(0);
                                    playMedia();
                                }
                            }                              
                            break;
                        case KeyEvent.KEYCODE_MEDIA_PAUSE:
                            pauseMedia();
                            break;
                        case KeyEvent.KEYCODE_MEDIA_PLAY:

                            process_play_request();
                            break;
                        case KeyEvent.KEYCODE_MEDIA_NEXT:
                            skipToPrevious();
                            break;
                        case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
                            skipToNext();
                            break;
                    }
                }
            }
            return super.onMediaButtonEvent(mediaButtonEvent);
        }});
    

and tried to add this code, but also no use:

         MediaControllerCompat mController;

    mController = new MediaControllerCompat(this, mediaSession.getSessionToken());


    mController.registerCallback(mCallback);
    mCallback.onPlaybackStateChanged(mController.getPlaybackState());
    mCallback.onMetadataChanged(mController.getMetadata());

private final MediaControllerCompat.Callback mCallback = new MediaControllerCompat.Callback() {
    @Override
    public void onPlaybackStateChanged(PlaybackStateCompat playbackState) {
        onUpdate();
    }

    @Override
    public void onMetadataChanged(MediaMetadataCompat metadata) {
        onUpdate();
    }

    @Override
    public void onSessionDestroyed() {
    }

    private void onUpdate() {
    }
};

This issue has no relation to android.permission.POST_NOTIFICATIONS as runtime permission is requested and granted but still no use.

Noting that after media player perpared, SetState is called as below:

mediaPlayer.start();

            setState(PlaybackStateCompat.STATE_PLAYING);

private void setState(int state) {
    long position = 0;

    PlaybackStateCompat.Builder builder = new PlaybackStateCompat.Builder();
    builder.setState(state, position, 1.0f);
    builder.setActions(
            PlaybackStateCompat.ACTION_PLAY |
                    PlaybackStateCompat.ACTION_STOP |
                    PlaybackStateCompat.ACTION_PAUSE |
                    PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS |
                    PlaybackStateCompat.ACTION_SKIP_TO_NEXT);
    mediaSession.setPlaybackState(builder.build());


}

suggestions please


Solution

  • Please try to add a few override methods to your MediaSessionCompat.Callback():

    mediaSession.setCallback(new MediaSessionCompat.Callback() {
        // Implement callbacks
        @Override
        public boolean onMediaButtonEvent(Intent mediaButtonEvent) {
            // your implements
        }
    
        @Override
        public void onPlay() {
            super.onPlay();
            // your play() implements
        }
    
        @Override
        public void onPause() {
            super.onPause();
            // your pause() implements
        }
    
        @Override
        public void onSkipToNext() {
            super.onSkipToNext();
            // your next() implements
        }
    
        @Override
        public void onSkipToPrevious() {
            super.onSkipToPrevious();
            // your prev() implements
        }
    
        @Override
        public void onSeekTo(long pos) {
            // your seek() implements
        }
    });
    

    You will receive the action buttons event in these callbacks.