Changeset View
Changeset View
Standalone View
Standalone View
src/org/kde/kdeconnect/Plugins/MprisPlugin/MprisPlugin.java
Show All 27 Lines | |||||
28 | import android.support.v4.content.ContextCompat; | 28 | import android.support.v4.content.ContextCompat; | ||
29 | import android.util.Log; | 29 | import android.util.Log; | ||
30 | 30 | | |||
31 | import org.kde.kdeconnect.NetworkPackage; | 31 | import org.kde.kdeconnect.NetworkPackage; | ||
32 | import org.kde.kdeconnect.Plugins.Plugin; | 32 | import org.kde.kdeconnect.Plugins.Plugin; | ||
33 | import org.kde.kdeconnect_tp.R; | 33 | import org.kde.kdeconnect_tp.R; | ||
34 | 34 | | |||
35 | import java.util.ArrayList; | 35 | import java.util.ArrayList; | ||
36 | import java.util.Collections; | ||||
36 | import java.util.HashMap; | 37 | import java.util.HashMap; | ||
38 | import java.util.Iterator; | ||||
37 | import java.util.List; | 39 | import java.util.List; | ||
40 | import java.util.Map; | ||||
38 | 41 | | |||
39 | public class MprisPlugin extends Plugin { | 42 | public class MprisPlugin extends Plugin { | ||
40 | 43 | public class MprisPlayer { | |||
41 | public final static String PACKAGE_TYPE_MPRIS = "kdeconnect.mpris"; | | |||
42 | public final static String PACKAGE_TYPE_MPRIS_REQUEST = "kdeconnect.mpris.request"; | | |||
43 | | ||||
44 | private String player = ""; | 44 | private String player = ""; | ||
45 | private boolean playing = false; | 45 | private boolean playing = false; | ||
46 | private String currentSong = ""; | 46 | private String currentSong = ""; | ||
47 | private int volume = 50; | 47 | private int volume = 50; | ||
48 | private long length = -1; | 48 | private long length = -1; | ||
49 | private long lastPosition; | 49 | private long lastPosition = 0; | ||
50 | private long lastPositionTime; | 50 | private long lastPositionTime; | ||
51 | private boolean playAllowed = true; | 51 | private boolean playAllowed = true; | ||
52 | private boolean pauseAllowed = true; | 52 | private boolean pauseAllowed = true; | ||
53 | private boolean goNextAllowed = true; | 53 | private boolean goNextAllowed = true; | ||
54 | private boolean goPreviousAllowed = true; | 54 | private boolean goPreviousAllowed = true; | ||
55 | private boolean seekAllowed = true; | 55 | private boolean seekAllowed = true; | ||
56 | | ||||
57 | public MprisPlayer() { | ||||
58 | lastPositionTime = System.currentTimeMillis(); | ||||
59 | } | ||||
60 | | ||||
61 | public String getCurrentSong() { | ||||
62 | return currentSong; | ||||
63 | } | ||||
64 | | ||||
65 | public String getPlayer() { | ||||
66 | return player; | ||||
67 | } | ||||
68 | | ||||
69 | private boolean isSpotify() { | ||||
70 | return getPlayer().toLowerCase().equals("spotify"); | ||||
71 | } | ||||
72 | | ||||
73 | public int getVolume() { | ||||
74 | return volume; | ||||
75 | } | ||||
76 | | ||||
77 | public long getLength(){ return length; } | ||||
78 | | ||||
79 | public boolean isPlaying() { | ||||
80 | return playing; | ||||
81 | } | ||||
82 | | ||||
83 | public boolean isPlayAllowed() { | ||||
84 | return playAllowed; | ||||
85 | } | ||||
86 | | ||||
87 | public boolean isPauseAllowed() { | ||||
88 | return pauseAllowed; | ||||
89 | } | ||||
90 | | ||||
91 | public boolean isGoNextAllowed() { | ||||
92 | return goNextAllowed; | ||||
93 | } | ||||
94 | | ||||
95 | public boolean isGoPreviousAllowed() { | ||||
96 | return goPreviousAllowed; | ||||
97 | } | ||||
98 | | ||||
99 | public boolean isSeekAllowed() { | ||||
100 | return seekAllowed && getLength() >= 0 && getPosition() >= 0 && !isSpotify(); | ||||
101 | } | ||||
102 | | ||||
103 | public boolean isSetVolumeAllowed() { | ||||
104 | return !isSpotify(); | ||||
105 | } | ||||
106 | | ||||
107 | public long getPosition(){ | ||||
108 | if(playing) { | ||||
109 | return lastPosition + (System.currentTimeMillis() - lastPositionTime); | ||||
110 | } else { | ||||
111 | return lastPosition; | ||||
112 | } | ||||
113 | } | ||||
114 | | ||||
115 | public void sendAction(String action) { | ||||
116 | MprisPlugin.this.sendAction(getPlayer(), action); | ||||
117 | } | ||||
118 | | ||||
119 | public void setVolume(int volume) { | ||||
120 | MprisPlugin.this.setVolume(getPlayer(), volume); | ||||
121 | } | ||||
122 | | ||||
123 | public void setPosition(int position) { | ||||
124 | MprisPlugin.this.setPosition(getPlayer(), position); | ||||
125 | | ||||
126 | lastPosition = position; | ||||
127 | lastPositionTime = System.currentTimeMillis(); | ||||
128 | } | ||||
129 | | ||||
130 | public void Seek(int offset) { | ||||
131 | MprisPlugin.this.Seek(getPlayer(), offset); | ||||
132 | } | ||||
133 | } | ||||
134 | | ||||
135 | public final static String PACKAGE_TYPE_MPRIS = "kdeconnect.mpris"; | ||||
136 | public final static String PACKAGE_TYPE_MPRIS_REQUEST = "kdeconnect.mpris.request"; | ||||
137 | | ||||
138 | private HashMap<String, MprisPlayer> players = new HashMap<>(); | ||||
56 | private HashMap<String,Handler> playerStatusUpdated = new HashMap<>(); | 139 | private HashMap<String,Handler> playerStatusUpdated = new HashMap<>(); | ||
57 | 140 | | |||
58 | private List<String> playerList = new ArrayList<>(); | | |||
59 | private HashMap<String,Handler> playerListUpdated = new HashMap<>(); | 141 | private HashMap<String,Handler> playerListUpdated = new HashMap<>(); | ||
60 | 142 | | |||
61 | @Override | 143 | @Override | ||
62 | public String getDisplayName() { | 144 | public String getDisplayName() { | ||
63 | return context.getResources().getString(R.string.pref_plugin_mpris); | 145 | return context.getResources().getString(R.string.pref_plugin_mpris); | ||
64 | } | 146 | } | ||
65 | 147 | | |||
66 | @Override | 148 | @Override | ||
Show All 9 Lines | |||||
76 | @Override | 158 | @Override | ||
77 | public boolean hasSettings() { | 159 | public boolean hasSettings() { | ||
78 | return true; | 160 | return true; | ||
79 | } | 161 | } | ||
80 | 162 | | |||
81 | @Override | 163 | @Override | ||
82 | public boolean onCreate() { | 164 | public boolean onCreate() { | ||
83 | requestPlayerList(); | 165 | requestPlayerList(); | ||
84 | lastPositionTime = System.currentTimeMillis(); | | |||
85 | return true; | 166 | return true; | ||
86 | } | 167 | } | ||
87 | 168 | | |||
88 | @Override | 169 | @Override | ||
89 | public void onDestroy() { | 170 | public void onDestroy() { | ||
90 | playerList.clear(); | 171 | players.clear(); | ||
91 | } | 172 | } | ||
92 | 173 | | |||
93 | public void sendAction(String player, String action) { | 174 | private void sendAction(String player, String action) { | ||
94 | NetworkPackage np = new NetworkPackage(PACKAGE_TYPE_MPRIS_REQUEST); | 175 | NetworkPackage np = new NetworkPackage(PACKAGE_TYPE_MPRIS_REQUEST); | ||
95 | np.set("player", player); | 176 | np.set("player", player); | ||
96 | np.set("action", action); | 177 | np.set("action", action); | ||
97 | device.sendPackage(np); | 178 | device.sendPackage(np); | ||
98 | } | 179 | } | ||
99 | public void sendAction(String action) { | | |||
100 | sendAction(player, action); | | |||
101 | } | | |||
102 | 180 | | |||
103 | public void setVolume(int volume) { | 181 | private void setVolume(String player, int volume) { | ||
104 | NetworkPackage np = new NetworkPackage(PACKAGE_TYPE_MPRIS_REQUEST); | 182 | NetworkPackage np = new NetworkPackage(PACKAGE_TYPE_MPRIS_REQUEST); | ||
105 | np.set("player", player); | 183 | np.set("player", player); | ||
106 | np.set("setVolume",volume); | 184 | np.set("setVolume",volume); | ||
107 | device.sendPackage(np); | 185 | device.sendPackage(np); | ||
108 | } | 186 | } | ||
109 | 187 | | |||
110 | public void setPosition(int position) { | 188 | private void setPosition(String player, int position) { | ||
111 | NetworkPackage np = new NetworkPackage(PACKAGE_TYPE_MPRIS_REQUEST); | 189 | NetworkPackage np = new NetworkPackage(PACKAGE_TYPE_MPRIS_REQUEST); | ||
112 | np.set("player", player); | 190 | np.set("player", player); | ||
113 | np.set("SetPosition", position); | 191 | np.set("SetPosition", position); | ||
114 | device.sendPackage(np); | 192 | device.sendPackage(np); | ||
115 | this.lastPosition = position; | | |||
116 | this.lastPositionTime = System.currentTimeMillis(); | | |||
117 | } | 193 | } | ||
118 | 194 | | |||
119 | public void Seek(int offset) { | 195 | private void Seek(String player, int offset) { | ||
120 | NetworkPackage np = new NetworkPackage(PACKAGE_TYPE_MPRIS_REQUEST); | 196 | NetworkPackage np = new NetworkPackage(PACKAGE_TYPE_MPRIS_REQUEST); | ||
121 | np.set("player", player); | 197 | np.set("player", player); | ||
122 | np.set("Seek", offset); | 198 | np.set("Seek", offset); | ||
123 | device.sendPackage(np); | 199 | device.sendPackage(np); | ||
124 | } | 200 | } | ||
125 | 201 | | |||
126 | @Override | 202 | @Override | ||
127 | public boolean onPackageReceived(NetworkPackage np) { | 203 | public boolean onPackageReceived(NetworkPackage np) { | ||
128 | | ||||
129 | if (np.has("nowPlaying") || np.has("volume") || np.has("isPlaying") || np.has("length") || np.has("pos")) { | 204 | if (np.has("nowPlaying") || np.has("volume") || np.has("isPlaying") || np.has("length") || np.has("pos")) { | ||
130 | if (np.getString("player").equals(player)) { | 205 | MprisPlayer playerStatus = players.get(np.getString("player")); | ||
131 | currentSong = np.getString("nowPlaying", currentSong); | 206 | if (playerStatus != null) { | ||
132 | volume = np.getInt("volume", volume); | 207 | playerStatus.currentSong = np.getString("nowPlaying", playerStatus.currentSong); | ||
133 | length = np.getLong("length", length); | 208 | playerStatus.volume = np.getInt("volume", playerStatus.volume); | ||
209 | playerStatus.length = np.getLong("length", playerStatus.length); | ||||
134 | if(np.has("pos")){ | 210 | if(np.has("pos")){ | ||
135 | lastPosition = np.getLong("pos", lastPosition); | 211 | playerStatus.lastPosition = np.getLong("pos", playerStatus.lastPosition); | ||
136 | lastPositionTime = System.currentTimeMillis(); | 212 | playerStatus.lastPositionTime = System.currentTimeMillis(); | ||
137 | } | 213 | } | ||
138 | playing = np.getBoolean("isPlaying", playing); | 214 | playerStatus.playing = np.getBoolean("isPlaying", playerStatus.playing); | ||
139 | playAllowed = np.getBoolean("canPlay", playAllowed); | 215 | playerStatus.playAllowed = np.getBoolean("canPlay", playerStatus.playAllowed); | ||
140 | pauseAllowed = np.getBoolean("canPause", pauseAllowed); | 216 | playerStatus.pauseAllowed = np.getBoolean("canPause", playerStatus.pauseAllowed); | ||
141 | goNextAllowed = np.getBoolean("canGoNext", goNextAllowed); | 217 | playerStatus.goNextAllowed = np.getBoolean("canGoNext", playerStatus.goNextAllowed); | ||
142 | goPreviousAllowed = np.getBoolean("canGoPrevious", goPreviousAllowed); | 218 | playerStatus.goPreviousAllowed = np.getBoolean("canGoPrevious", playerStatus.goPreviousAllowed); | ||
143 | seekAllowed = np.getBoolean("canSeek", seekAllowed); | 219 | playerStatus.seekAllowed = np.getBoolean("canSeek", playerStatus.seekAllowed); | ||
144 | for (String key : playerStatusUpdated.keySet()) { | 220 | for (String key : playerStatusUpdated.keySet()) { | ||
145 | try { | 221 | try { | ||
146 | playerStatusUpdated.get(key).dispatchMessage(new Message()); | 222 | playerStatusUpdated.get(key).dispatchMessage(new Message()); | ||
147 | } catch(Exception e) { | 223 | } catch(Exception e) { | ||
148 | e.printStackTrace(); | 224 | e.printStackTrace(); | ||
149 | Log.e("MprisControl","Exception"); | 225 | Log.e("MprisControl","Exception"); | ||
150 | playerStatusUpdated.remove(key); | 226 | playerStatusUpdated.remove(key); | ||
151 | } | 227 | } | ||
152 | } | 228 | } | ||
153 | } | 229 | } | ||
154 | } | 230 | } | ||
155 | 231 | | |||
156 | List<String> newPlayerList = np.getStringList("playerList"); | 232 | List<String> newPlayerList = np.getStringList("playerList"); | ||
157 | if (newPlayerList != null) { | 233 | if (newPlayerList != null) { | ||
158 | boolean equals = false; | 234 | boolean equals = true; | ||
159 | if (newPlayerList.size() == playerList.size()) { | 235 | for (String newPlayer : newPlayerList) { | ||
160 | equals = true; | 236 | if (!players.containsKey(newPlayer)) { | ||
161 | for (int i=0; i<newPlayerList.size(); i++) { | | |||
162 | if (!newPlayerList.get(i).equals(playerList.get(i))) { | | |||
163 | equals = false; | 237 | equals = false; | ||
238 | | ||||
239 | MprisPlayer player = new MprisPlayer(); | ||||
240 | player.player = newPlayer; | ||||
241 | players.put(newPlayer, player); | ||||
242 | | ||||
243 | //Immediately ask for the data of this player | ||||
244 | requestPlayerStatus(newPlayer); | ||||
245 | } | ||||
246 | } | ||||
247 | Iterator<HashMap.Entry<String, MprisPlayer>> iter = players.entrySet().iterator(); | ||||
248 | while (iter.hasNext()) { | ||||
249 | String oldPlayer = iter.next().getKey(); | ||||
250 | | ||||
251 | boolean found = false; | ||||
252 | for (String newPlayer : newPlayerList) { | ||||
253 | if (newPlayer.equals(oldPlayer)) { | ||||
254 | found = true; | ||||
164 | break; | 255 | break; | ||
165 | } | 256 | } | ||
166 | } | 257 | } | ||
258 | | ||||
259 | if (!found) { | ||||
260 | iter.remove(); | ||||
261 | equals = false; | ||||
262 | } | ||||
167 | } | 263 | } | ||
168 | if (!equals) { | 264 | if (!equals) { | ||
169 | playerList = newPlayerList; | | |||
170 | for (String key : playerListUpdated.keySet()) { | 265 | for (String key : playerListUpdated.keySet()) { | ||
171 | try { | 266 | try { | ||
172 | playerListUpdated.get(key).dispatchMessage(new Message()); | 267 | playerListUpdated.get(key).dispatchMessage(new Message()); | ||
173 | } catch(Exception e) { | 268 | } catch(Exception e) { | ||
174 | e.printStackTrace(); | 269 | e.printStackTrace(); | ||
175 | Log.e("MprisControl","Exception"); | 270 | Log.e("MprisControl","Exception"); | ||
176 | playerListUpdated.remove(key); | 271 | playerListUpdated.remove(key); | ||
177 | } | 272 | } | ||
Show All 15 Lines | |||||
193 | } | 288 | } | ||
194 | 289 | | |||
195 | public void setPlayerStatusUpdatedHandler(String id, Handler h) { | 290 | public void setPlayerStatusUpdatedHandler(String id, Handler h) { | ||
196 | playerStatusUpdated.put(id, h); | 291 | playerStatusUpdated.put(id, h); | ||
197 | 292 | | |||
198 | h.dispatchMessage(new Message()); | 293 | h.dispatchMessage(new Message()); | ||
199 | 294 | | |||
200 | //Get the status if this is the first handler we have | 295 | //Get the status if this is the first handler we have | ||
201 | if (playerListUpdated.size() == 1) { | 296 | if (playerListUpdated.size() == 1 && !players.isEmpty()) { | ||
202 | requestPlayerStatus(); | 297 | requestPlayerStatus(getPlayerList().get(0)); | ||
203 | } | 298 | } | ||
204 | } | 299 | } | ||
205 | 300 | | |||
206 | public void setPlayerListUpdatedHandler(String id, Handler h) { | 301 | public void setPlayerListUpdatedHandler(String id, Handler h) { | ||
207 | playerListUpdated.put(id,h); | 302 | playerListUpdated.put(id,h); | ||
208 | 303 | | |||
209 | h.dispatchMessage(new Message()); | 304 | h.dispatchMessage(new Message()); | ||
210 | 305 | | |||
211 | //Get the status if this is the first handler we have | 306 | //Get the status if this is the first handler we have | ||
212 | if (playerListUpdated.size() == 1) { | 307 | if (playerListUpdated.size() == 1) { | ||
213 | requestPlayerList(); | 308 | requestPlayerList(); | ||
214 | } | 309 | } | ||
215 | } | 310 | } | ||
216 | 311 | | |||
217 | public void setPlayer(String player) { | | |||
218 | if (player == null || player.equals(this.player)) return; | | |||
219 | this.player = player; | | |||
220 | currentSong = ""; | | |||
221 | volume = 50; | | |||
222 | playing = false; | | |||
223 | playAllowed = true; | | |||
224 | pauseAllowed = true; | | |||
225 | goNextAllowed = true; | | |||
226 | goPreviousAllowed = true; | | |||
227 | seekAllowed = true; | | |||
228 | for (String key : playerStatusUpdated.keySet()) { | | |||
229 | try { | | |||
230 | playerStatusUpdated.get(key).dispatchMessage(new Message()); | | |||
231 | } catch(Exception e) { | | |||
232 | e.printStackTrace(); | | |||
233 | Log.e("MprisControl","Exception"); | | |||
234 | playerStatusUpdated.remove(key); | | |||
235 | } | | |||
236 | } | | |||
237 | requestPlayerStatus(); | | |||
238 | } | | |||
239 | | ||||
240 | public List<String> getPlayerList() { | 312 | public List<String> getPlayerList() { | ||
241 | return playerList; | 313 | List<String> playerlist = new ArrayList<>(players.keySet()); | ||
242 | } | 314 | Collections.sort(playerlist); | ||
243 | 315 | return playerlist; | |||
244 | public String getCurrentSong() { | | |||
245 | return currentSong; | | |||
246 | } | | |||
247 | | ||||
248 | public String getPlayer() { | | |||
249 | return player; | | |||
250 | } | | |||
251 | | ||||
252 | public int getVolume() { | | |||
253 | return volume; | | |||
254 | } | | |||
255 | | ||||
256 | public long getLength(){ return length; } | | |||
257 | | ||||
258 | public boolean isPlaying() { | | |||
259 | return playing; | | |||
260 | } | 316 | } | ||
261 | 317 | | |||
262 | public boolean isPlayAllowed() { | 318 | public MprisPlayer getPlayerStatus(String player) { | ||
263 | return playAllowed; | 319 | return players.get(player); | ||
264 | } | | |||
265 | | ||||
266 | public boolean isPauseAllowed() { | | |||
267 | return pauseAllowed; | | |||
268 | } | 320 | } | ||
269 | 321 | | |||
270 | public boolean isGoNextAllowed() { | 322 | public MprisPlayer getEmptyPlayer() { | ||
271 | return goNextAllowed; | 323 | return new MprisPlayer(); | ||
272 | } | | |||
273 | | ||||
274 | public boolean isGoPreviousAllowed() { | | |||
275 | return goPreviousAllowed; | | |||
276 | } | | |||
277 | | ||||
278 | public boolean isSeekAllowed() { | | |||
279 | return seekAllowed; | | |||
280 | } | | |||
281 | | ||||
282 | public long getPosition(){ | | |||
283 | if(playing) { | | |||
284 | return lastPosition + (System.currentTimeMillis() - lastPositionTime); | | |||
285 | } else { | | |||
286 | return lastPosition; | | |||
287 | } | | |||
288 | } | 324 | } | ||
289 | 325 | | |||
290 | private void requestPlayerList() { | 326 | private void requestPlayerList() { | ||
291 | NetworkPackage np = new NetworkPackage(PACKAGE_TYPE_MPRIS_REQUEST); | 327 | NetworkPackage np = new NetworkPackage(PACKAGE_TYPE_MPRIS_REQUEST); | ||
292 | np.set("requestPlayerList",true); | 328 | np.set("requestPlayerList",true); | ||
293 | device.sendPackage(np); | 329 | device.sendPackage(np); | ||
294 | } | 330 | } | ||
295 | 331 | | |||
296 | private void requestPlayerStatus() { | 332 | private void requestPlayerStatus(String player) { | ||
297 | NetworkPackage np = new NetworkPackage(PACKAGE_TYPE_MPRIS_REQUEST); | 333 | NetworkPackage np = new NetworkPackage(PACKAGE_TYPE_MPRIS_REQUEST); | ||
298 | np.set("player",player); | 334 | np.set("player", player); | ||
299 | np.set("requestNowPlaying",true); | 335 | np.set("requestNowPlaying",true); | ||
300 | np.set("requestVolume",true); | 336 | np.set("requestVolume",true); | ||
301 | device.sendPackage(np); | 337 | device.sendPackage(np); | ||
302 | } | 338 | } | ||
303 | 339 | | |||
304 | @Override | 340 | @Override | ||
305 | public boolean hasMainActivity() { | 341 | public boolean hasMainActivity() { | ||
306 | return true; | 342 | return true; | ||
Show All 15 Lines |