2
0
mirror of https://github.com/KDE/kdeconnect-android synced 2025-08-22 18:07:55 +00:00

Add MPRIS media control notification

Summary:
BUG: 337485

Adds a notification to show and control mpris players. It shows the title, artist etc. (so depends on D9083, but can easily be adapted to work without it, but that leads to less features).

The notification appears as soon as one of your connected devices plays music. If multiple devices/players are playing, it shows the information and controls for only one of these. If it stops playing, it tries to switch to another playing device/player. If those do not exist, it shows the same player, but allows starting it again.

Dismissing the notification is only possible if the showed player is paused (as effect, only when all players are paused). It automatically closes if the device or player disappears or disconnects and no other players are playing. I think this behaviour is intuitive, other native android music players have similar behaviour.

About the implementation: there are two parts to this: the notification and the media session control API. The first shows the notification and its controls. The second allows lock screen controls on older Android versions and control using e.g. headphone buttons. Since nearly all code is shared between the two parts, and the rest is mostly straightforward, I put them in the same diff.

Test Plan:
Tested on Android Nougat 7.1 (shows the notification with buttons, as expected; no lock screen controls, as expected) and Android Gingerbread 2.3 (shows a notification without buttons, lock screen controls work, so as expected).

I am not able to test with multiple desktops, so testing that would be appreciated.

Disabling buttons when not available should work, but all players I tested always allowed next/previous/play/pause.

Reviewers: #kde_connect, nicolasfella

Reviewed By: #kde_connect, nicolasfella

Subscribers: apol, albertvaka, nicolasfella

Tags: #kde_connect

Maniphest Tasks: T6512

Differential Revision: https://phabricator.kde.org/D9266
This commit is contained in:
Matthijs Tijink 2017-12-11 12:01:13 +01:00
parent 0d00b8aa4a
commit 2f127b3047
10 changed files with 560 additions and 1 deletions

View File

@ -154,6 +154,13 @@
android:name="android.support.PARENT_ACTIVITY"
android:value="org.kde.kdeconnect.UserInterface.MaterialActivity" />
</activity>
<receiver
android:name="org.kde.kdeconnect.Plugins.MprisPlugin.MprisMediaNotificationReceiver">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
<activity
android:name="org.kde.kdeconnect.Plugins.RunCommandPlugin.RunCommandActivity"
android:label="@string/remote_control"

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M6,18l8.5,-6L6,6v12zM16,6v12h2V6h-2z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M6,19h4L10,5L6,5v14zM14,5v14h4L18,5h-4z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M8,5v14l11,-7z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M6,6h2v12L6,18zM9.5,12l8.5,6L18,6z"/>
</vector>

View File

@ -127,6 +127,7 @@
<string name="remote_control">Remote control</string>
<string name="settings">KDE Connect Settings</string>
<string name="mpris_play">Play</string>
<string name="mpris_pause">Pause</string>
<string name="mpris_previous">Previous</string>
<string name="mpris_rew">Rewind</string>
<string name="mpris_ff">Fast-forward</string>
@ -151,6 +152,9 @@
<item>60000000</item>
<item>120000000</item>
</string-array>
<string name="mpris_notification_settings_title">Show media control notification</string>
<string name="mpris_notification_settings_summary">Allows controlling your media players without opening KDE Connect.</string>
<string name="mpris_notification_key" translatable="false">mpris_notification_enabled</string>
<string name="share_to">Share To...</string>
<string name="protocol_version_older">This device uses an old protocol version</string>
<string name="protocol_version_newer">This device uses a newer protocol version</string>

View File

@ -12,4 +12,11 @@
android:entryValues="@array/mpris_time_entries_values"
android:defaultValue="@string/mpris_time_default" />
<CheckBoxPreference
android:id="@+id/mpris_notification_preference"
android:key="@string/mpris_notification_key"
android:title="@string/mpris_notification_settings_title"
android:summary="@string/mpris_notification_settings_summary"
android:defaultValue="true" />
</PreferenceScreen>

View File

