diff --git a/src/org/kde/kdeconnect/Plugins/MprisPlugin/MprisActivity.java b/src/org/kde/kdeconnect/Plugins/MprisPlugin/MprisActivity.java --- a/src/org/kde/kdeconnect/Plugins/MprisPlugin/MprisActivity.java +++ b/src/org/kde/kdeconnect/Plugins/MprisPlugin/MprisActivity.java @@ -88,49 +88,7 @@ runOnUiThread(new Runnable() { @Override public void run() { - String song = mpris.getCurrentSong(); - - TextView nowPlaying = (TextView) findViewById(R.id.now_playing_textview); - if (!nowPlaying.getText().toString().equals(song)) { - nowPlaying.setText(song); - } - - //Hacks for Spotify because it reports incorrect info about what it supports - boolean isSpotify = "spotify".equals(mpris.getPlayer().toLowerCase()); - - if (mpris.getLength() > -1 && mpris.getPosition() > -1 && !isSpotify) { - ((TextView) findViewById(R.id.time_textview)).setText(milisToProgress(mpris.getLength())); - SeekBar positionSeek = (SeekBar)findViewById(R.id.positionSeek); - positionSeek.setMax((int)(mpris.getLength())); - positionSeek.setProgress((int)(mpris.getPosition())); - findViewById(R.id.progress_slider).setVisibility(View.VISIBLE); - } else { - findViewById(R.id.progress_slider).setVisibility(View.GONE); - } - - int volume = mpris.getVolume(); - ((SeekBar) findViewById(R.id.volume_seek)).setProgress(volume); - - boolean isPlaying = mpris.isPlaying(); - if (isPlaying) { - ((ImageButton) findViewById(R.id.play_button)).setImageResource(android.R.drawable.ic_media_pause); - findViewById(R.id.play_button).setVisibility(mpris.isPauseAllowed() ? View.VISIBLE : View.GONE); - } else { - ((ImageButton) findViewById(R.id.play_button)).setImageResource(android.R.drawable.ic_media_play); - findViewById(R.id.play_button).setVisibility(mpris.isPlayAllowed() ? View.VISIBLE : View.GONE); - } - - if (isSpotify) { - findViewById(R.id.volume_layout).setVisibility(View.INVISIBLE); - findViewById(R.id.rew_button).setVisibility(View.GONE); - findViewById(R.id.ff_button).setVisibility(View.GONE); - } else { - findViewById(R.id.volume_layout).setVisibility(View.VISIBLE); - findViewById(R.id.rew_button).setVisibility(mpris.isSeekAllowed() ? View.VISIBLE : View.GONE); - findViewById(R.id.ff_button).setVisibility(mpris.isSeekAllowed() ? View.VISIBLE : View.GONE); - } - findViewById(R.id.next_button).setVisibility(mpris.isGoNextAllowed() ? View.VISIBLE : View.GONE); - findViewById(R.id.prev_button).setVisibility(mpris.isGoPreviousAllowed() ? View.VISIBLE : View.GONE); + updatePlayerStatus(mpris); } }); } @@ -169,20 +127,16 @@ if (pos >= playerList.size()) return; String player = playerList.get(pos); - if (player.equals(mpris.getPlayer())) { + if (player.equals(targetPlayer)) { return; //Player hasn't actually changed } - mpris.setPlayer(player); - - //Clear values from previous player - ((TextView) findViewById(R.id.now_playing_textview)).setText(""); - ((TextView) findViewById(R.id.time_textview)).setText(milisToProgress(0)); - ((SeekBar)findViewById(R.id.positionSeek)).setMax(0); + targetPlayer = player; + updatePlayerStatus(mpris); } @Override public void onNothingSelected(AdapterView arg0) { - mpris.setPlayer(null); + targetPlayer = null; } }); @@ -192,12 +146,16 @@ spinner.setSelection(targetIndex); } targetPlayer = null; + } + String selectedPlayer; + if (spinner.getSelectedItemPosition() >= 0) { + selectedPlayer = playerList.get(spinner.getSelectedItemPosition()); } else { - // restore last selected player - int position = adapter.getPosition(mpris.getPlayer()); - if (position >= 0) { - spinner.setSelection(position); - } + selectedPlayer = null; + } + if ((targetPlayer == null && selectedPlayer != null) || (targetPlayer != null && !targetPlayer.equals(selectedPlayer))) { + targetPlayer = selectedPlayer; + updatePlayerStatus(mpris); } } }); @@ -232,22 +190,78 @@ }); } + private void updatePlayerStatus(MprisPlugin mpris) { + MprisPlugin.MprisPlayer playerStatus = mpris.getPlayerStatus(targetPlayer); + if (playerStatus == null) { + //No player with that name found, just display "empty" data + playerStatus = new MprisPlugin.MprisPlayer(); + } + String song = playerStatus.getCurrentSong(); + + TextView nowPlaying = (TextView) findViewById(R.id.now_playing_textview); + if (!nowPlaying.getText().toString().equals(song)) { + nowPlaying.setText(song); + } + + //Hacks for Spotify because it reports incorrect info about what it supports + boolean isSpotify = "spotify".equals(playerStatus.getPlayer().toLowerCase()); + + if (playerStatus.getLength() > -1 && playerStatus.getPosition() > -1 && !isSpotify) { + ((TextView) findViewById(R.id.time_textview)).setText(milisToProgress(playerStatus.getLength())); + SeekBar positionSeek = (SeekBar)findViewById(R.id.positionSeek); + positionSeek.setMax((int)(playerStatus.getLength())); + positionSeek.setProgress((int)(playerStatus.getPosition())); + findViewById(R.id.progress_slider).setVisibility(View.VISIBLE); + } else { + findViewById(R.id.progress_slider).setVisibility(View.GONE); + } + + int volume = playerStatus.getVolume(); + ((SeekBar) findViewById(R.id.volume_seek)).setProgress(volume); + + boolean isPlaying = playerStatus.isPlaying(); + if (isPlaying) { + ((ImageButton) findViewById(R.id.play_button)).setImageResource(android.R.drawable.ic_media_pause); + findViewById(R.id.play_button).setVisibility(playerStatus.isPauseAllowed() ? View.VISIBLE : View.GONE); + } else { + ((ImageButton) findViewById(R.id.play_button)).setImageResource(android.R.drawable.ic_media_play); + findViewById(R.id.play_button).setVisibility(playerStatus.isPlayAllowed() ? View.VISIBLE : View.GONE); + } + + if (isSpotify) { + findViewById(R.id.volume_layout).setVisibility(View.INVISIBLE); + findViewById(R.id.rew_button).setVisibility(View.GONE); + findViewById(R.id.ff_button).setVisibility(View.GONE); + } else { + findViewById(R.id.volume_layout).setVisibility(View.VISIBLE); + findViewById(R.id.rew_button).setVisibility(playerStatus.isSeekAllowed() ? View.VISIBLE : View.GONE); + findViewById(R.id.ff_button).setVisibility(playerStatus.isSeekAllowed() ? View.VISIBLE : View.GONE); + } + findViewById(R.id.next_button).setVisibility(playerStatus.isGoNextAllowed() ? View.VISIBLE : View.GONE); + findViewById(R.id.prev_button).setVisibility(playerStatus.isGoPreviousAllowed() ? View.VISIBLE : View.GONE); + } + /** * Change current volume with provided step. * * @param mpris multimedia controller * @param step step size volume change */ private void updateVolume(MprisPlugin mpris, int step) { - final int currentVolume = mpris.getVolume(); + MprisPlugin.MprisPlayer playerStatus = mpris.getPlayerStatus(targetPlayer); + if (playerStatus == null) { + return; + } + final int currentVolume = playerStatus.getVolume(); + if(currentVolume < 100 || currentVolume > 0) { int newVolume = currentVolume + step; if(newVolume > 100) { newVolume = 100; } else if (newVolume <0 ) { newVolume = 0; } - mpris.setVolume(newVolume); + mpris.setVolume(targetPlayer, newVolume); } } @@ -324,7 +338,7 @@ Device device = service.getDevice(deviceId); MprisPlugin mpris = device.getPlugin(MprisPlugin.class); if (mpris == null) return; - mpris.sendAction("PlayPause"); + mpris.sendAction(targetPlayer, "PlayPause"); } }); } @@ -339,7 +353,7 @@ Device device = service.getDevice(deviceId); MprisPlugin mpris = device.getPlugin(MprisPlugin.class); if (mpris == null) return; - mpris.sendAction("Previous"); + mpris.sendAction(targetPlayer, "Previous"); } }); } @@ -354,7 +368,7 @@ Device device = service.getDevice(deviceId); MprisPlugin mpris = device.getPlugin(MprisPlugin.class); if (mpris == null) return; - mpris.Seek(interval_time * -1); + mpris.Seek(targetPlayer, interval_time * -1); } }); } @@ -369,7 +383,7 @@ Device device = service.getDevice(deviceId); MprisPlugin mpris = device.getPlugin(MprisPlugin.class); if (mpris == null) return; - mpris.Seek(interval_time); + mpris.Seek(targetPlayer, interval_time); } }); } @@ -384,7 +398,7 @@ Device device = service.getDevice(deviceId); MprisPlugin mpris = device.getPlugin(MprisPlugin.class); if (mpris == null) return; - mpris.sendAction("Next"); + mpris.sendAction(targetPlayer, "Next"); } }); } @@ -407,7 +421,7 @@ Device device = service.getDevice(deviceId); MprisPlugin mpris = device.getPlugin(MprisPlugin.class); if (mpris == null) return; - mpris.setVolume(seekBar.getProgress()); + mpris.setVolume(targetPlayer, seekBar.getProgress()); } }); } @@ -425,7 +439,10 @@ if (device != null) { MprisPlugin mpris = device.getPlugin(MprisPlugin.class); if (mpris != null) { - positionSeek.setProgress((int) (mpris.getPosition())); + MprisPlugin.MprisPlayer playerStatus = mpris.getPlayerStatus(targetPlayer); + if (playerStatus != null) { + positionSeek.setProgress((int) (playerStatus.getPosition())); + } } } positionSeekUpdateHandler.removeCallbacks(positionSeekUpdateRunnable); @@ -456,7 +473,7 @@ Device device = service.getDevice(deviceId); MprisPlugin mpris = device.getPlugin(MprisPlugin.class); if (mpris != null) { - mpris.setPosition(seekBar.getProgress()); + mpris.setPosition(targetPlayer, seekBar.getProgress()); } positionSeekUpdateHandler.postDelayed(positionSeekUpdateRunnable, 200); } diff --git a/src/org/kde/kdeconnect/Plugins/MprisPlugin/MprisPlugin.java b/src/org/kde/kdeconnect/Plugins/MprisPlugin/MprisPlugin.java --- a/src/org/kde/kdeconnect/Plugins/MprisPlugin/MprisPlugin.java +++ b/src/org/kde/kdeconnect/Plugins/MprisPlugin/MprisPlugin.java @@ -33,29 +33,84 @@ import org.kde.kdeconnect_tp.R; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.List; +import java.util.Map; public class MprisPlugin extends Plugin { + public static class MprisPlayer { + private String player = ""; + private boolean playing = false; + private String currentSong = ""; + private int volume = 50; + private long length = -1; + private long lastPosition = 0; + private long lastPositionTime; + private boolean playAllowed = true; + private boolean pauseAllowed = true; + private boolean goNextAllowed = true; + private boolean goPreviousAllowed = true; + private boolean seekAllowed = true; + + public MprisPlayer() { + lastPositionTime = System.currentTimeMillis(); + } + + public String getCurrentSong() { + return currentSong; + } + + public String getPlayer() { + return player; + } + + public int getVolume() { + return volume; + } + + public long getLength(){ return length; } + + public boolean isPlaying() { + return playing; + } + + public boolean isPlayAllowed() { + return playAllowed; + } + + public boolean isPauseAllowed() { + return pauseAllowed; + } + + public boolean isGoNextAllowed() { + return goNextAllowed; + } + + public boolean isGoPreviousAllowed() { + return goPreviousAllowed; + } + + public boolean isSeekAllowed() { + return seekAllowed; + } + + public long getPosition(){ + if(playing) { + return lastPosition + (System.currentTimeMillis() - lastPositionTime); + } else { + return lastPosition; + } + } + } public final static String PACKAGE_TYPE_MPRIS = "kdeconnect.mpris"; public final static String PACKAGE_TYPE_MPRIS_REQUEST = "kdeconnect.mpris.request"; - private String player = ""; - private boolean playing = false; - private String currentSong = ""; - private int volume = 50; - private long length = -1; - private long lastPosition; - private long lastPositionTime; - private boolean playAllowed = true; - private boolean pauseAllowed = true; - private boolean goNextAllowed = true; - private boolean goPreviousAllowed = true; - private boolean seekAllowed = true; + private HashMap players = new HashMap<>(); private HashMap playerStatusUpdated = new HashMap<>(); - private List playerList = new ArrayList<>(); private HashMap playerListUpdated = new HashMap<>(); @Override @@ -81,66 +136,66 @@ @Override public boolean onCreate() { requestPlayerList(); - lastPositionTime = System.currentTimeMillis(); return true; } @Override public void onDestroy() { - playerList.clear(); + players.clear(); } public void sendAction(String player, String action) { NetworkPackage np = new NetworkPackage(PACKAGE_TYPE_MPRIS_REQUEST); np.set("player", player); np.set("action", action); device.sendPackage(np); } - public void sendAction(String action) { - sendAction(player, action); - } - public void setVolume(int volume) { + public void setVolume(String player, int volume) { NetworkPackage np = new NetworkPackage(PACKAGE_TYPE_MPRIS_REQUEST); np.set("player", player); np.set("setVolume",volume); device.sendPackage(np); } - public void setPosition(int position) { + public void setPosition(String player, int position) { NetworkPackage np = new NetworkPackage(PACKAGE_TYPE_MPRIS_REQUEST); np.set("player", player); np.set("SetPosition", position); device.sendPackage(np); - this.lastPosition = position; - this.lastPositionTime = System.currentTimeMillis(); + + MprisPlayer playerStatus = players.get(player); + if (playerStatus != null) { + playerStatus.lastPosition = position; + playerStatus.lastPositionTime = System.currentTimeMillis(); + } } - public void Seek(int offset) { + public void Seek(String player, int offset) { NetworkPackage np = new NetworkPackage(PACKAGE_TYPE_MPRIS_REQUEST); np.set("player", player); np.set("Seek", offset); device.sendPackage(np); } @Override public boolean onPackageReceived(NetworkPackage np) { - if (np.has("nowPlaying") || np.has("volume") || np.has("isPlaying") || np.has("length") || np.has("pos")) { - if (np.getString("player").equals(player)) { - currentSong = np.getString("nowPlaying", currentSong); - volume = np.getInt("volume", volume); - length = np.getLong("length", length); + MprisPlayer playerStatus = players.get(np.getString("player")); + if (playerStatus != null) { + playerStatus.currentSong = np.getString("nowPlaying", playerStatus.currentSong); + playerStatus.volume = np.getInt("volume", playerStatus.volume); + playerStatus.length = np.getLong("length", playerStatus.length); if(np.has("pos")){ - lastPosition = np.getLong("pos", lastPosition); - lastPositionTime = System.currentTimeMillis(); + playerStatus.lastPosition = np.getLong("pos", playerStatus.lastPosition); + playerStatus.lastPositionTime = System.currentTimeMillis(); } - playing = np.getBoolean("isPlaying", playing); - playAllowed = np.getBoolean("canPlay", playAllowed); - pauseAllowed = np.getBoolean("canPause", pauseAllowed); - goNextAllowed = np.getBoolean("canGoNext", goNextAllowed); - goPreviousAllowed = np.getBoolean("canGoPrevious", goPreviousAllowed); - seekAllowed = np.getBoolean("canSeek", seekAllowed); + playerStatus.playing = np.getBoolean("isPlaying", playerStatus.playing); + playerStatus.playAllowed = np.getBoolean("canPlay", playerStatus.playAllowed); + playerStatus.pauseAllowed = np.getBoolean("canPause", playerStatus.pauseAllowed); + playerStatus.goNextAllowed = np.getBoolean("canGoNext", playerStatus.goNextAllowed); + playerStatus.goPreviousAllowed = np.getBoolean("canGoPrevious", playerStatus.goPreviousAllowed); + playerStatus.seekAllowed = np.getBoolean("canSeek", playerStatus.seekAllowed); for (String key : playerStatusUpdated.keySet()) { try { playerStatusUpdated.get(key).dispatchMessage(new Message()); @@ -155,18 +210,37 @@ List newPlayerList = np.getStringList("playerList"); if (newPlayerList != null) { - boolean equals = false; - if (newPlayerList.size() == playerList.size()) { - equals = true; - for (int i=0; i> iter = players.entrySet().iterator(); + while (iter.hasNext()) { + String oldPlayer = iter.next().getKey(); + + boolean found = false; + for (String newPlayer : newPlayerList) { + if (newPlayer.equals(oldPlayer)) { + found = true; break; } } + + if (!found) { + iter.remove(); + equals = false; + } } if (!equals) { - playerList = newPlayerList; for (String key : playerListUpdated.keySet()) { try { playerListUpdated.get(key).dispatchMessage(new Message()); @@ -198,8 +272,8 @@ h.dispatchMessage(new Message()); //Get the status if this is the first handler we have - if (playerListUpdated.size() == 1) { - requestPlayerStatus(); + if (playerListUpdated.size() == 1 && !players.isEmpty()) { + requestPlayerStatus(getPlayerList().get(0)); } } @@ -214,88 +288,25 @@ } } - public void setPlayer(String player) { - if (player == null || player.equals(this.player)) return; - this.player = player; - currentSong = ""; - volume = 50; - playing = false; - playAllowed = true; - pauseAllowed = true; - goNextAllowed = true; - goPreviousAllowed = true; - seekAllowed = true; - for (String key : playerStatusUpdated.keySet()) { - try { - playerStatusUpdated.get(key).dispatchMessage(new Message()); - } catch(Exception e) { - e.printStackTrace(); - Log.e("MprisControl","Exception"); - playerStatusUpdated.remove(key); - } - } - requestPlayerStatus(); - } - public List getPlayerList() { - return playerList; - } - - public String getCurrentSong() { - return currentSong; - } - - public String getPlayer() { - return player; - } - - public int getVolume() { - return volume; + List playerlist = new ArrayList<>(players.keySet()); + Collections.sort(playerlist); + return playerlist; } - public long getLength(){ return length; } - - public boolean isPlaying() { - return playing; - } - - public boolean isPlayAllowed() { - return playAllowed; - } - - public boolean isPauseAllowed() { - return pauseAllowed; - } - - public boolean isGoNextAllowed() { - return goNextAllowed; - } - - public boolean isGoPreviousAllowed() { - return goPreviousAllowed; - } - - public boolean isSeekAllowed() { - return seekAllowed; - } - - public long getPosition(){ - if(playing) { - return lastPosition + (System.currentTimeMillis() - lastPositionTime); - } else { - return lastPosition; - } + public MprisPlayer getPlayerStatus(String player) { + return players.get(player); } private void requestPlayerList() { NetworkPackage np = new NetworkPackage(PACKAGE_TYPE_MPRIS_REQUEST); np.set("requestPlayerList",true); device.sendPackage(np); } - private void requestPlayerStatus() { + private void requestPlayerStatus(String player) { NetworkPackage np = new NetworkPackage(PACKAGE_TYPE_MPRIS_REQUEST); - np.set("player",player); + np.set("player", player); np.set("requestNowPlaying",true); np.set("requestVolume",true); device.sendPackage(np);