Search code examples
androidandroid-notificationslockscreenandroid-music-playerandroid-mediasession

Lockscreen controls not working on Xiaomi devices


I'm trying to build lockscreen controls for my music player app. I have successfully built a mediastyle notification with playback controls(working perfectly). The lockscreen controls on Xiaomi devices are always sending the same pending intent (android.intent.action.MEDIA_BUTTON) while in other devices it is perfectly firing the expected intent.

How are two devices running on the same code firing two different intents?

Code for notification :

private void buildNotifications(final PlaybackStatus playbackStatus) {

        Intent intent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 100, intent, 0);
        Intent intent1 = new Intent(this, MediaPlayerService.class).setAction(ConstantsForBroadCast.ACTION_KILL_APP);
        PendingIntent pendingIntent1 = PendingIntent.getService(this.getApplicationContext(), 0, intent1, 0);

        int notificationAction = R.drawable.play_song;//needs to be initialized
        PendingIntent play_pauseAction = null;


        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

            createChannel();
        }

        notiB = new NotificationCompat.Builder(this, CHANNEL_ID);


        //Build a new notification according to the current state of the MediaPlayer
        if (playbackStatus == PlaybackStatus.PLAYING) {
            notificationAction = R.drawable.pause_song;

            //create the pause action
            play_pauseAction = playbackAction(1);
        } else if (playbackStatus == PlaybackStatus.PAUSED) {
            notificationAction = R.drawable.play_song;

            //create the play action
            play_pauseAction = playbackAction(0);
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {


            if (!Build.MANUFACTURER.equalsIgnoreCase("Huawei")) {
                notiB.setStyle(new MediaStyle()
                        .setMediaSession(mediaSession.getSessionToken())
                        .setShowActionsInCompactView(0, 1, 2));
            }


        } else {


            if (!Build.MANUFACTURER.equalsIgnoreCase("Huawei")) {
                notiB.setStyle(new MediaStyle()
                        .setMediaSession(mediaSession.getSessionToken())
                        .setCancelButtonIntent(pendingIntent1)
                        .setShowCancelButton(true)
                        .setShowActionsInCompactView(0, 1, 2));
            }


        }
        notiB.setSmallIcon(R.drawable.identifysong);
        notiB.setOngoing(playbackStatus == PlaybackStatus.PLAYING);
        notiB.setContentIntent(pendingIntent);
        notiB.setDeleteIntent(pendingIntent1);
        notiB.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
        notiB.setContentTitle(songInfoModelService.getSongName());
        notiB.setContentText(songInfoModelService.getArtistName());
        notiB.addAction(R.drawable.previous_song, "previous", playbackAction(3));
        notiB.addAction(notificationAction, "pause", play_pauseAction);
        notiB.addAction(R.drawable.next_song, "next", playbackAction(2));


        Glide.with(this).asBitmap().load(songInfoModelService.getAlbumIDArtwork()).apply(new RequestOptions()).listener(new RequestListener<Bitmap>() {
            @Override
            public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Bitmap> target, boolean isFirstResource) {

                Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.placeholder);
                notiB.setLargeIcon(bm);
                notification = notiB.build();
                showNotification(notification, playbackStatus);


                return true;
            }

            @Override
            public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) {

                notiB.setLargeIcon(resource);
                notification = notiB.build();
                showNotification(notification, playbackStatus);

                return true;
            }
        }).submit();


    }

    private void showNotification(Notification notification, PlaybackStatus playbackStatus) {

        if (!isNotiAlive) {

            this.startForeground(NOTIFICATION_ID, notification);
            isNotiAlive = true;

        } else {

            notificationManager.notify(NOTIFICATION_ID, notification);
        }

        if (playbackStatus == PlaybackStatus.PAUSED) {

            this.stopForeground(false);
            isNotiAlive = false;
        }


    }

Code for assigning pending intent:

private PendingIntent playbackAction(int actionNumber) {
        Intent playbackAction = new Intent(this, MediaPlayerService.class);
        switch (actionNumber) {
            case 0:
                // Play
                playbackAction.setAction(ConstantsForBroadCast.ACTION_PLAY_FROM_NOTI);
                return PendingIntent.getService(this, actionNumber, playbackAction, 0);
            case 1:
                // Pause
                playbackAction.setAction(ConstantsForBroadCast.ACTION_PAUSE_FROM_NOTI);
                return PendingIntent.getService(this, actionNumber, playbackAction, 0);
            case 2:
                // Next track
                playbackAction.setAction(ConstantsForBroadCast.ACTION_PLAY_NEXT);
                return PendingIntent.getService(this, actionNumber, playbackAction, 0);
            case 3:
                // Previous track
                playbackAction.setAction(ConstantsForBroadCast.ACTION_PLAY_PREVIOUS);
                return PendingIntent.getService(this, actionNumber, playbackAction, 0);
            default:
                break;
        }
        return null;
    }

Code for MediaSession:

 private void initMediaSession() throws RemoteException {
        if (mediaSessionManager != null) return; //mediaSessionManager exists

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            mediaSessionManager = (MediaSessionManager) getSystemService(Context.MEDIA_SESSION_SERVICE);
        }

        mediaSession = new MediaSessionCompat(this, "AudioPlayer", mReceiverComponent, null);

        transportControls = mediaSession.getController().getTransportControls();

        mediaSession.setActive(true);

        mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS | MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS);



        updateMetaData();


        mediaSession.setCallback(new MediaSessionCompat.Callback() {
            @Override
            public void onPlay() {
                super.onPlay();

                resumeMedia();
            }

            @Override
            public void onPause() {
                super.onPause();

                pauseMedia();
            }

            @Override
            public void onSkipToNext() {
                super.onSkipToNext();
                skipToNext();

            }

            @Override
            public void onSkipToPrevious() {
                super.onSkipToNext();
                skipToPrevious();

            }

            @Override
            public boolean onMediaButtonEvent(Intent mediaButtonIntent) {



                return super.onMediaButtonEvent(mediaButtonIntent);
            }
        });


    }

Solution

  • In your onMediaButtonEvent is where you need to receive the media button type. The action of the Intent there will always be MEDIA_BUTTON, but the extras will change.

    @Override
    public boolean onMediaButtonEvent(Intent eventIntent) {
        KeyEvent event = eventIntent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
        //compare event.getKeyCode() with the relevant KeyEvent static constants
    }