@ -0,0 +1,86 @@
/*
* Copyright 2017 Matthijs Tijink <matthijstijink@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License or (at your option) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.kde.kdeconnect.Plugins.MprisPlugin;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.support.v4.media.session.MediaSessionCompat;
import android.view.KeyEvent;
import org.kde.kdeconnect.BackgroundService;
import org.kde.kdeconnect.Device;
/**
* Called when the mpris media notification's buttons are pressed
*/
public class MprisMediaNotificationReceiver extends BroadcastReceiver {
public static final String ACTION_PLAY = "ACTION_PLAY";
public static final String ACTION_PAUSE = "ACTION_PAUSE";
public static final String ACTION_PREVIOUS = "ACTION_PREVIOUS";
public static final String ACTION_NEXT = "ACTION_NEXT";
public static final String ACTION_CLOSE_NOTIFICATION = "ACTION_CLOSE_NOTIFICATION";
public static final String EXTRA_DEVICE_ID = "deviceId";
public static final String EXTRA_MPRIS_PLAYER = "player";
@Override
public void onReceive(Context context, Intent intent) {
//First case: buttons send by other applications via the media session APIs
if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())) {
//Route these buttons to the media session, which will handle them
MediaSessionCompat mediaSession = MprisMediaSession.getMediaSession();
if (mediaSession == null) return;
mediaSession.getController().dispatchMediaButtonEvent((KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT));
} else {
//Second case: buttons on the notification, which we created ourselves
//Get the correct device, the mpris plugin and the mpris player
BackgroundService service = BackgroundService.getInstance();
if (service == null) return;
Device device = service.getDevice(intent.getStringExtra(EXTRA_DEVICE_ID));
if (device == null) return;
MprisPlugin mpris = device.getPlugin(MprisPlugin.class);
if (mpris == null) return;
MprisPlugin.MprisPlayer player = mpris.getPlayerStatus(intent.getStringExtra(EXTRA_MPRIS_PLAYER));
if (player == null) return;
//Forward the action to the player
switch (intent.getAction()) {
case ACTION_PLAY:
player.play();
break;
case ACTION_PAUSE:
player.pause();
break;
case ACTION_PREVIOUS:
player.previous();
break;
case ACTION_NEXT:
player.next();
break;
case ACTION_CLOSE_NOTIFICATION:
//The user dismissed the notification: actually handle its removal correctly
MprisMediaSession.getInstance().closeMediaNotification();
}
}
}
}

View File

