summaryrefslogtreecommitdiff
path: root/core/src/main
diff options
context:
space:
mode:
authorTom Hennen <TomHennen@users.noreply.github.com>2016-04-12 20:31:05 -0400
committerTom Hennen <TomHennen@users.noreply.github.com>2016-04-12 20:31:05 -0400
commitcc3f1bfd5bbbd04d3cb2ef9c2ec4febe22706298 (patch)
tree0a6b471885bafd0e7be09ae75c8f0cabc95187b0 /core/src/main
parent9b563c1c873e027b622ad122b92f00ddbea16a68 (diff)
parent65e77d7902bbe44834e1a1b33bca231a7bd37801 (diff)
downloadAntennaPod-cc3f1bfd5bbbd04d3cb2ef9c2ec4febe22706298.zip
Merge pull request #1862 from domingos86/media-session-to-playback-service
Having the PlaybackService handle the MediaSession
Diffstat (limited to 'core/src/main')
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/receiver/MediaButtonReceiver.java7
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/MediaButtonIntentReceiver.java26
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java237
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java295
4 files changed, 240 insertions, 325 deletions
diff --git a/core/src/main/java/de/danoeh/antennapod/core/receiver/MediaButtonReceiver.java b/core/src/main/java/de/danoeh/antennapod/core/receiver/MediaButtonReceiver.java
index 51cc52e10..0bfeb1150 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/receiver/MediaButtonReceiver.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/receiver/MediaButtonReceiver.java
@@ -13,6 +13,7 @@ import de.danoeh.antennapod.core.service.playback.PlaybackService;
public class MediaButtonReceiver extends BroadcastReceiver {
private static final String TAG = "MediaButtonReceiver";
public static final String EXTRA_KEYCODE = "de.danoeh.antennapod.core.service.extra.MediaButtonReceiver.KEYCODE";
+ public static final String EXTRA_SOURCE = "de.danoeh.antennapod.core.service.extra.MediaButtonReceiver.SOURCE";
public static final String NOTIFY_BUTTON_RECEIVER = "de.danoeh.antennapod.NOTIFY_BUTTON_RECEIVER";
@@ -20,11 +21,11 @@ public class MediaButtonReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Received intent");
KeyEvent event = (KeyEvent) intent.getExtras().get(Intent.EXTRA_KEY_EVENT);
- if (event.getAction() == KeyEvent.ACTION_DOWN) {
+ if (event != null && event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount()==0) {
ClientConfig.initialize(context);
Intent serviceIntent = new Intent(context, PlaybackService.class);
- int keycode = event.getKeyCode();
- serviceIntent.putExtra(EXTRA_KEYCODE, keycode);
+ serviceIntent.putExtra(EXTRA_KEYCODE, event.getKeyCode());
+ serviceIntent.putExtra(EXTRA_SOURCE, event.getSource());
context.startService(serviceIntent);
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/MediaButtonIntentReceiver.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/MediaButtonIntentReceiver.java
deleted file mode 100644
index 7d06390f2..000000000
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/MediaButtonIntentReceiver.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package de.danoeh.antennapod.core.service.playback;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.util.Log;
-
-public class MediaButtonIntentReceiver extends BroadcastReceiver {
-
- private static final String TAG = "MediaButtonIntentRcver";
-
- private static PlaybackServiceMediaPlayer mMediaPlayer;
-
- public static void setMediaPlayer(PlaybackServiceMediaPlayer mediaPlayer) {
- mMediaPlayer = mediaPlayer;
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- Log.d(TAG, "onReceive(Context, " + intent.toString() +")");
- if (mMediaPlayer != null && Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())) {
- mMediaPlayer.handleMediaKey(intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT));
- }
- }
-
-} \ No newline at end of file
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
index edea3962f..6ab9859ac 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
@@ -6,6 +6,7 @@ import android.app.PendingIntent;
import android.app.Service;
import android.bluetooth.BluetoothA2dp;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -19,12 +20,18 @@ import android.os.Build;
import android.os.IBinder;
import android.os.Vibrator;
import android.preference.PreferenceManager;
+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 android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
+import android.view.Display;
+import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.SurfaceHolder;
+import android.view.WindowManager;
import android.widget.Toast;
import com.bumptech.glide.Glide;
@@ -54,7 +61,7 @@ import de.danoeh.antennapod.core.util.playback.Playable;
/**
* Controls the MediaPlayer that plays a FeedMedia-file
*/
-public class PlaybackService extends Service {
+public class PlaybackService extends Service implements SharedPreferences.OnSharedPreferenceChangeListener {
public static final String FORCE_WIDGET_UPDATE = "de.danoeh.antennapod.FORCE_WIDGET_UPDATE";
public static final String STOP_WIDGET_UPDATE = "de.danoeh.antennapod.STOP_WIDGET_UPDATE";
/**
@@ -169,6 +176,10 @@ public class PlaybackService extends Service {
private PlaybackServiceMediaPlayer mediaPlayer;
private PlaybackServiceTaskManager taskManager;
+ /**
+ * Only used for Lollipop notifications.
+ */
+ private MediaSessionCompat mediaSession;
private int startPosition;
@@ -239,6 +250,28 @@ public class PlaybackService extends Service {
taskManager = new PlaybackServiceTaskManager(this, taskManagerCallback);
mediaPlayer = new PlaybackServiceMediaPlayer(this, mediaPlayerCallback);
+ ComponentName eventReceiver = new ComponentName(getApplicationContext(),
+ MediaButtonReceiver.class);
+ Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+ mediaButtonIntent.setComponent(eventReceiver);
+ PendingIntent buttonReceiverIntent = PendingIntent.getBroadcast(this, 0, mediaButtonIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+
+ mediaSession = new MediaSessionCompat(getApplicationContext(), TAG, eventReceiver, buttonReceiverIntent);
+
+ try {
+ mediaSession.setCallback(sessionCallback);
+ mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
+ mediaSession.setActive(true);
+ } catch (NullPointerException npe) {
+ // on some devices (Huawei) setting active can cause a NullPointerException
+ // even with correct use of the api.
+ // See http://stackoverflow.com/questions/31556679/android-huawei-mediassessioncompat
+ // and https://plus.google.com/+IanLake/posts/YgdTkKFxz7d
+ Log.e(TAG, "NullPointerException while setting up MediaSession");
+ npe.printStackTrace();
+ }
+ PreferenceManager.getDefaultSharedPreferences(this)
+ .registerOnSharedPreferenceChangeListener(this);
}
@Override
@@ -249,6 +282,11 @@ public class PlaybackService extends Service {
started = false;
currentMediaType = MediaType.UNKNOWN;
+ PreferenceManager.getDefaultSharedPreferences(this)
+ .unregisterOnSharedPreferenceChangeListener(this);
+ if (mediaSession != null) {
+ mediaSession.release();
+ }
unregisterReceiver(headsetDisconnected);
unregisterReceiver(shutdownReceiver);
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
@@ -269,6 +307,13 @@ public class PlaybackService extends Service {
}
@Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+ if(key.equals(UserPreferences.PREF_LOCKSCREEN_BACKGROUND)) {
+ updateMediaSessionMetadata(getPlayable());
+ }
+ }
+
+ @Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
@@ -287,7 +332,8 @@ public class PlaybackService extends Service {
if (keycode != -1) {
Log.d(TAG, "Received media button event");
- handleKeycode(keycode);
+ handleKeycode(keycode, intent.getIntExtra(MediaButtonReceiver.EXTRA_SOURCE,
+ InputDevice.SOURCE_CLASS_NONE));
} else {
started = true;
boolean stream = intent.getBooleanExtra(EXTRA_SHOULD_STREAM,
@@ -305,7 +351,7 @@ public class PlaybackService extends Service {
/**
* Handles media button events
*/
- private void handleKeycode(int keycode) {
+ private void handleKeycode(int keycode, int source) {
Log.d(TAG, "Handling keycode: " + keycode);
final PlaybackServiceMediaPlayer.PSMPInfo info = mediaPlayer.getPSMPInfo();
final PlayerStatus status = info.playerStatus;
@@ -347,7 +393,16 @@ public class PlaybackService extends Service {
break;
case KeyEvent.KEYCODE_MEDIA_NEXT:
- mediaPlayer.endPlayback(true);
+ if(source == InputDevice.SOURCE_CLASS_NONE ||
+ UserPreferences.shouldHardwareButtonSkip()) {
+ // assume the skip command comes from a notification or the lockscreen
+ // a >| skip button should actually skip
+ mediaPlayer.endPlayback(true);
+ } else {
+ // assume skip command comes from a (bluetooth) media button
+ // user actually wants to fast-forward
+ seekDelta(UserPreferences.getFastFowardSecs() * 1000);
+ }
break;
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
mediaPlayer.seekDelta(UserPreferences.getFastFowardSecs() * 1000);
@@ -365,6 +420,7 @@ public class PlaybackService extends Service {
stopForeground(true); // gets rid of persistent notification
break;
default:
+ Log.d(TAG, "Unhandled key code: " + keycode);
if (info.playable != null && info.playerStatus == PlayerStatus.PLAYING) { // only notify the user about an unknown key event if it is actually doing something
String message = String.format(getResources().getString(R.string.unknown_media_key), keycode);
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
@@ -439,6 +495,7 @@ public class PlaybackService extends Service {
@Override
public void statusChanged(PlaybackServiceMediaPlayer.PSMPInfo newInfo) {
currentMediaType = mediaPlayer.getCurrentMediaType();
+ updateMediaSession(newInfo.playerStatus);
switch (newInfo.playerStatus) {
case INITIALIZED:
writePlaybackPreferences();
@@ -530,6 +587,11 @@ public class PlaybackService extends Service {
}
@Override
+ public void updateMediaSessionMetadata(Playable p) {
+ PlaybackService.this.updateMediaSessionMetadata(p);
+ }
+
+ @Override
public boolean onMediaPlayerInfo(int code) {
switch (code) {
case MediaPlayer.MEDIA_INFO_BUFFERING_START:
@@ -796,6 +858,86 @@ public class PlaybackService extends Service {
private Thread notificationSetupThread;
/**
+ * Updates the Media Session for the corresponding status.
+ * @param playerStatus the current {@link PlayerStatus}
+ */
+ private void updateMediaSession(final PlayerStatus playerStatus) {
+ PlaybackStateCompat.Builder sessionState = new PlaybackStateCompat.Builder();
+
+ int state;
+ if (playerStatus != null) {
+ switch (playerStatus) {
+ case PLAYING:
+ state = PlaybackStateCompat.STATE_PLAYING;
+ break;
+ case PREPARED:
+ case PAUSED:
+ state = PlaybackStateCompat.STATE_PAUSED;
+ break;
+ case STOPPED:
+ state = PlaybackStateCompat.STATE_STOPPED;
+ break;
+ case SEEKING:
+ state = PlaybackStateCompat.STATE_FAST_FORWARDING;
+ break;
+ case PREPARING:
+ case INITIALIZING:
+ state = PlaybackStateCompat.STATE_CONNECTING;
+ break;
+ case INITIALIZED:
+ case INDETERMINATE:
+ state = PlaybackStateCompat.STATE_NONE;
+ break;
+ case ERROR:
+ state = PlaybackStateCompat.STATE_ERROR;
+ break;
+ default:
+ state = PlaybackStateCompat.STATE_NONE;
+ break;
+ }
+ } else {
+ state = PlaybackStateCompat.STATE_NONE;
+ }
+ sessionState.setState(state, mediaPlayer.getPosition(), mediaPlayer.getPlaybackSpeed());
+ sessionState.setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE
+ | PlaybackStateCompat.ACTION_REWIND
+ | PlaybackStateCompat.ACTION_FAST_FORWARD
+ | PlaybackStateCompat.ACTION_SKIP_TO_NEXT);
+ mediaSession.setPlaybackState(sessionState.build());
+ }
+
+ private void updateMediaSessionMetadata(Playable p) {
+ if (p == null) {
+ return;
+ }
+ MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder();
+ builder.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, p.getFeedTitle());
+ builder.putString(MediaMetadataCompat.METADATA_KEY_TITLE, p.getEpisodeTitle());
+ builder.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, p.getDuration());
+ builder.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, p.getEpisodeTitle());
+ builder.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, p.getFeedTitle());
+
+ if (p.getImageUri() != null && UserPreferences.setLockscreenBackground()) {
+ builder.putString(MediaMetadataCompat.METADATA_KEY_ART_URI, p.getImageUri().toString());
+ try {
+ WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
+ Display display = wm.getDefaultDisplay();
+ Bitmap art = Glide.with(this)
+ .load(p.getImageUri())
+ .asBitmap()
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .centerCrop()
+ .into(display.getWidth(), display.getHeight())
+ .get();
+ builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ART, art);
+ } catch (Throwable tr) {
+ Log.e(TAG, Log.getStackTraceString(tr));
+ }
+ }
+ mediaSession.setMetadata(builder.build());
+ }
+
+ /**
* Prepares notification and starts the service in the foreground.
*/
private void setupNotification(final PlaybackServiceMediaPlayer.PSMPInfo info) {
@@ -913,7 +1055,7 @@ public class PlaybackService extends Service {
PendingIntent stopButtonPendingIntent = getPendingIntentForMediaAction(
KeyEvent.KEYCODE_MEDIA_STOP, numActions);
notificationBuilder.setStyle(new android.support.v7.app.NotificationCompat.MediaStyle()
- .setMediaSession(mediaPlayer.getSessionToken())
+ .setMediaSession(mediaSession.getSessionToken())
.setShowActionsInCompactView(compactActionList.toArray())
.setShowCancelButton(true)
.setCancelButtonIntent(stopButtonPendingIntent))
@@ -1287,4 +1429,89 @@ public class PlaybackService extends Service {
return false;
}
}
+
+ private final MediaSessionCompat.Callback sessionCallback = new MediaSessionCompat.Callback() {
+
+ private static final String TAG = "MediaSessionCompat";
+
+ @Override
+ public void onPlay() {
+ Log.d(TAG, "onPlay()");
+ PlayerStatus status = getStatus();
+ if (status == PlayerStatus.PAUSED || status == PlayerStatus.PREPARED) {
+ resume();
+ } else if (status == PlayerStatus.INITIALIZED) {
+ setStartWhenPrepared(true);
+ prepare();
+ }
+ }
+
+ @Override
+ public void onPause() {
+ Log.d(TAG, "onPause()");
+ if (getStatus() == PlayerStatus.PLAYING) {
+ pause(false, true);
+ }
+ if (UserPreferences.isPersistNotify()) {
+ pause(false, true);
+ } else {
+ pause(true, true);
+ }
+ }
+
+ @Override
+ public void onStop() {
+ Log.d(TAG, "onStop()");
+ mediaPlayer.stop();
+ }
+
+ @Override
+ public void onSkipToPrevious() {
+ Log.d(TAG, "onSkipToPrevious()");
+ seekDelta(-UserPreferences.getRewindSecs() * 1000);
+ }
+
+ @Override
+ public void onRewind() {
+ Log.d(TAG, "onRewind()");
+ seekDelta(-UserPreferences.getRewindSecs() * 1000);
+ }
+
+ @Override
+ public void onFastForward() {
+ Log.d(TAG, "onFastForward()");
+ seekDelta(UserPreferences.getFastFowardSecs() * 1000);
+ }
+
+ @Override
+ public void onSkipToNext() {
+ Log.d(TAG, "onSkipToNext()");
+ if(UserPreferences.shouldHardwareButtonSkip()) {
+ mediaPlayer.endPlayback(true);
+ } else {
+ seekDelta(UserPreferences.getFastFowardSecs() * 1000);
+ }
+ }
+
+
+ @Override
+ public void onSeekTo(long pos) {
+ Log.d(TAG, "onSeekTo()");
+ seekTo((int) pos);
+ }
+
+ @Override
+ public boolean onMediaButtonEvent(final Intent mediaButton) {
+ Log.d(TAG, "onMediaButtonEvent(" + mediaButton + ")");
+ if (mediaButton != null) {
+ KeyEvent keyEvent = (KeyEvent) mediaButton.getExtras().get(Intent.EXTRA_KEY_EVENT);
+ if (keyEvent != null &&
+ keyEvent.getAction() == KeyEvent.ACTION_DOWN &&
+ keyEvent.getRepeatCount() == 0){
+ handleKeycode(keyEvent.getKeyCode(), keyEvent.getSource());
+ }
+ }
+ return false;
+ }
+ };
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java
index aa51840a7..d8b334295 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java
@@ -1,29 +1,14 @@
package de.danoeh.antennapod.core.service.playback;
-import android.app.PendingIntent;
-import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.graphics.Bitmap;
import android.media.AudioManager;
import android.net.wifi.WifiManager;
import android.os.PowerManager;
-import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
-import android.support.v4.media.MediaMetadataCompat;
-import android.support.v4.media.session.MediaSessionCompat;
-import android.support.v4.media.session.PlaybackStateCompat;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.util.Pair;
-import android.view.Display;
-import android.view.InputDevice;
-import android.view.KeyEvent;
import android.view.SurfaceHolder;
-import android.view.WindowManager;
-
-import com.bumptech.glide.Glide;
import org.antennapod.audio.MediaPlayer;
@@ -40,7 +25,6 @@ import de.danoeh.antennapod.core.feed.Chapter;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.feed.MediaType;
-import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.RewindAfterPauseUtils;
@@ -52,7 +36,7 @@ import de.danoeh.antennapod.core.util.playback.VideoPlayer;
/**
* Manages the MediaPlayer object of the PlaybackService.
*/
-public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPreferenceChangeListener {
+public class PlaybackServiceMediaPlayer {
public static final String TAG = "PlaybackSvcMediaPlayer";
/**
@@ -66,10 +50,6 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
private volatile PlayerStatus statusBeforeSeeking;
private volatile IPlayer mediaPlayer;
private volatile Playable media;
- /**
- * Only used for Lollipop notifications.
- */
- private final MediaSessionCompat mediaSession;
private volatile boolean stream;
private volatile MediaType mediaType;
@@ -110,43 +90,12 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
}
);
- MediaButtonIntentReceiver.setMediaPlayer(this);
- ComponentName eventReceiver = new ComponentName(context.getPackageName(), MediaButtonIntentReceiver.class.getName());
- Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
- mediaButtonIntent.setComponent(eventReceiver);
- PendingIntent buttonReceiverIntent = PendingIntent.getBroadcast(context, 0, mediaButtonIntent, PendingIntent.FLAG_UPDATE_CURRENT);
-
- mediaSession = new MediaSessionCompat(context, TAG, eventReceiver, buttonReceiverIntent);
-
- try {
- mediaSession.setCallback(sessionCallback);
- mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
- mediaSession.setActive(true);
- } catch (NullPointerException npe) {
- // on some devices (Huawei) setting active can cause a NullPointerException
- // even with correct use of the api.
- // See http://stackoverflow.com/questions/31556679/android-huawei-mediassessioncompat
- // and https://plus.google.com/+IanLake/posts/YgdTkKFxz7d
- Log.e(TAG, "NullPointerException while setting up MediaSession");
- npe.printStackTrace();
- }
-
mediaPlayer = null;
statusBeforeSeeking = null;
pausedBecauseOfTransientAudiofocusLoss = false;
mediaType = MediaType.UNKNOWN;
playerStatus = PlayerStatus.STOPPED;
videoSize = null;
-
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
- prefs.registerOnSharedPreferenceChangeListener(this);
- }
-
- @Override
- public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
- if(key.equals(UserPreferences.PREF_LOCKSCREEN_BACKGROUND)) {
- updateMediaSessionMetadata();
- }
}
/**
@@ -249,7 +198,7 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
setPlayerStatus(PlayerStatus.INITIALIZING, media);
try {
media.loadMetadata();
- updateMediaSessionMetadata();
+ executor.submit(() -> callback.updateMediaSessionMetadata(media));
if (stream) {
mediaPlayer.setDataSource(media.getStreamUrl());
} else {
@@ -269,41 +218,6 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
}
}
- private void updateMediaSessionMetadata() {
- executor.execute(() -> {
- final Playable p = this.media;
- if (p == null) {
- return;
- }
- MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder();
- builder.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, p.getFeedTitle());
- builder.putString(MediaMetadataCompat.METADATA_KEY_TITLE, p.getEpisodeTitle());
- builder.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, p.getDuration());
- builder.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, p.getEpisodeTitle());
- builder.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, p.getFeedTitle());
-
- if (p.getImageUri() != null && UserPreferences.setLockscreenBackground()) {
- builder.putString(MediaMetadataCompat.METADATA_KEY_ART_URI, p.getImageUri().toString());
- try {
- WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
- Display display = wm.getDefaultDisplay();
- Bitmap art = Glide.with(context)
- .load(p.getImageUri())
- .asBitmap()
- .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
- .centerCrop()
- .into(display.getWidth(), display.getHeight())
- .get();
- builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ART, art);
- } catch (Throwable tr) {
- Log.e(TAG, Log.getStackTraceString(tr));
- }
- }
- mediaSession.setMetadata(builder.build());
- });
- }
-
-
/**
* Resumes playback if the PSMP object is in PREPARED or PAUSED state. If the PSMP object is in an invalid state.
* nothing will happen.
@@ -718,9 +632,6 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
if (mediaPlayer != null) {
mediaPlayer.release();
}
- if (mediaSession != null) {
- mediaSession.release();
- }
releaseWifiLockIfNecessary();
}
@@ -798,16 +709,6 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
}
/**
- * Returns a token to this object's MediaSession. The MediaSession should only be used for notifications
- * at the moment.
- *
- * @return The MediaSessionCompat.Token object.
- */
- public MediaSessionCompat.Token getSessionToken() {
- return mediaSession.getSessionToken();
- }
-
- /**
* Sets the player status of the PSMP object. PlayerStatus and media attributes have to be set at the same time
* so that getPSMPInfo can't return an invalid state (e.g. status is PLAYING, but media is null).
* <p/>
@@ -822,50 +723,9 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
this.playerStatus = newStatus;
this.media = newMedia;
-
- PlaybackStateCompat.Builder sessionState = new PlaybackStateCompat.Builder();
-
- int state;
if (playerStatus != null) {
Log.d(TAG, "playerStatus: " + playerStatus.toString());
- switch (playerStatus) {
- case PLAYING:
- state = PlaybackStateCompat.STATE_PLAYING;
- break;
- case PREPARED:
- case PAUSED:
- state = PlaybackStateCompat.STATE_PAUSED;
- break;
- case STOPPED:
- state = PlaybackStateCompat.STATE_STOPPED;
- break;
- case SEEKING:
- state = PlaybackStateCompat.STATE_FAST_FORWARDING;
- break;
- case PREPARING:
- case INITIALIZING:
- state = PlaybackStateCompat.STATE_CONNECTING;
- break;
- case INITIALIZED:
- case INDETERMINATE:
- state = PlaybackStateCompat.STATE_NONE;
- break;
- case ERROR:
- state = PlaybackStateCompat.STATE_ERROR;
- break;
- default:
- state = PlaybackStateCompat.STATE_NONE;
- break;
- }
- } else {
- state = PlaybackStateCompat.STATE_NONE;
}
- sessionState.setState(state, getPosition(), getPlaybackSpeed());
- sessionState.setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE
- | PlaybackStateCompat.ACTION_REWIND
- | PlaybackStateCompat.ACTION_FAST_FORWARD
- | PlaybackStateCompat.ACTION_SKIP_TO_NEXT);
- mediaSession.setPlaybackState(sessionState.build());
callback.statusChanged(new PSMPInfo(playerStatus, media));
}
@@ -1022,6 +882,8 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
void onBufferingUpdate(int percent);
+ void updateMediaSessionMetadata(Playable p);
+
boolean onMediaPlayerInfo(int code);
boolean onMediaPlayerError(Object inObj, int what, int extra);
@@ -1130,153 +992,4 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
});
t.start();
}
-
- private final MediaSessionCompat.Callback sessionCallback = new MediaSessionCompat.Callback() {
-
- private static final String TAG = "MediaSessionCompat";
-
- @Override
- public void onPlay() {
- Log.d(TAG, "onPlay()");
- if (playerStatus == PlayerStatus.PAUSED || playerStatus == PlayerStatus.PREPARED) {
- resume();
- } else if (playerStatus == PlayerStatus.INITIALIZED) {
- setStartWhenPrepared(true);
- prepare();
- }
- }
-
- @Override
- public void onPause() {
- Log.d(TAG, "onPause()");
- if (playerStatus == PlayerStatus.PLAYING) {
- pause(false, true);
- }
- if (UserPreferences.isPersistNotify()) {
- pause(false, true);
- } else {
- pause(true, true);
- }
- }
-
- @Override
- public void onStop() {
- Log.d(TAG, "onStop()");
- stop();
- }
-
- @Override
- public void onSkipToPrevious() {
- Log.d(TAG, "onSkipToPrevious()");
- seekDelta(-UserPreferences.getRewindSecs() * 1000);
- }
-
- @Override
- public void onRewind() {
- Log.d(TAG, "onRewind()");
- seekDelta(-UserPreferences.getRewindSecs() * 1000);
- }
-
- @Override
- public void onFastForward() {
- Log.d(TAG, "onFastForward()");
- seekDelta(UserPreferences.getFastFowardSecs() * 1000);
- }
-
- @Override
- public void onSkipToNext() {
- Log.d(TAG, "onSkipToNext()");
- if(UserPreferences.shouldHardwareButtonSkip()) {
- endPlayback(true);
- } else {
- seekDelta(UserPreferences.getFastFowardSecs() * 1000);
- }
- }
-
-
- @Override
- public void onSeekTo(long pos) {
- Log.d(TAG, "onSeekTo()");
- seekTo((int) pos);
- }
-
- @Override
- public boolean onMediaButtonEvent(final Intent mediaButton) {
- Log.d(TAG, "onMediaButtonEvent(" + mediaButton + ")");
- if (mediaButton != null) {
- KeyEvent keyEvent = (KeyEvent) mediaButton.getExtras().get(Intent.EXTRA_KEY_EVENT);
- handleMediaKey(keyEvent);
- }
- return false;
- }
- };
-
- public boolean handleMediaKey(KeyEvent event) {
- Log.d(TAG, "handleMediaKey(" + event +")");
- if (event != null
- && event.getAction() == KeyEvent.ACTION_DOWN
- && event.getRepeatCount() == 0) {
- switch (event.getKeyCode()) {
- case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
- case KeyEvent.KEYCODE_HEADSETHOOK: {
- Log.d(TAG, "Received Play/Pause event from RemoteControlClient");
- if (playerStatus == PlayerStatus.PAUSED || playerStatus == PlayerStatus.PREPARED) {
- resume();
- } else if (playerStatus == PlayerStatus.INITIALIZED) {
- setStartWhenPrepared(true);
- prepare();
- } else if (playerStatus == PlayerStatus.PLAYING) {
- pause(false, true);
- if (UserPreferences.isPersistNotify()) {
- pause(false, true);
- } else {
- pause(true, true);
- }
- }
- return true;
- }
- case KeyEvent.KEYCODE_MEDIA_PLAY: {
- sessionCallback.onPlay();
- return true;
- }
- case KeyEvent.KEYCODE_MEDIA_PAUSE: {
- sessionCallback.onPause();
- return true;
- }
- case KeyEvent.KEYCODE_MEDIA_STOP: {
- sessionCallback.onStop();
- return true;
- }
- case KeyEvent.KEYCODE_MEDIA_PREVIOUS: {
- sessionCallback.onSkipToPrevious();
- return true;
- }
- case KeyEvent.KEYCODE_MEDIA_REWIND: {
- sessionCallback.onRewind();
- return true;
- }
- case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
- sessionCallback.onFastForward();
- return true;
- }
- case KeyEvent.KEYCODE_MEDIA_NEXT: {
- if(event.getSource() == InputDevice.SOURCE_CLASS_NONE ||
- UserPreferences.shouldHardwareButtonSkip()) {
- // assume the skip command comes from a notification or the lockscreen
- // a >| skip button should actually skip
- endPlayback(true);
- } else {
- // assume skip command comes from a (bluetooth) media button
- // user actually wants to fast-forward
- seekDelta(UserPreferences.getFastFowardSecs() * 1000);
- }
- return true;
- }
- default:
- Log.d(TAG, "Unhandled key code: " + event.getKeyCode());
- break;
- }
- }
- return false;
- }
}