mirror of
https://github.com/KDE/kdeconnect-android
synced 2025-08-29 13:17:43 +00:00
Fix NPEs and improve handling of nullability
This commit is contained in:
parent
d951e3faad
commit
c275e26e00
@ -52,7 +52,7 @@ class MprisMediaSession : OnSharedPreferenceChangeListener, NotificationReceiver
|
|||||||
private var spotifyRunning = false
|
private var spotifyRunning = false
|
||||||
|
|
||||||
// Holds the device and player displayed in the notification
|
// Holds the device and player displayed in the notification
|
||||||
private var notificationDevice: String? = null
|
private var notificationDeviceId: String? = null
|
||||||
private var notificationPlayer: MprisPlayer? = null
|
private var notificationPlayer: MprisPlayer? = null
|
||||||
|
|
||||||
// Holds the device ids for which we can display a notification
|
// Holds the device ids for which we can display a notification
|
||||||
@ -64,29 +64,27 @@ class MprisMediaSession : OnSharedPreferenceChangeListener, NotificationReceiver
|
|||||||
// Callback for control via the media session API
|
// Callback for control via the media session API
|
||||||
private val mediaSessionCallback: MediaSessionCompat.Callback = object : MediaSessionCompat.Callback() {
|
private val mediaSessionCallback: MediaSessionCompat.Callback = object : MediaSessionCompat.Callback() {
|
||||||
override fun onPlay() {
|
override fun onPlay() {
|
||||||
notificationPlayer!!.sendPlay()
|
notificationPlayer?.sendPlay()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
notificationPlayer!!.sendPause()
|
notificationPlayer?.sendPause()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSkipToNext() {
|
override fun onSkipToNext() {
|
||||||
notificationPlayer!!.sendNext()
|
notificationPlayer?.sendNext()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSkipToPrevious() {
|
override fun onSkipToPrevious() {
|
||||||
notificationPlayer!!.sendPrevious()
|
notificationPlayer?.sendPrevious()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStop() {
|
override fun onStop() {
|
||||||
if (notificationPlayer != null) {
|
notificationPlayer?.sendStop()
|
||||||
notificationPlayer!!.sendStop()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSeekTo(pos: Long) {
|
override fun onSeekTo(pos: Long) {
|
||||||
notificationPlayer!!.sendSetPosition(pos.toInt())
|
notificationPlayer?.sendSetPosition(pos.toInt())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,7 +99,7 @@ class MprisMediaSession : OnSharedPreferenceChangeListener, NotificationReceiver
|
|||||||
* @param device The device id
|
* @param device The device id
|
||||||
*/
|
*/
|
||||||
fun onCreate(context: Context?, plugin: MprisPlugin, device: String) {
|
fun onCreate(context: Context?, plugin: MprisPlugin, device: String) {
|
||||||
if (mprisDevices.isEmpty()) {
|
if (mprisDevices.isEmpty) {
|
||||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
prefs.registerOnSharedPreferenceChangeListener(this)
|
prefs.registerOnSharedPreferenceChangeListener(this)
|
||||||
}
|
}
|
||||||
@ -139,7 +137,7 @@ class MprisMediaSession : OnSharedPreferenceChangeListener, NotificationReceiver
|
|||||||
plugin.removePlayerListUpdatedHandler("media_notification")
|
plugin.removePlayerListUpdatedHandler("media_notification")
|
||||||
updateMediaNotification()
|
updateMediaNotification()
|
||||||
|
|
||||||
if (mprisDevices.isEmpty()) {
|
if (mprisDevices.isEmpty) {
|
||||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
prefs.unregisterOnSharedPreferenceChangeListener(this)
|
prefs.unregisterOnSharedPreferenceChangeListener(this)
|
||||||
}
|
}
|
||||||
@ -153,25 +151,27 @@ class MprisMediaSession : OnSharedPreferenceChangeListener, NotificationReceiver
|
|||||||
* player and device, while possible.
|
* player and device, while possible.
|
||||||
*/
|
*/
|
||||||
private fun updateCurrentPlayer(): MprisPlayer? {
|
private fun updateCurrentPlayer(): MprisPlayer? {
|
||||||
val player = findPlayer()
|
val player = findPlayer() ?: return null
|
||||||
|
|
||||||
// Update the last-displayed device and player
|
// Update the last-displayed device and player
|
||||||
notificationDevice = if (player.first == null) null else player.first!!.deviceId
|
notificationDeviceId = if (player.first == null) null else player.first.deviceId
|
||||||
notificationPlayer = player.second
|
notificationPlayer = player.second
|
||||||
return notificationPlayer
|
return notificationPlayer
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findPlayer(): Pair<Device?, MprisPlayer?> {
|
private fun findPlayer(): Pair<Device, MprisPlayer>? {
|
||||||
// First try the previously displayed player (if still playing) or the previous displayed device (otherwise)
|
val currentDevice = if (notificationDeviceId != null && mprisDevices.contains(notificationDeviceId)) {
|
||||||
if (notificationDevice != null && mprisDevices.contains(notificationDevice)) {
|
KdeConnect.getInstance().getDevice(notificationDeviceId)
|
||||||
val device = KdeConnect.getInstance().getDevice(notificationDevice)
|
|
||||||
val player = if (notificationPlayer != null && notificationPlayer!!.isPlaying) {
|
|
||||||
getPlayerFromDevice(device, notificationPlayer)
|
|
||||||
} else {
|
} else {
|
||||||
getPlayerFromDevice(device, null)
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// First try the previously displayed player (if still playing) or the previous displayed device (otherwise)
|
||||||
|
if (currentDevice != null) {
|
||||||
|
val playingPlayer = notificationPlayer?.takeIf { it.isPlaying }
|
||||||
|
val player = getPlayerFromDevice(currentDevice, playingPlayer)
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
return Pair(device, player)
|
return Pair(currentDevice, player)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,42 +186,33 @@ class MprisMediaSession : OnSharedPreferenceChangeListener, NotificationReceiver
|
|||||||
// So no player is playing. Try the previously displayed player again
|
// So no player is playing. Try the previously displayed player again
|
||||||
// This will succeed if it's paused:
|
// This will succeed if it's paused:
|
||||||
// that allows pausing and subsequently resuming via the notification
|
// that allows pausing and subsequently resuming via the notification
|
||||||
if (notificationDevice != null && mprisDevices.contains(notificationDevice)) {
|
if (currentDevice != null) {
|
||||||
val device = KdeConnect.getInstance().getDevice(notificationDevice)
|
val player = getPlayerFromDevice(currentDevice, notificationPlayer)
|
||||||
|
|
||||||
val player = getPlayerFromDevice(device, notificationPlayer)
|
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
return Pair(device, player)
|
return Pair(currentDevice, player)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Pair(null, null)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getPlayerFromDevice(device: Device?, preferredPlayer: MprisPlayer?): MprisPlayer? {
|
|
||||||
if (device == null || !mprisDevices.contains(device.deviceId)) return null
|
|
||||||
|
|
||||||
val plugin = device.getPlugin(MprisPlugin::class.java) ?: return null
|
|
||||||
|
|
||||||
// First try the preferred player, if supplied
|
|
||||||
if (plugin.hasPlayer(preferredPlayer) && shouldShowPlayer(preferredPlayer)) {
|
|
||||||
return preferredPlayer
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, accept any playing player
|
|
||||||
val player = plugin.playingPlayer
|
|
||||||
if (shouldShowPlayer(player)) {
|
|
||||||
return player
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun shouldShowPlayer(player: MprisPlayer?): Boolean {
|
private fun getPlayerFromDevice(device: Device, preferredPlayer: MprisPlayer?): MprisPlayer? {
|
||||||
return player != null && !(player.isSpotify && spotifyRunning)
|
if (!mprisDevices.contains(device.deviceId)) return null
|
||||||
|
|
||||||
|
val plugin = device.getPlugin(MprisPlugin::class.java) ?: return null
|
||||||
|
// First try the preferred player, if supplied & available, otherwise, accept any playing player
|
||||||
|
val player = preferredPlayer?.takeIf(plugin::hasPlayer)
|
||||||
|
?: plugin.playingPlayer
|
||||||
|
?: return null
|
||||||
|
return player.takeIf(::shouldShowPlayer)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun shouldShowPlayer(player: MprisPlayer): Boolean {
|
||||||
|
return !(player.isSpotify && spotifyRunning)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateRemoteDeviceVolumeControl() {
|
private fun updateRemoteDeviceVolumeControl() {
|
||||||
val plugin = KdeConnect.getInstance().getDevicePlugin(notificationDevice, SystemVolumePlugin::class.java)
|
val plugin = KdeConnect.getInstance().getDevicePlugin(notificationDeviceId, SystemVolumePlugin::class.java)
|
||||||
?: return
|
?: return
|
||||||
val systemVolumeProvider = fromPlugin(plugin)
|
val systemVolumeProvider = fromPlugin(plugin)
|
||||||
systemVolumeProvider.addStateListener(this)
|
systemVolumeProvider.addStateListener(this)
|
||||||
@ -250,7 +241,7 @@ class MprisMediaSession : OnSharedPreferenceChangeListener, NotificationReceiver
|
|||||||
// Make sure our information is up-to-date
|
// Make sure our information is up-to-date
|
||||||
val currentPlayer = updateCurrentPlayer()
|
val currentPlayer = updateCurrentPlayer()
|
||||||
|
|
||||||
val device = KdeConnect.getInstance().getDevice(notificationDevice)
|
val device = KdeConnect.getInstance().getDevice(notificationDeviceId)
|
||||||
if (device == null) {
|
if (device == null) {
|
||||||
closeMediaNotification()
|
closeMediaNotification()
|
||||||
return
|
return
|
||||||
@ -295,7 +286,7 @@ class MprisMediaSession : OnSharedPreferenceChangeListener, NotificationReceiver
|
|||||||
// Create all actions (previous/play/pause/next)
|
// Create all actions (previous/play/pause/next)
|
||||||
val iPlay = Intent(context, MprisMediaNotificationReceiver::class.java).apply {
|
val iPlay = Intent(context, MprisMediaNotificationReceiver::class.java).apply {
|
||||||
setAction(MprisMediaNotificationReceiver.ACTION_PLAY)
|
setAction(MprisMediaNotificationReceiver.ACTION_PLAY)
|
||||||
putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice)
|
putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDeviceId)
|
||||||
putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, currentPlayer.playerName)
|
putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, currentPlayer.playerName)
|
||||||
}
|
}
|
||||||
val piPlay = PendingIntent.getBroadcast(
|
val piPlay = PendingIntent.getBroadcast(
|
||||||
@ -310,7 +301,7 @@ class MprisMediaSession : OnSharedPreferenceChangeListener, NotificationReceiver
|
|||||||
|
|
||||||
val iPause = Intent(context, MprisMediaNotificationReceiver::class.java).apply {
|
val iPause = Intent(context, MprisMediaNotificationReceiver::class.java).apply {
|
||||||
setAction(MprisMediaNotificationReceiver.ACTION_PAUSE)
|
setAction(MprisMediaNotificationReceiver.ACTION_PAUSE)
|
||||||
putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice)
|
putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDeviceId)
|
||||||
putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, currentPlayer.playerName)
|
putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, currentPlayer.playerName)
|
||||||
}
|
}
|
||||||
val piPause = PendingIntent.getBroadcast(
|
val piPause = PendingIntent.getBroadcast(
|
||||||
@ -325,7 +316,7 @@ class MprisMediaSession : OnSharedPreferenceChangeListener, NotificationReceiver
|
|||||||
|
|
||||||
val iPrevious = Intent(context, MprisMediaNotificationReceiver::class.java).apply {
|
val iPrevious = Intent(context, MprisMediaNotificationReceiver::class.java).apply {
|
||||||
setAction(MprisMediaNotificationReceiver.ACTION_PREVIOUS)
|
setAction(MprisMediaNotificationReceiver.ACTION_PREVIOUS)
|
||||||
putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice)
|
putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDeviceId)
|
||||||
putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, currentPlayer.playerName)
|
putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, currentPlayer.playerName)
|
||||||
}
|
}
|
||||||
val piPrevious = PendingIntent.getBroadcast(
|
val piPrevious = PendingIntent.getBroadcast(
|
||||||
@ -340,7 +331,7 @@ class MprisMediaSession : OnSharedPreferenceChangeListener, NotificationReceiver
|
|||||||
|
|
||||||
val iNext = Intent(context, MprisMediaNotificationReceiver::class.java).apply {
|
val iNext = Intent(context, MprisMediaNotificationReceiver::class.java).apply {
|
||||||
setAction(MprisMediaNotificationReceiver.ACTION_NEXT)
|
setAction(MprisMediaNotificationReceiver.ACTION_NEXT)
|
||||||
putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice)
|
putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDeviceId)
|
||||||
putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, currentPlayer.playerName)
|
putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, currentPlayer.playerName)
|
||||||
}
|
}
|
||||||
val piNext = PendingIntent.getBroadcast(
|
val piNext = PendingIntent.getBroadcast(
|
||||||
@ -354,7 +345,7 @@ class MprisMediaSession : OnSharedPreferenceChangeListener, NotificationReceiver
|
|||||||
)
|
)
|
||||||
|
|
||||||
val iOpenActivity = Intent(context, MprisActivity::class.java).apply {
|
val iOpenActivity = Intent(context, MprisActivity::class.java).apply {
|
||||||
putExtra("deviceId", notificationDevice)
|
putExtra("deviceId", notificationDeviceId)
|
||||||
putExtra("player", currentPlayer.playerName)
|
putExtra("player", currentPlayer.playerName)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -392,7 +383,7 @@ class MprisMediaSession : OnSharedPreferenceChangeListener, NotificationReceiver
|
|||||||
if (!currentPlayer.isPlaying) {
|
if (!currentPlayer.isPlaying) {
|
||||||
val iCloseNotification = Intent(context, MprisMediaNotificationReceiver::class.java)
|
val iCloseNotification = Intent(context, MprisMediaNotificationReceiver::class.java)
|
||||||
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, notificationDeviceId)
|
||||||
iCloseNotification.putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, currentPlayer.playerName)
|
iCloseNotification.putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, currentPlayer.playerName)
|
||||||
val piCloseNotification = PendingIntent.getBroadcast(
|
val piCloseNotification = PendingIntent.getBroadcast(
|
||||||
context,
|
context,
|
||||||
@ -450,17 +441,18 @@ class MprisMediaSession : OnSharedPreferenceChangeListener, NotificationReceiver
|
|||||||
|
|
||||||
// Display the notification
|
// Display the notification
|
||||||
synchronized(instance) {
|
synchronized(instance) {
|
||||||
if (mediaSession == null) {
|
val mediaSession = mediaSession ?: MediaSessionCompat(context!!, MPRIS_MEDIA_SESSION_TAG).apply {
|
||||||
mediaSession = MediaSessionCompat(context!!, MPRIS_MEDIA_SESSION_TAG)
|
setCallback(mediaSessionCallback, Handler(context!!.mainLooper))
|
||||||
mediaSession!!.setCallback(mediaSessionCallback, Handler(context!!.mainLooper))
|
|
||||||
}
|
}
|
||||||
mediaSession!!.setMetadata(metadata.build())
|
mediaSession.setMetadata(metadata.build())
|
||||||
mediaSession!!.setPlaybackState(playbackState.build())
|
mediaSession.setPlaybackState(playbackState.build())
|
||||||
mediaStyle.setMediaSession(mediaSession!!.sessionToken)
|
mediaStyle.setMediaSession(mediaSession.sessionToken)
|
||||||
notification.setStyle(mediaStyle)
|
notification.setStyle(mediaStyle)
|
||||||
mediaSession!!.isActive = true
|
mediaSession.isActive = true
|
||||||
val nm = ContextCompat.getSystemService(context!!, NotificationManager::class.java)
|
ContextCompat.getSystemService(context!!, NotificationManager::class.java)?.notify(MPRIS_MEDIA_NOTIFICATION_ID, notification.build())
|
||||||
nm!!.notify(MPRIS_MEDIA_NOTIFICATION_ID, notification.build())
|
if (this.mediaSession == null) {
|
||||||
|
this.mediaSession = mediaSession
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -472,16 +464,14 @@ class MprisMediaSession : OnSharedPreferenceChangeListener, NotificationReceiver
|
|||||||
// Clear the current player and media session
|
// Clear the current player and media session
|
||||||
notificationPlayer = null
|
notificationPlayer = null
|
||||||
synchronized(instance) {
|
synchronized(instance) {
|
||||||
if (mediaSession != null) {
|
mediaSession?.apply {
|
||||||
mediaSession!!.setPlaybackState(PlaybackStateCompat.Builder().build())
|
setPlaybackState(PlaybackStateCompat.Builder().build())
|
||||||
mediaSession!!.setMetadata(MediaMetadataCompat.Builder().build())
|
setMetadata(MediaMetadataCompat.Builder().build())
|
||||||
mediaSession!!.isActive = false
|
isActive = false
|
||||||
mediaSession!!.release()
|
release()
|
||||||
mediaSession = null
|
|
||||||
|
|
||||||
val currentProvider = currentProvider
|
|
||||||
currentProvider?.release()
|
|
||||||
}
|
}
|
||||||
|
mediaSession = null
|
||||||
|
currentProvider?.release()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -529,8 +519,8 @@ class MprisMediaSession : OnSharedPreferenceChangeListener, NotificationReceiver
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun StatusBarNotification?.isSpotify(): Boolean =
|
private fun StatusBarNotification.isSpotify(): Boolean =
|
||||||
this?.packageName == SPOTIFY_PACKAGE_NAME
|
this.packageName == SPOTIFY_PACKAGE_NAME
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val TAG = "MprisMediaSession"
|
const val TAG = "MprisMediaSession"
|
||||||
|
@ -413,7 +413,7 @@ class MprisPlugin : Plugin() {
|
|||||||
*/
|
*/
|
||||||
get() = players.values.stream().filter(MprisPlayer::isPlaying).findFirst().orElse(null)
|
get() = players.values.stream().filter(MprisPlayer::isPlaying).findFirst().orElse(null)
|
||||||
|
|
||||||
fun hasPlayer(player: MprisPlayer?): Boolean = player != null && players.containsValue(player)
|
fun hasPlayer(player: MprisPlayer): Boolean = players.containsValue(player)
|
||||||
|
|
||||||
private fun requestPlayerList() {
|
private fun requestPlayerList() {
|
||||||
val np = NetworkPacket(PACKET_TYPE_MPRIS_REQUEST).apply {
|
val np = NetworkPacket(PACKET_TYPE_MPRIS_REQUEST).apply {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user