@ -0,0 +1,404 @@
/*
* Copyright 2017 Matthijs Tijink <matthijstijink@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License or (at your option) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.kde.kdeconnect.Plugins.MprisPlugin;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.preference.PreferenceManager;
import android.support.v4.content.SharedPreferencesCompat;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
import android.support.v7.app.NotificationCompat;
import org.kde.kdeconnect.BackgroundService;
import org.kde.kdeconnect.Device;
import org.kde.kdeconnect_tp.R;
import java.util.HashSet;
/**
* Controls the mpris media control notification
*
* There are two parts to this:
* - The notification (with buttons etc.)
* - The media session (via MediaSessionCompat; for lock screen control on
* older Android version. And in the future for lock screen album covers)
*/
public class MprisMediaSession implements SharedPreferences.OnSharedPreferenceChangeListener {
public final static int MPRIS_MEDIA_NOTIFICATION_ID = 0x91b70463; // echo MprisNotification | md5sum | head -c 8
public final static String MPRIS_MEDIA_SESSION_TAG = "org.kde.kdeconnect_tp.media_session";
private static MprisMediaSession instance = new MprisMediaSession();
public static MprisMediaSession getInstance() {
return instance;
}
public static MediaSessionCompat getMediaSession() {
return instance.mediaSession;
}
//Holds the device and player displayed in the notification
private String notificationDevice = null;
private MprisPlugin.MprisPlayer notificationPlayer = null;
//Holds the device ids for which we can display a notification
private HashSet<String> mprisDevices = new HashSet<>();
private Context context;
private MediaSessionCompat mediaSession;
//Callback for mpris plugin updates
private Handler mediaNotificationHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
updateMediaNotification();
}
};
//Callback for control via the media session API
private MediaSessionCompat.Callback mediaSessionCallback = new MediaSessionCompat.Callback() {
@Override
public void onPlay() {
notificationPlayer.play();
}
@Override
public void onPause() {
notificationPlayer.pause();
}
@Override
public void onSkipToNext() {
notificationPlayer.next();
}
@Override
public void onSkipToPrevious() {
notificationPlayer.previous();
}
@Override
public void onStop() {
notificationPlayer.stop();
}
};
/**
* Called by the mpris plugin when it wants media control notifications for its device
*
* Can be called multiple times, once for each device
* @param _context The context
* @param mpris The mpris plugin
* @param device The device id
*/
public void onCreate(Context _context, MprisPlugin mpris, String device) {
if (mprisDevices.isEmpty()) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(_context);
prefs.registerOnSharedPreferenceChangeListener(this);
}
context = _context;
mprisDevices.add(device);
mpris.setPlayerListUpdatedHandler("media_notification", mediaNotificationHandler);
mpris.setPlayerStatusUpdatedHandler("media_notification", mediaNotificationHandler);
updateMediaNotification();
}
/**
* Called when a device disconnects/does not want notifications anymore
*
* Can be called multiple times, once for each device
* @param mpris The mpris plugin
* @param device The device id
*/
public void onDestroy(MprisPlugin mpris, String device) {
mprisDevices.remove(device);
mpris.removePlayerStatusUpdatedHandler("media_notification");
mpris.removePlayerListUpdatedHandler("media_notification");
updateMediaNotification();
if (mprisDevices.isEmpty()) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
prefs.unregisterOnSharedPreferenceChangeListener(this);
}
}
/**
* Updates which device+player we're going to use in the notification
*
* Prefers playing devices/mpris players, but tries to keep displaying the same
* player and device, while possible.
* @param service The background service
*/
private void updateCurrentPlayer(BackgroundService service) {
Device device = null;
MprisPlugin.MprisPlayer playing = null;
//First try the previously displayed player
if (notificationDevice != null && mprisDevices.contains(notificationDevice) && notificationPlayer != null) {
device = service.getDevice(notificationDevice);
}
MprisPlugin mpris = null;
if (device != null) {
mpris = device.getPlugin(MprisPlugin.class);
}
if (mpris != null) {
playing = mpris.getPlayerStatus(notificationPlayer.getPlayer());
}
//If nonexistant or not playing, try a different player for the same device
if ((playing == null || !playing.isPlaying()) && mpris != null) {
MprisPlugin.MprisPlayer playingPlayer = mpris.getPlayingPlayer();
//Only replace the previously found player if we really found one
if (playingPlayer != null) {
playing = playingPlayer;
}
}
//If nonexistant or not playing, try a different player for another device
if (playing == null || !playing.isPlaying()) {
for (Device otherDevice : service.getDevices().values()) {
//First, check if we actually display notification for this device
if (!mprisDevices.contains(otherDevice.getDeviceId())) continue;
mpris = otherDevice.getPlugin(MprisPlugin.class);
if (mpris == null) continue;
MprisPlugin.MprisPlayer playingPlayer = mpris.getPlayingPlayer();
//Only replace the previously found player if we really found one
if (playingPlayer != null) {
playing = playingPlayer;
device = otherDevice;
break;
}
}
}
//Update the last-displayed device and player
notificationDevice = device == null ? null : device.getDeviceId();
notificationPlayer = playing;
}
/**
* Update the media control notification
*/
private void updateMediaNotification() {
BackgroundService.RunCommand(context, new BackgroundService.InstanceCallback() {
@Override
public void onServiceStart(BackgroundService service) {
//If the user disabled the media notification, do not show it
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
if (!prefs.getBoolean(context.getString(R.string.mpris_notification_key), true)) {
closeMediaNotification();
return;
}
//Make sure our information is up-to-date
updateCurrentPlayer(service);
//If the player disappeared (and no other playing one found), just remove the notification
if (notificationPlayer == null) {
closeMediaNotification();
return;
}
//Update the metadata and playback status
if (mediaSession == null) {
mediaSession = new MediaSessionCompat(context, MPRIS_MEDIA_SESSION_TAG);
mediaSession.setCallback(mediaSessionCallback);
mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
}
MediaMetadataCompat.Builder metadata = new MediaMetadataCompat.Builder();
//Fallback because older KDE connect versions do not support getTitle()
if (!notificationPlayer.getTitle().isEmpty()) {
metadata.putString(MediaMetadataCompat.METADATA_KEY_TITLE, notificationPlayer.getTitle());
} else {
metadata.putString(MediaMetadataCompat.METADATA_KEY_TITLE, notificationPlayer.getCurrentSong());
}
if (!notificationPlayer.getArtist().isEmpty()) {
metadata.putString(MediaMetadataCompat.METADATA_KEY_AUTHOR, notificationPlayer.getArtist());
}
if (!notificationPlayer.getAlbum().isEmpty()) {
metadata.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, notificationPlayer.getAlbum());
}
if (notificationPlayer.getLength() > 0) {
metadata.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, notificationPlayer.getLength());
}
mediaSession.setMetadata(metadata.build());
PlaybackStateCompat.Builder playbackState = new PlaybackStateCompat.Builder();
if (notificationPlayer.isPlaying()) {
playbackState.setState(PlaybackStateCompat.STATE_PLAYING, notificationPlayer.getPosition(), 1.0f);
} else {
playbackState.setState(PlaybackStateCompat.STATE_PAUSED, notificationPlayer.getPosition(), 0.0f);
}
//Create all actions (previous/play/pause/next)
Intent iPlay = new Intent(service, MprisMediaNotificationReceiver.class);
iPlay.setAction(MprisMediaNotificationReceiver.ACTION_PLAY);
iPlay.putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice);
iPlay.putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, notificationPlayer.getPlayer());
PendingIntent piPlay = PendingIntent.getBroadcast(service, 0, iPlay, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Action.Builder aPlay = new NotificationCompat.Action.Builder(
R.drawable.ic_play_white, service.getString(R.string.mpris_play), piPlay);
Intent iPause = new Intent(service, MprisMediaNotificationReceiver.class);
iPause.setAction(MprisMediaNotificationReceiver.ACTION_PAUSE);
iPause.putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice);
iPause.putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, notificationPlayer.getPlayer());
PendingIntent piPause = PendingIntent.getBroadcast(service, 0, iPause, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Action.Builder aPause = new NotificationCompat.Action.Builder(
R.drawable.ic_pause_white, service.getString(R.string.mpris_pause), piPause);
Intent iPrevious = new Intent(service, MprisMediaNotificationReceiver.class);
iPrevious.setAction(MprisMediaNotificationReceiver.ACTION_PREVIOUS);
iPrevious.putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice);
iPrevious.putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, notificationPlayer.getPlayer());
PendingIntent piPrevious = PendingIntent.getBroadcast(service, 0, iPrevious, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Action.Builder aPrevious = new NotificationCompat.Action.Builder(
R.drawable.ic_previous_white, service.getString(R.string.mpris_previous), piPrevious);
Intent iNext = new Intent(service, MprisMediaNotificationReceiver.class);
iNext.setAction(MprisMediaNotificationReceiver.ACTION_NEXT);
iNext.putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice);
iNext.putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, notificationPlayer.getPlayer());
PendingIntent piNext = PendingIntent.getBroadcast(service, 0, iNext, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Action.Builder aNext = new NotificationCompat.Action.Builder(
R.drawable.ic_next_white, service.getString(R.string.mpris_next), piNext);
Intent iOpenActivity = new Intent(service, MprisActivity.class);
iOpenActivity.putExtra("deviceId", notificationDevice);
iOpenActivity.putExtra("player", notificationPlayer.getPlayer());
PendingIntent piOpenActivity = PendingIntent.getActivity(service, 0, iOpenActivity, PendingIntent.FLAG_UPDATE_CURRENT);
//Create the notification
final NotificationCompat.Builder notification = new NotificationCompat.Builder(service);
notification
.setAutoCancel(false)
.setContentIntent(piOpenActivity)
.setSmallIcon(R.drawable.ic_play_white)
.setShowWhen(false)
.setColor(service.getResources().getColor(R.color.primary));
if (!notificationPlayer.getTitle().isEmpty()) {
notification.setContentTitle(notificationPlayer.getTitle());
} else {
notification.setContentTitle(notificationPlayer.getCurrentSong());
}
//Only set the notification body text if we have an author and/or album
if (!notificationPlayer.getArtist().isEmpty() && !notificationPlayer.getAlbum().isEmpty()) {
notification.setContentText(notificationPlayer.getArtist() + " - " + notificationPlayer.getAlbum() + " (" + notificationPlayer.getPlayer() + ")");
} else if (!notificationPlayer.getArtist().isEmpty()) {
notification.setContentText(notificationPlayer.getArtist() + " (" + notificationPlayer.getPlayer() + ")");
} else if (!notificationPlayer.getAlbum().isEmpty()) {
notification.setContentText(notificationPlayer.getAlbum() + " (" + notificationPlayer.getPlayer() + ")");
} else {
notification.setContentText(notificationPlayer.getPlayer());
}
if (!notificationPlayer.isPlaying()) {
Intent iCloseNotification = new Intent(service, MprisMediaNotificationReceiver.class);
iCloseNotification.setAction(MprisMediaNotificationReceiver.ACTION_CLOSE_NOTIFICATION);
iCloseNotification.putExtra(MprisMediaNotificationReceiver.EXTRA_DEVICE_ID, notificationDevice);
iCloseNotification.putExtra(MprisMediaNotificationReceiver.EXTRA_MPRIS_PLAYER, notificationPlayer.getPlayer());
PendingIntent piCloseNotification = PendingIntent.getActivity(service, 0, iCloseNotification, PendingIntent.FLAG_UPDATE_CURRENT);
notification.setDeleteIntent(piCloseNotification);
}
//Add media control actions
int numActions = 0;
long playbackActions = 0;
if (notificationPlayer.isGoPreviousAllowed()) {
notification.addAction(aPrevious.build());
playbackActions |= PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS;
++numActions;
}
if (notificationPlayer.isPlaying() && notificationPlayer.isPauseAllowed()) {
notification.addAction(aPause.build());
playbackActions |= PlaybackStateCompat.ACTION_PAUSE;
++numActions;
}
if (!notificationPlayer.isPlaying() && notificationPlayer.isPlayAllowed()) {
notification.addAction(aPlay.build());
playbackActions |= PlaybackStateCompat.ACTION_PLAY;
++numActions;
}
if (notificationPlayer.isGoNextAllowed()) {
notification.addAction(aNext.build());
playbackActions |= PlaybackStateCompat.ACTION_SKIP_TO_NEXT;
++numActions;
}
playbackState.setActions(playbackActions);
mediaSession.setPlaybackState(playbackState.build());
//Only allow deletion if no music is notificationPlayer
if (notificationPlayer.isPlaying()) {
notification.setOngoing(true);
} else {
notification.setOngoing(false);
}
//Use the MediaStyle notification, so it feels like other media players. That also allows adding actions
NotificationCompat.MediaStyle mediaStyle = new NotificationCompat.MediaStyle();
if (numActions == 1) {
mediaStyle.setShowActionsInCompactView(0);
} else if (numActions == 2) {
mediaStyle.setShowActionsInCompactView(0, 1);
} else if (numActions >= 3) {
mediaStyle.setShowActionsInCompactView(0, 1, 2);
}
mediaStyle.setMediaSession(mediaSession.getSessionToken());
notification.setStyle(mediaStyle);
//Display the notification
mediaSession.setActive(true);
final NotificationManager nm = (NotificationManager) service.getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(MPRIS_MEDIA_NOTIFICATION_ID, notification.build());
}
});
}
public void closeMediaNotification() {
//Remove the notification
NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
nm.cancel(MPRIS_MEDIA_NOTIFICATION_ID);
//Clear the current player and media session
notificationPlayer = null;
if (mediaSession != null) {
mediaSession.release();
mediaSession = null;
}
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
updateMediaNotification();
}
}

View File

@ -229,6 +229,7 @@ public class MprisPlugin extends Plugin {
@Override
public boolean onCreate() {
requestPlayerList();
MprisMediaSession.getInstance().onCreate(context.getApplicationContext(), this, device.getDeviceId());
//Always request the player list so the data is up-to-date
requestPlayerList();
@ -243,6 +244,7 @@ public class MprisPlugin extends Plugin {
public void onDestroy() {
players.clear();
AlbumArtCache.deregisterPlugin(this);
MprisMediaSession.getInstance().onDestroy(this, device.getDeviceId());
}
private void sendCommand(String player, String method, String value) {
@ -391,6 +393,19 @@ public class MprisPlugin extends Plugin {
return new MprisPlayer();
}
/**
* Returns a playing mpris player, if any exist
* @return null if no players are playing, a playing player otherwise
*/
public MprisPlayer getPlayingPlayer() {
for (MprisPlayer player : players.values()) {
if (player.isPlaying()) {
return player;
}
}
return null;
}
private void requestPlayerList() {
NetworkPackage np = new NetworkPackage(PACKAGE_TYPE_MPRIS_REQUEST);
np.set("requestPlayerList",true);