mirror of
https://github.com/KDE/kdeconnect-android
synced 2025-09-03 23:55:08 +00:00
Copy the ref to MpriMprisPlayer since the field can become null
Create a local copy of the reference, otherwise other fields can set the field to null while the function is running and cause a NPE.
This commit is contained in:
@@ -168,12 +168,13 @@ public class MprisMediaSession implements
|
|||||||
* Prefers playing devices/mpris players, but tries to keep displaying the same
|
* Prefers playing devices/mpris players, but tries to keep displaying the same
|
||||||
* player and device, while possible.
|
* player and device, while possible.
|
||||||
*/
|
*/
|
||||||
private void updateCurrentPlayer() {
|
private MprisPlugin.MprisPlayer updateCurrentPlayer() {
|
||||||
Pair<Device, MprisPlugin.MprisPlayer> player = findPlayer();
|
Pair<Device, MprisPlugin.MprisPlayer> player = findPlayer();
|
||||||
|
|
||||||
//Update the last-displayed device and player
|
//Update the last-displayed device and player
|
||||||
notificationDevice = player.first == null ? null : player.first.getDeviceId();
|
notificationDevice = player.first == null ? null : player.first.getDeviceId();
|
||||||
notificationPlayer = player.second;
|
notificationPlayer = player.second;
|
||||||
|
return notificationPlayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Pair<Device, MprisPlugin.MprisPlayer> findPlayer() {
|
private Pair<Device, MprisPlugin.MprisPlayer> findPlayer() {
|
||||||
@@ -273,10 +274,10 @@ public class MprisMediaSession implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Make sure our information is up-to-date
|
//Make sure our information is up-to-date
|
||||||
updateCurrentPlayer();
|
MprisPlugin.MprisPlayer currentPlayer = updateCurrentPlayer();
|
||||||
|
|
||||||
//If the player disappeared (and no other playing one found), just remove the notification
|
//If the player disappeared (and no other playing one found), just remove the notification
|
||||||
if (notificationPlayer == null) {
|
if (currentPlayer == null) {
|
||||||
closeMediaNotification();
|
closeMediaNotification();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -285,20 +286,20 @@ public class MprisMediaSession implements
|
|||||||
|
|
||||||
MediaMetadataCompat.Builder metadata = new MediaMetadataCompat.Builder();
|
MediaMetadataCompat.Builder metadata = new MediaMetadataCompat.Builder();
|
||||||
|
|
||||||
metadata.putString(MediaMetadataCompat.METADATA_KEY_TITLE, notificationPlayer.getTitle());
|
metadata.putString(MediaMetadataCompat.METADATA_KEY_TITLE, currentPlayer.getTitle());
|
||||||
|
|
||||||
if (!notificationPlayer.getArtist().isEmpty()) {
|
if (!currentPlayer.getArtist().isEmpty()) {
|
||||||
metadata.putString(MediaMetadataCompat.METADATA_KEY_AUTHOR, notificationPlayer.getArtist());
|
metadata.putString(MediaMetadataCompat.METADATA_KEY_AUTHOR, currentPlayer.getArtist());
|
||||||
metadata.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, notificationPlayer.getArtist());
|
metadata.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, currentPlayer.getArtist());
|
||||||
}
|
}
|
||||||
if (!notificationPlayer.getAlbum().isEmpty()) {
|
if (!currentPlayer.getAlbum().isEmpty()) {
|
||||||
metadata.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, notificationPlayer.getAlbum());
|
metadata.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, currentPlayer.getAlbum());
|
||||||
}
|
}
|
||||||
if (notificationPlayer.getLength() > 0) {
|
if (currentPlayer.getLength() > 0) {
|
||||||
metadata.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, notificationPlayer.getLength());
|
metadata.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, currentPlayer.getLength());
|
||||||
}
|
}
|
||||||
|
|
||||||
Bitmap albumArt = notificationPlayer.getAlbumArt();
|
Bitmap albumArt = currentPlayer.getAlbumArt();
|
||||||
if (albumArt != null) {
|
if (albumArt != null) {
|
||||||
metadata.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, albumArt);
|
metadata.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, albumArt);
|
||||||
}
|
}
|
||||||
@@ -306,17 +307,17 @@ public class MprisMediaSession implements
|
|||||||
mediaSession.setMetadata(metadata.build());
|
mediaSession.setMetadata(metadata.build());
|
||||||
PlaybackStateCompat.Builder playbackState = new PlaybackStateCompat.Builder();
|
PlaybackStateCompat.Builder playbackState = new PlaybackStateCompat.Builder();
|
||||||
|
|
||||||
if (notificationPlayer.isPlaying()) {
|
if (currentPlayer.isPlaying()) {
|
||||||
playbackState.setState(PlaybackStateCompat.STATE_PLAYING, notificationPlayer.getPosition(), 1.0f);
|
playbackState.setState(PlaybackStateCompat.STATE_PLAYING, currentPlayer.getPosition(), 1.0f);
|
||||||
} else {
|
} else {
|
||||||
playbackState.setState(PlaybackStateCompat.STATE_PAUSED, notificationPlayer.getPosition(), 0.0f);
|
playbackState.setState(PlaybackStateCompat.STATE_PAUSED, currentPlayer.getPosition(), 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Create all actions (previous/play/pause/next)
|
//Create all actions (previous/play/pause/next)
|
||||||
Intent iPlay = new Intent(context, MprisMediaNotificationReceiver.class);
|
Intent iPlay = new Intent(context, MprisMediaNotificationReceiver.class);
|
||||||
iPlay.setAction(MprisMediaNotificationReceiver.ACTION_PLAY);
|
iPlay.setAction(MprisMediaNotificationReceiver.ACTION_PLAY);
|
||||||
iPlay.putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice);
|
iPlay.putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice);
|
||||||
iPlay.putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, notificationPlayer.getPlayerName());
|
iPlay.putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, currentPlayer.getPlayerName());
|
||||||
PendingIntent piPlay = PendingIntent.getBroadcast(context, 0, iPlay, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
|
PendingIntent piPlay = PendingIntent.getBroadcast(context, 0, iPlay, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
|
||||||
NotificationCompat.Action.Builder aPlay = new NotificationCompat.Action.Builder(
|
NotificationCompat.Action.Builder aPlay = new NotificationCompat.Action.Builder(
|
||||||
R.drawable.ic_play_white, context.getString(R.string.mpris_play), piPlay);
|
R.drawable.ic_play_white, context.getString(R.string.mpris_play), piPlay);
|
||||||
@@ -324,7 +325,7 @@ public class MprisMediaSession implements
|
|||||||
Intent iPause = new Intent(context, MprisMediaNotificationReceiver.class);
|
Intent iPause = new Intent(context, MprisMediaNotificationReceiver.class);
|
||||||
iPause.setAction(MprisMediaNotificationReceiver.ACTION_PAUSE);
|
iPause.setAction(MprisMediaNotificationReceiver.ACTION_PAUSE);
|
||||||
iPause.putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice);
|
iPause.putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice);
|
||||||
iPause.putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, notificationPlayer.getPlayerName());
|
iPause.putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, currentPlayer.getPlayerName());
|
||||||
PendingIntent piPause = PendingIntent.getBroadcast(context, 0, iPause, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
|
PendingIntent piPause = PendingIntent.getBroadcast(context, 0, iPause, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
|
||||||
NotificationCompat.Action.Builder aPause = new NotificationCompat.Action.Builder(
|
NotificationCompat.Action.Builder aPause = new NotificationCompat.Action.Builder(
|
||||||
R.drawable.ic_pause_white, context.getString(R.string.mpris_pause), piPause);
|
R.drawable.ic_pause_white, context.getString(R.string.mpris_pause), piPause);
|
||||||
@@ -332,7 +333,7 @@ public class MprisMediaSession implements
|
|||||||
Intent iPrevious = new Intent(context, MprisMediaNotificationReceiver.class);
|
Intent iPrevious = new Intent(context, MprisMediaNotificationReceiver.class);
|
||||||
iPrevious.setAction(MprisMediaNotificationReceiver.ACTION_PREVIOUS);
|
iPrevious.setAction(MprisMediaNotificationReceiver.ACTION_PREVIOUS);
|
||||||
iPrevious.putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice);
|
iPrevious.putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice);
|
||||||
iPrevious.putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, notificationPlayer.getPlayerName());
|
iPrevious.putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, currentPlayer.getPlayerName());
|
||||||
PendingIntent piPrevious = PendingIntent.getBroadcast(context, 0, iPrevious, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
|
PendingIntent piPrevious = PendingIntent.getBroadcast(context, 0, iPrevious, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
|
||||||
NotificationCompat.Action.Builder aPrevious = new NotificationCompat.Action.Builder(
|
NotificationCompat.Action.Builder aPrevious = new NotificationCompat.Action.Builder(
|
||||||
R.drawable.ic_previous_white, context.getString(R.string.mpris_previous), piPrevious);
|
R.drawable.ic_previous_white, context.getString(R.string.mpris_previous), piPrevious);
|
||||||
@@ -340,14 +341,14 @@ public class MprisMediaSession implements
|
|||||||
Intent iNext = new Intent(context, MprisMediaNotificationReceiver.class);
|
Intent iNext = new Intent(context, MprisMediaNotificationReceiver.class);
|
||||||
iNext.setAction(MprisMediaNotificationReceiver.ACTION_NEXT);
|
iNext.setAction(MprisMediaNotificationReceiver.ACTION_NEXT);
|
||||||
iNext.putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice);
|
iNext.putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice);
|
||||||
iNext.putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, notificationPlayer.getPlayerName());
|
iNext.putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, currentPlayer.getPlayerName());
|
||||||
PendingIntent piNext = PendingIntent.getBroadcast(context, 0, iNext, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
|
PendingIntent piNext = PendingIntent.getBroadcast(context, 0, iNext, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
|
||||||
NotificationCompat.Action.Builder aNext = new NotificationCompat.Action.Builder(
|
NotificationCompat.Action.Builder aNext = new NotificationCompat.Action.Builder(
|
||||||
R.drawable.ic_next_white, context.getString(R.string.mpris_next), piNext);
|
R.drawable.ic_next_white, context.getString(R.string.mpris_next), piNext);
|
||||||
|
|
||||||
Intent iOpenActivity = new Intent(context, MprisActivity.class);
|
Intent iOpenActivity = new Intent(context, MprisActivity.class);
|
||||||
iOpenActivity.putExtra("deviceId", notificationDevice);
|
iOpenActivity.putExtra("deviceId", notificationDevice);
|
||||||
iOpenActivity.putExtra("player", notificationPlayer.getPlayerName());
|
iOpenActivity.putExtra("player", currentPlayer.getPlayerName());
|
||||||
|
|
||||||
PendingIntent piOpenActivity = TaskStackBuilder.create(context)
|
PendingIntent piOpenActivity = TaskStackBuilder.create(context)
|
||||||
.addNextIntentWithParentStack(iOpenActivity)
|
.addNextIntentWithParentStack(iOpenActivity)
|
||||||
@@ -364,28 +365,28 @@ public class MprisMediaSession implements
|
|||||||
.setVisibility(androidx.core.app.NotificationCompat.VISIBILITY_PUBLIC)
|
.setVisibility(androidx.core.app.NotificationCompat.VISIBILITY_PUBLIC)
|
||||||
.setSubText(KdeConnect.getInstance().getDevice(notificationDevice).getName());
|
.setSubText(KdeConnect.getInstance().getDevice(notificationDevice).getName());
|
||||||
|
|
||||||
notification.setContentTitle(notificationPlayer.getTitle());
|
notification.setContentTitle(currentPlayer.getTitle());
|
||||||
|
|
||||||
//Only set the notification body text if we have an author and/or album
|
//Only set the notification body text if we have an author and/or album
|
||||||
if (!notificationPlayer.getArtist().isEmpty() && !notificationPlayer.getAlbum().isEmpty()) {
|
if (!currentPlayer.getArtist().isEmpty() && !currentPlayer.getAlbum().isEmpty()) {
|
||||||
notification.setContentText(notificationPlayer.getArtist() + " - " + notificationPlayer.getAlbum() + " (" + notificationPlayer.getPlayerName() + ")");
|
notification.setContentText(currentPlayer.getArtist() + " - " + currentPlayer.getAlbum() + " (" + currentPlayer.getPlayerName() + ")");
|
||||||
} else if (!notificationPlayer.getArtist().isEmpty()) {
|
} else if (!currentPlayer.getArtist().isEmpty()) {
|
||||||
notification.setContentText(notificationPlayer.getArtist() + " (" + notificationPlayer.getPlayerName() + ")");
|
notification.setContentText(currentPlayer.getArtist() + " (" + currentPlayer.getPlayerName() + ")");
|
||||||
} else if (!notificationPlayer.getAlbum().isEmpty()) {
|
} else if (!currentPlayer.getAlbum().isEmpty()) {
|
||||||
notification.setContentText(notificationPlayer.getAlbum() + " (" + notificationPlayer.getPlayerName() + ")");
|
notification.setContentText(currentPlayer.getAlbum() + " (" + currentPlayer.getPlayerName() + ")");
|
||||||
} else {
|
} else {
|
||||||
notification.setContentText(notificationPlayer.getPlayerName());
|
notification.setContentText(currentPlayer.getPlayerName());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (albumArt != null) {
|
if (albumArt != null) {
|
||||||
notification.setLargeIcon(albumArt);
|
notification.setLargeIcon(albumArt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!notificationPlayer.isPlaying()) {
|
if (!currentPlayer.isPlaying()) {
|
||||||
Intent iCloseNotification = new Intent(context, MprisMediaNotificationReceiver.class);
|
Intent iCloseNotification = new Intent(context, MprisMediaNotificationReceiver.class);
|
||||||
iCloseNotification.setAction(MprisMediaNotificationReceiver.ACTION_CLOSE_NOTIFICATION);
|
iCloseNotification.setAction(MprisMediaNotificationReceiver.ACTION_CLOSE_NOTIFICATION);
|
||||||
iCloseNotification.putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice);
|
iCloseNotification.putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice);
|
||||||
iCloseNotification.putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, notificationPlayer.getPlayerName());
|
iCloseNotification.putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, currentPlayer.getPlayerName());
|
||||||
PendingIntent piCloseNotification = PendingIntent.getBroadcast(context, 0, iCloseNotification, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
|
PendingIntent piCloseNotification = PendingIntent.getBroadcast(context, 0, iCloseNotification, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
|
||||||
notification.setDeleteIntent(piCloseNotification);
|
notification.setDeleteIntent(piCloseNotification);
|
||||||
}
|
}
|
||||||
@@ -393,37 +394,37 @@ public class MprisMediaSession implements
|
|||||||
//Add media control actions
|
//Add media control actions
|
||||||
int numActions = 0;
|
int numActions = 0;
|
||||||
long playbackActions = 0;
|
long playbackActions = 0;
|
||||||
if (notificationPlayer.isGoPreviousAllowed()) {
|
if (currentPlayer.isGoPreviousAllowed()) {
|
||||||
notification.addAction(aPrevious.build());
|
notification.addAction(aPrevious.build());
|
||||||
playbackActions |= PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS;
|
playbackActions |= PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS;
|
||||||
++numActions;
|
++numActions;
|
||||||
}
|
}
|
||||||
if (notificationPlayer.isPlaying() && notificationPlayer.isPauseAllowed()) {
|
if (currentPlayer.isPlaying() && currentPlayer.isPauseAllowed()) {
|
||||||
notification.addAction(aPause.build());
|
notification.addAction(aPause.build());
|
||||||
playbackActions |= PlaybackStateCompat.ACTION_PAUSE;
|
playbackActions |= PlaybackStateCompat.ACTION_PAUSE;
|
||||||
++numActions;
|
++numActions;
|
||||||
}
|
}
|
||||||
if (!notificationPlayer.isPlaying() && notificationPlayer.isPlayAllowed()) {
|
if (!currentPlayer.isPlaying() && currentPlayer.isPlayAllowed()) {
|
||||||
notification.addAction(aPlay.build());
|
notification.addAction(aPlay.build());
|
||||||
playbackActions |= PlaybackStateCompat.ACTION_PLAY;
|
playbackActions |= PlaybackStateCompat.ACTION_PLAY;
|
||||||
++numActions;
|
++numActions;
|
||||||
}
|
}
|
||||||
if (notificationPlayer.isGoNextAllowed()) {
|
if (currentPlayer.isGoNextAllowed()) {
|
||||||
notification.addAction(aNext.build());
|
notification.addAction(aNext.build());
|
||||||
playbackActions |= PlaybackStateCompat.ACTION_SKIP_TO_NEXT;
|
playbackActions |= PlaybackStateCompat.ACTION_SKIP_TO_NEXT;
|
||||||
++numActions;
|
++numActions;
|
||||||
}
|
}
|
||||||
// Documentation says that this was added in Lollipop (21) but it seems to cause crashes on < Pie (28)
|
// Documentation says that this was added in Lollipop (21) but it seems to cause crashes on < Pie (28)
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
if (notificationPlayer.isSeekAllowed()) {
|
if (currentPlayer.isSeekAllowed()) {
|
||||||
playbackActions |= PlaybackStateCompat.ACTION_SEEK_TO;
|
playbackActions |= PlaybackStateCompat.ACTION_SEEK_TO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
playbackState.setActions(playbackActions);
|
playbackState.setActions(playbackActions);
|
||||||
mediaSession.setPlaybackState(playbackState.build());
|
mediaSession.setPlaybackState(playbackState.build());
|
||||||
|
|
||||||
//Only allow deletion if no music is notificationPlayer
|
//Only allow deletion if no music is currentPlayer
|
||||||
notification.setOngoing(notificationPlayer.isPlaying());
|
notification.setOngoing(currentPlayer.isPlaying());
|
||||||
|
|
||||||
//Use the MediaStyle notification, so it feels like other media players. That also allows adding actions
|
//Use the MediaStyle notification, so it feels like other media players. That also allows adding actions
|
||||||
MediaStyle mediaStyle = new MediaStyle();
|
MediaStyle mediaStyle = new MediaStyle();
|
||||||
|
Reference in New Issue
Block a user