adapt PlaybackService to different flavors
This commit is contained in:
parent
58ddbd5728
commit
8b791fbab4
|
@ -0,0 +1,44 @@
|
||||||
|
package de.danoeh.antennapod.core.service.playback;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.support.annotation.StringRes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class intended to work along PlaybackService and provide support for different flavors.
|
||||||
|
*/
|
||||||
|
public class PlaybackServiceFlavorHelper {
|
||||||
|
|
||||||
|
private PlaybackService.FlavorHelperCallback callback;
|
||||||
|
|
||||||
|
PlaybackServiceFlavorHelper(Context context, PlaybackService.FlavorHelperCallback callback) {
|
||||||
|
this.callback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void initializeMediaPlayer(Context context) {
|
||||||
|
callback.setMediaPlayer(new LocalPSMP(context, callback.getMediaPlayerCallback()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeCastConsumer() {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean castDisconnect(boolean castDisconnect) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean onMediaPlayerInfo(Context context, int code, @StringRes int resourceId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void registerWifiBroadcastReceiver() {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
void unregisterWifiBroadcastReceiver() {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean onSharedPreference(String key) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,14 +15,11 @@ import android.graphics.Bitmap;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
import android.media.MediaPlayer;
|
import android.media.MediaPlayer;
|
||||||
import android.net.NetworkInfo;
|
|
||||||
import android.net.wifi.WifiManager;
|
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.Vibrator;
|
import android.os.Vibrator;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.support.annotation.StringRes;
|
import android.support.annotation.StringRes;
|
||||||
import android.support.v4.media.MediaMetadataCompat;
|
import android.support.v4.media.MediaMetadataCompat;
|
||||||
import android.support.v4.media.session.MediaSessionCompat;
|
import android.support.v4.media.session.MediaSessionCompat;
|
||||||
|
@ -61,6 +58,7 @@ import de.danoeh.antennapod.core.storage.DBWriter;
|
||||||
import de.danoeh.antennapod.core.util.IntList;
|
import de.danoeh.antennapod.core.util.IntList;
|
||||||
import de.danoeh.antennapod.core.util.QueueAccess;
|
import de.danoeh.antennapod.core.util.QueueAccess;
|
||||||
import de.danoeh.antennapod.core.util.flattr.FlattrUtils;
|
import de.danoeh.antennapod.core.util.flattr.FlattrUtils;
|
||||||
|
import de.danoeh.antennapod.core.util.playback.ExternalMedia;
|
||||||
import de.danoeh.antennapod.core.util.playback.Playable;
|
import de.danoeh.antennapod.core.util.playback.Playable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -174,12 +172,6 @@ public class PlaybackService extends Service {
|
||||||
*/
|
*/
|
||||||
public static final int INVALID_TIME = -1;
|
public static final int INVALID_TIME = -1;
|
||||||
|
|
||||||
/**
|
|
||||||
* Time in seconds during which the CastManager will try to reconnect to the Cast Device after
|
|
||||||
* the Wifi Connection is regained.
|
|
||||||
*/
|
|
||||||
private static final int RECONNECTION_ATTEMPT_PERIOD_S = 15;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is true if service is running.
|
* Is true if service is running.
|
||||||
*/
|
*/
|
||||||
|
@ -196,21 +188,13 @@ public class PlaybackService extends Service {
|
||||||
* Is true if a Cast Device is connected to the service.
|
* Is true if a Cast Device is connected to the service.
|
||||||
*/
|
*/
|
||||||
private static volatile boolean isCasting = false;
|
private static volatile boolean isCasting = false;
|
||||||
/**
|
|
||||||
* Stores the state of the cast playback just before it disconnects.
|
|
||||||
*/
|
|
||||||
private volatile PlaybackServiceMediaPlayer.PSMPInfo infoBeforeCastDisconnection;
|
|
||||||
|
|
||||||
private boolean wifiConnectivity = true;
|
|
||||||
private BroadcastReceiver wifiBroadcastReceiver;
|
|
||||||
|
|
||||||
private static final int NOTIFICATION_ID = 1;
|
private static final int NOTIFICATION_ID = 1;
|
||||||
|
|
||||||
private PlaybackServiceMediaPlayer mediaPlayer;
|
private PlaybackServiceMediaPlayer mediaPlayer;
|
||||||
private PlaybackServiceTaskManager taskManager;
|
private PlaybackServiceTaskManager taskManager;
|
||||||
|
private PlaybackServiceFlavorHelper flavorHelper;
|
||||||
|
|
||||||
// private CastManager castManager;
|
|
||||||
// private MediaRouter mediaRouter;
|
|
||||||
/**
|
/**
|
||||||
* Only used for Lollipop notifications.
|
* Only used for Lollipop notifications.
|
||||||
*/
|
*/
|
||||||
|
@ -284,7 +268,7 @@ public class PlaybackService extends Service {
|
||||||
ACTION_RESUME_PLAY_CURRENT_EPISODE));
|
ACTION_RESUME_PLAY_CURRENT_EPISODE));
|
||||||
taskManager = new PlaybackServiceTaskManager(this, taskManagerCallback);
|
taskManager = new PlaybackServiceTaskManager(this, taskManagerCallback);
|
||||||
|
|
||||||
// mediaRouter = MediaRouter.getInstance(getApplicationContext());
|
flavorHelper = new PlaybackServiceFlavorHelper(PlaybackService.this, flavorHelperCallback);
|
||||||
PreferenceManager.getDefaultSharedPreferences(this)
|
PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
.registerOnSharedPreferenceChangeListener(prefListener);
|
.registerOnSharedPreferenceChangeListener(prefListener);
|
||||||
|
|
||||||
|
@ -308,18 +292,7 @@ public class PlaybackService extends Service {
|
||||||
npe.printStackTrace();
|
npe.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
// castManager = CastManager.getInstance();
|
flavorHelper.initializeMediaPlayer(PlaybackService.this);
|
||||||
// castManager.addCastConsumer(castConsumer);
|
|
||||||
// isCasting = castManager.isConnected();
|
|
||||||
// if (isCasting) {
|
|
||||||
// if (UserPreferences.isCastEnabled()) {
|
|
||||||
// onCastAppConnected(false);
|
|
||||||
// } else {
|
|
||||||
// castManager.disconnect();
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
mediaPlayer = new LocalPSMP(this, mediaPlayerCallback);
|
|
||||||
// }
|
|
||||||
|
|
||||||
mediaSession.setActive(true);
|
mediaSession.setActive(true);
|
||||||
}
|
}
|
||||||
|
@ -346,8 +319,8 @@ public class PlaybackService extends Service {
|
||||||
unregisterReceiver(skipCurrentEpisodeReceiver);
|
unregisterReceiver(skipCurrentEpisodeReceiver);
|
||||||
unregisterReceiver(pausePlayCurrentEpisodeReceiver);
|
unregisterReceiver(pausePlayCurrentEpisodeReceiver);
|
||||||
unregisterReceiver(pauseResumeCurrentEpisodeReceiver);
|
unregisterReceiver(pauseResumeCurrentEpisodeReceiver);
|
||||||
// castManager.removeCastConsumer(castConsumer);
|
flavorHelper.removeCastConsumer();
|
||||||
unregisterWifiBroadcastReceiver();
|
flavorHelper.unregisterWifiBroadcastReceiver();
|
||||||
mediaPlayer.shutdown();
|
mediaPlayer.shutdown();
|
||||||
taskManager.shutdown();
|
taskManager.shutdown();
|
||||||
}
|
}
|
||||||
|
@ -381,9 +354,7 @@ public class PlaybackService extends Service {
|
||||||
Log.d(TAG, "Received media button event");
|
Log.d(TAG, "Received media button event");
|
||||||
handleKeycode(keycode, intent.getIntExtra(MediaButtonReceiver.EXTRA_SOURCE,
|
handleKeycode(keycode, intent.getIntExtra(MediaButtonReceiver.EXTRA_SOURCE,
|
||||||
InputDevice.SOURCE_CLASS_NONE));
|
InputDevice.SOURCE_CLASS_NONE));
|
||||||
// } else if (castDisconnect) {
|
} else if (!flavorHelper.castDisconnect(castDisconnect)) {
|
||||||
// castManager.disconnect();
|
|
||||||
} else {
|
|
||||||
started = true;
|
started = true;
|
||||||
boolean stream = intent.getBooleanExtra(EXTRA_SHOULD_STREAM,
|
boolean stream = intent.getBooleanExtra(EXTRA_SHOULD_STREAM,
|
||||||
true);
|
true);
|
||||||
|
@ -391,9 +362,7 @@ public class PlaybackService extends Service {
|
||||||
boolean prepareImmediately = intent.getBooleanExtra(EXTRA_PREPARE_IMMEDIATELY, false);
|
boolean prepareImmediately = intent.getBooleanExtra(EXTRA_PREPARE_IMMEDIATELY, false);
|
||||||
sendNotificationBroadcast(NOTIFICATION_TYPE_RELOAD, 0);
|
sendNotificationBroadcast(NOTIFICATION_TYPE_RELOAD, 0);
|
||||||
//If the user asks to play External Media, the casting session, if on, should end.
|
//If the user asks to play External Media, the casting session, if on, should end.
|
||||||
// if (playable instanceof ExternalMedia) {
|
flavorHelper.castDisconnect(playable instanceof ExternalMedia);
|
||||||
// castManager.disconnect();
|
|
||||||
// }
|
|
||||||
mediaPlayer.playMediaObject(playable, stream, startWhenPrepared, prepareImmediately);
|
mediaPlayer.playMediaObject(playable, stream, startWhenPrepared, prepareImmediately);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -649,14 +618,8 @@ public class PlaybackService extends Service {
|
||||||
case MediaPlayer.MEDIA_INFO_BUFFERING_END:
|
case MediaPlayer.MEDIA_INFO_BUFFERING_END:
|
||||||
sendNotificationBroadcast(NOTIFICATION_TYPE_BUFFER_END, 0);
|
sendNotificationBroadcast(NOTIFICATION_TYPE_BUFFER_END, 0);
|
||||||
return true;
|
return true;
|
||||||
// case RemotePSMP.CAST_ERROR:
|
|
||||||
// sendNotificationBroadcast(NOTIFICATION_TYPE_SHOW_TOAST, resourceId);
|
|
||||||
// return true;
|
|
||||||
// case RemotePSMP.CAST_ERROR_PRIORITY_HIGH:
|
|
||||||
// Toast.makeText(PlaybackService.this, resourceId, Toast.LENGTH_SHORT).show();
|
|
||||||
// return true;
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return flavorHelper.onMediaPlayerInfo(PlaybackService.this, code, resourceId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1527,67 +1490,6 @@ public class PlaybackService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// private CastConsumer castConsumer = new DefaultCastConsumer() {
|
|
||||||
// @Override
|
|
||||||
// public void onApplicationConnected(ApplicationMetadata appMetadata, String sessionId, boolean wasLaunched) {
|
|
||||||
// PlaybackService.this.onCastAppConnected(wasLaunched);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public void onDisconnectionReason(int reason) {
|
|
||||||
// Log.d(TAG, "onDisconnectionReason() with code " + reason);
|
|
||||||
// // This is our final chance to update the underlying stream position
|
|
||||||
// // In onDisconnected(), the underlying CastPlayback#mVideoCastConsumer
|
|
||||||
// // is disconnected and hence we update our local value of stream position
|
|
||||||
// // to the latest position.
|
|
||||||
// if (mediaPlayer != null) {
|
|
||||||
// saveCurrentPosition(false, 0);
|
|
||||||
// infoBeforeCastDisconnection = mediaPlayer.getPSMPInfo();
|
|
||||||
// if (reason != BaseCastManager.DISCONNECT_REASON_EXPLICIT &&
|
|
||||||
// infoBeforeCastDisconnection.playerStatus == PlayerStatus.PLAYING) {
|
|
||||||
// // If it's NOT based on user action, we shouldn't automatically resume local playback
|
|
||||||
// infoBeforeCastDisconnection.playerStatus = PlayerStatus.PAUSED;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public void onDisconnected() {
|
|
||||||
// Log.d(TAG, "onDisconnected()");
|
|
||||||
// isCasting = false;
|
|
||||||
// PlaybackServiceMediaPlayer.PSMPInfo info = infoBeforeCastDisconnection;
|
|
||||||
// infoBeforeCastDisconnection = null;
|
|
||||||
// if (info == null && mediaPlayer != null) {
|
|
||||||
// info = mediaPlayer.getPSMPInfo();
|
|
||||||
// }
|
|
||||||
// if (info == null) {
|
|
||||||
// info = new PlaybackServiceMediaPlayer.PSMPInfo(PlayerStatus.STOPPED, null);
|
|
||||||
// }
|
|
||||||
// switchMediaPlayer(new LocalPSMP(PlaybackService.this, mediaPlayerCallback),
|
|
||||||
// info, true);
|
|
||||||
// if (info.playable != null) {
|
|
||||||
// sendNotificationBroadcast(NOTIFICATION_TYPE_RELOAD,
|
|
||||||
// info.playable.getMediaType() == MediaType.AUDIO ? EXTRA_CODE_AUDIO : EXTRA_CODE_VIDEO);
|
|
||||||
// } else {
|
|
||||||
// Log.d(TAG, "Cast session disconnected, but no current media");
|
|
||||||
// sendNotificationBroadcast(NOTIFICATION_TYPE_PLAYBACK_END, 0);
|
|
||||||
// }
|
|
||||||
// // hardware volume buttons control the local device volume
|
|
||||||
// mediaRouter.setMediaSessionCompat(null);
|
|
||||||
// unregisterWifiBroadcastReceiver();
|
|
||||||
// PlayerStatus status = info.playerStatus;
|
|
||||||
// if ((status == PlayerStatus.PLAYING ||
|
|
||||||
// status == PlayerStatus.SEEKING ||
|
|
||||||
// status == PlayerStatus.PREPARING ||
|
|
||||||
// UserPreferences.isPersistNotify()) &&
|
|
||||||
// android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
|
||||||
// setupNotification(info);
|
|
||||||
// } else if (!UserPreferences.isPersistNotify()){
|
|
||||||
// stopForeground(true);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
private final MediaSessionCompat.Callback sessionCallback = new MediaSessionCompat.Callback() {
|
private final MediaSessionCompat.Callback sessionCallback = new MediaSessionCompat.Callback() {
|
||||||
|
|
||||||
private static final String TAG = "MediaSessionCompat";
|
private static final String TAG = "MediaSessionCompat";
|
||||||
|
@ -1673,101 +1575,90 @@ public class PlaybackService extends Service {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// private void onCastAppConnected(boolean wasLaunched) {
|
|
||||||
// Log.d(TAG, "A cast device application was " + (wasLaunched ? "launched" : "joined"));
|
|
||||||
// isCasting = true;
|
|
||||||
// PlaybackServiceMediaPlayer.PSMPInfo info = null;
|
|
||||||
// if (mediaPlayer != null) {
|
|
||||||
// info = mediaPlayer.getPSMPInfo();
|
|
||||||
// if (info.playerStatus == PlayerStatus.PLAYING) {
|
|
||||||
// // could be pause, but this way we make sure the new player will get the correct position,
|
|
||||||
// // since pause runs asynchronously and we could be directing the new player to play even before
|
|
||||||
// // the old player gives us back the position.
|
|
||||||
// saveCurrentPosition(false, 0);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// if (info == null) {
|
|
||||||
// info = new PlaybackServiceMediaPlayer.PSMPInfo(PlayerStatus.STOPPED, null);
|
|
||||||
// }
|
|
||||||
// sendNotificationBroadcast(NOTIFICATION_TYPE_RELOAD, EXTRA_CODE_CAST);
|
|
||||||
// switchMediaPlayer(new RemotePSMP(PlaybackService.this, mediaPlayerCallback),
|
|
||||||
// info,
|
|
||||||
// wasLaunched);
|
|
||||||
// // hardware volume buttons control the remote device volume
|
|
||||||
// mediaRouter.setMediaSessionCompat(mediaSession);
|
|
||||||
// registerWifiBroadcastReceiver();
|
|
||||||
// setupNotification(info);
|
|
||||||
// }
|
|
||||||
|
|
||||||
private void switchMediaPlayer(@NonNull PlaybackServiceMediaPlayer newPlayer,
|
|
||||||
@NonNull PlaybackServiceMediaPlayer.PSMPInfo info,
|
|
||||||
boolean wasLaunched) {
|
|
||||||
if (mediaPlayer != null) {
|
|
||||||
mediaPlayer.endPlayback(true, true);
|
|
||||||
mediaPlayer.shutdownQuietly();
|
|
||||||
}
|
|
||||||
mediaPlayer = newPlayer;
|
|
||||||
Log.d(TAG, "switched to " + mediaPlayer.getClass().getSimpleName());
|
|
||||||
if (!wasLaunched) {
|
|
||||||
PlaybackServiceMediaPlayer.PSMPInfo candidate = mediaPlayer.getPSMPInfo();
|
|
||||||
if (candidate.playable != null &&
|
|
||||||
candidate.playerStatus.isAtLeast(PlayerStatus.PREPARING)) {
|
|
||||||
// do not automatically send new media to cast device
|
|
||||||
info.playable = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (info.playable != null) {
|
|
||||||
mediaPlayer.playMediaObject(info.playable,
|
|
||||||
!info.playable.localFileAvailable(),
|
|
||||||
info.playerStatus == PlayerStatus.PLAYING,
|
|
||||||
info.playerStatus.isAtLeast(PlayerStatus.PREPARING));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void registerWifiBroadcastReceiver() {
|
|
||||||
if (wifiBroadcastReceiver != null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
wifiBroadcastReceiver = new BroadcastReceiver() {
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
if (intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
|
|
||||||
NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
|
|
||||||
boolean isConnected = info.isConnected();
|
|
||||||
//apparently this method gets called twice when a change happens, but one run is enough.
|
|
||||||
if (isConnected && !wifiConnectivity) {
|
|
||||||
wifiConnectivity = true;
|
|
||||||
// castManager.startCastDiscovery();
|
|
||||||
// castManager.reconnectSessionIfPossible(RECONNECTION_ATTEMPT_PERIOD_S, NetworkUtils.getWifiSsid());
|
|
||||||
} else {
|
|
||||||
wifiConnectivity = isConnected;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
registerReceiver(wifiBroadcastReceiver,
|
|
||||||
new IntentFilter(WifiManager.NETWORK_STATE_CHANGED_ACTION));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void unregisterWifiBroadcastReceiver() {
|
|
||||||
if (wifiBroadcastReceiver != null) {
|
|
||||||
unregisterReceiver(wifiBroadcastReceiver);
|
|
||||||
wifiBroadcastReceiver = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private SharedPreferences.OnSharedPreferenceChangeListener prefListener =
|
private SharedPreferences.OnSharedPreferenceChangeListener prefListener =
|
||||||
(sharedPreferences, key) -> {
|
(sharedPreferences, key) -> {
|
||||||
// if (UserPreferences.PREF_CAST_ENABLED.equals(key)) {
|
|
||||||
// if (!UserPreferences.isCastEnabled()) {
|
|
||||||
// if (castManager.isConnecting() || castManager.isConnected()) {
|
|
||||||
// Log.d(TAG, "Disconnecting cast device due to a change in user preferences");
|
|
||||||
// castManager.disconnect();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// } else
|
|
||||||
if (UserPreferences.PREF_LOCKSCREEN_BACKGROUND.equals(key)) {
|
if (UserPreferences.PREF_LOCKSCREEN_BACKGROUND.equals(key)) {
|
||||||
updateMediaSessionMetadata(getPlayable());
|
updateMediaSessionMetadata(getPlayable());
|
||||||
|
} else {
|
||||||
|
flavorHelper.onSharedPreference(key);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
interface FlavorHelperCallback {
|
||||||
|
PlaybackServiceMediaPlayer.PSMPCallback getMediaPlayerCallback();
|
||||||
|
void setMediaPlayer(PlaybackServiceMediaPlayer mediaPlayer);
|
||||||
|
PlaybackServiceMediaPlayer getMediaPlayer();
|
||||||
|
void setIsCasting(boolean isCasting);
|
||||||
|
void sendNotificationBroadcast(int type, int code);
|
||||||
|
void saveCurrentPosition(boolean updatePlayedDuration, int deltaPlayedDuration);
|
||||||
|
void setupNotification(boolean connected, PlaybackServiceMediaPlayer.PSMPInfo info);
|
||||||
|
MediaSessionCompat getMediaSession();
|
||||||
|
Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter);
|
||||||
|
void unregisterReceiver(BroadcastReceiver receiver);
|
||||||
|
}
|
||||||
|
|
||||||
|
private FlavorHelperCallback flavorHelperCallback = new FlavorHelperCallback() {
|
||||||
|
@Override
|
||||||
|
public PlaybackServiceMediaPlayer.PSMPCallback getMediaPlayerCallback() {
|
||||||
|
return PlaybackService.this.mediaPlayerCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMediaPlayer(PlaybackServiceMediaPlayer mediaPlayer) {
|
||||||
|
PlaybackService.this.mediaPlayer = mediaPlayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PlaybackServiceMediaPlayer getMediaPlayer() {
|
||||||
|
return PlaybackService.this.mediaPlayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setIsCasting(boolean isCasting) {
|
||||||
|
PlaybackService.isCasting = isCasting;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendNotificationBroadcast(int type, int code) {
|
||||||
|
PlaybackService.this.sendNotificationBroadcast(type, code);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveCurrentPosition(boolean updatePlayedDuration, int deltaPlayedDuration) {
|
||||||
|
PlaybackService.this.saveCurrentPosition(updatePlayedDuration, deltaPlayedDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setupNotification(boolean connected, PlaybackServiceMediaPlayer.PSMPInfo info) {
|
||||||
|
if (connected) {
|
||||||
|
PlaybackService.this.setupNotification(info);
|
||||||
|
} else {
|
||||||
|
PlayerStatus status = info.playerStatus;
|
||||||
|
if ((status == PlayerStatus.PLAYING ||
|
||||||
|
status == PlayerStatus.SEEKING ||
|
||||||
|
status == PlayerStatus.PREPARING ||
|
||||||
|
UserPreferences.isPersistNotify()) &&
|
||||||
|
android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||||
|
PlaybackService.this.setupNotification(info);
|
||||||
|
} else if (!UserPreferences.isPersistNotify()){
|
||||||
|
PlaybackService.this.stopForeground(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MediaSessionCompat getMediaSession() {
|
||||||
|
return PlaybackService.this.mediaSession;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
|
||||||
|
return PlaybackService.this.registerReceiver(receiver, filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unregisterReceiver(BroadcastReceiver receiver) {
|
||||||
|
PlaybackService.this.unregisterReceiver(receiver);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,252 @@
|
||||||
|
package de.danoeh.antennapod.core.service.playback;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.net.NetworkInfo;
|
||||||
|
import android.net.wifi.WifiManager;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.StringRes;
|
||||||
|
import android.support.v7.media.MediaRouter;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.google.android.gms.cast.ApplicationMetadata;
|
||||||
|
import com.google.android.libraries.cast.companionlibrary.cast.BaseCastManager;
|
||||||
|
|
||||||
|
import de.danoeh.antennapod.core.cast.CastConsumer;
|
||||||
|
import de.danoeh.antennapod.core.cast.CastManager;
|
||||||
|
import de.danoeh.antennapod.core.cast.DefaultCastConsumer;
|
||||||
|
import de.danoeh.antennapod.core.feed.MediaType;
|
||||||
|
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||||
|
import de.danoeh.antennapod.core.util.NetworkUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class intended to work along PlaybackService and provide support for different flavors.
|
||||||
|
*/
|
||||||
|
public class PlaybackServiceFlavorHelper {
|
||||||
|
public static final String TAG = "PlaybackSrvFlavorHelper";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time in seconds during which the CastManager will try to reconnect to the Cast Device after
|
||||||
|
* the Wifi Connection is regained.
|
||||||
|
*/
|
||||||
|
private static final int RECONNECTION_ATTEMPT_PERIOD_S = 15;
|
||||||
|
/**
|
||||||
|
* Stores the state of the cast playback just before it disconnects.
|
||||||
|
*/
|
||||||
|
private volatile PlaybackServiceMediaPlayer.PSMPInfo infoBeforeCastDisconnection;
|
||||||
|
|
||||||
|
private boolean wifiConnectivity = true;
|
||||||
|
private BroadcastReceiver wifiBroadcastReceiver;
|
||||||
|
|
||||||
|
private CastManager castManager;
|
||||||
|
private MediaRouter mediaRouter;
|
||||||
|
private PlaybackService.FlavorHelperCallback callback;
|
||||||
|
private CastConsumer castConsumer;
|
||||||
|
|
||||||
|
PlaybackServiceFlavorHelper(Context context, PlaybackService.FlavorHelperCallback callback) {
|
||||||
|
this.callback = callback;
|
||||||
|
mediaRouter = MediaRouter.getInstance(context.getApplicationContext());
|
||||||
|
setCastConsumer(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
void initializeMediaPlayer(Context context) {
|
||||||
|
castManager = CastManager.getInstance();
|
||||||
|
castManager.addCastConsumer(castConsumer);
|
||||||
|
boolean isCasting = castManager.isConnected();
|
||||||
|
callback.setIsCasting(isCasting);
|
||||||
|
if (isCasting) {
|
||||||
|
if (UserPreferences.isCastEnabled()) {
|
||||||
|
onCastAppConnected(context, false);
|
||||||
|
} else {
|
||||||
|
castManager.disconnect();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
callback.setMediaPlayer(new LocalPSMP(context, callback.getMediaPlayerCallback()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeCastConsumer() {
|
||||||
|
castManager.removeCastConsumer(castConsumer);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean castDisconnect(boolean castDisconnect) {
|
||||||
|
if (castDisconnect) {
|
||||||
|
castManager.disconnect();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean onMediaPlayerInfo(Context context, int code, @StringRes int resourceId) {
|
||||||
|
switch (code) {
|
||||||
|
case RemotePSMP.CAST_ERROR:
|
||||||
|
callback.sendNotificationBroadcast(PlaybackService.NOTIFICATION_TYPE_SHOW_TOAST, resourceId);
|
||||||
|
return true;
|
||||||
|
case RemotePSMP.CAST_ERROR_PRIORITY_HIGH:
|
||||||
|
Toast.makeText(context, resourceId, Toast.LENGTH_SHORT).show();
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setCastConsumer(Context context) {
|
||||||
|
castConsumer = new DefaultCastConsumer() {
|
||||||
|
@Override
|
||||||
|
public void onApplicationConnected(ApplicationMetadata appMetadata, String sessionId, boolean wasLaunched) {
|
||||||
|
onCastAppConnected(context, wasLaunched);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisconnectionReason(int reason) {
|
||||||
|
Log.d(TAG, "onDisconnectionReason() with code " + reason);
|
||||||
|
// This is our final chance to update the underlying stream position
|
||||||
|
// In onDisconnected(), the underlying CastPlayback#mVideoCastConsumer
|
||||||
|
// is disconnected and hence we update our local value of stream position
|
||||||
|
// to the latest position.
|
||||||
|
PlaybackServiceMediaPlayer mediaPlayer = callback.getMediaPlayer();
|
||||||
|
if (mediaPlayer != null) {
|
||||||
|
callback.saveCurrentPosition(false, 0);
|
||||||
|
infoBeforeCastDisconnection = mediaPlayer.getPSMPInfo();
|
||||||
|
if (reason != BaseCastManager.DISCONNECT_REASON_EXPLICIT &&
|
||||||
|
infoBeforeCastDisconnection.playerStatus == PlayerStatus.PLAYING) {
|
||||||
|
// If it's NOT based on user action, we shouldn't automatically resume local playback
|
||||||
|
infoBeforeCastDisconnection.playerStatus = PlayerStatus.PAUSED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisconnected() {
|
||||||
|
Log.d(TAG, "onDisconnected()");
|
||||||
|
callback.setIsCasting(false);
|
||||||
|
PlaybackServiceMediaPlayer.PSMPInfo info = infoBeforeCastDisconnection;
|
||||||
|
infoBeforeCastDisconnection = null;
|
||||||
|
PlaybackServiceMediaPlayer mediaPlayer = callback.getMediaPlayer();
|
||||||
|
if (info == null && mediaPlayer != null) {
|
||||||
|
info = mediaPlayer.getPSMPInfo();
|
||||||
|
}
|
||||||
|
if (info == null) {
|
||||||
|
info = new PlaybackServiceMediaPlayer.PSMPInfo(PlayerStatus.STOPPED, null);
|
||||||
|
}
|
||||||
|
switchMediaPlayer(new LocalPSMP(context, callback.getMediaPlayerCallback()),
|
||||||
|
info, true);
|
||||||
|
if (info.playable != null) {
|
||||||
|
callback.sendNotificationBroadcast(PlaybackService.NOTIFICATION_TYPE_RELOAD,
|
||||||
|
info.playable.getMediaType() == MediaType.AUDIO ?
|
||||||
|
PlaybackService.EXTRA_CODE_AUDIO : PlaybackService.EXTRA_CODE_VIDEO);
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "Cast session disconnected, but no current media");
|
||||||
|
callback.sendNotificationBroadcast(PlaybackService.NOTIFICATION_TYPE_PLAYBACK_END, 0);
|
||||||
|
}
|
||||||
|
// hardware volume buttons control the local device volume
|
||||||
|
mediaRouter.setMediaSessionCompat(null);
|
||||||
|
unregisterWifiBroadcastReceiver();
|
||||||
|
callback.setupNotification(false, info);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onCastAppConnected(Context context, boolean wasLaunched) {
|
||||||
|
Log.d(TAG, "A cast device application was " + (wasLaunched ? "launched" : "joined"));
|
||||||
|
callback.setIsCasting(true);
|
||||||
|
PlaybackServiceMediaPlayer.PSMPInfo info = null;
|
||||||
|
PlaybackServiceMediaPlayer mediaPlayer = callback.getMediaPlayer();
|
||||||
|
if (mediaPlayer != null) {
|
||||||
|
info = mediaPlayer.getPSMPInfo();
|
||||||
|
if (info.playerStatus == PlayerStatus.PLAYING) {
|
||||||
|
// could be pause, but this way we make sure the new player will get the correct position,
|
||||||
|
// since pause runs asynchronously and we could be directing the new player to play even before
|
||||||
|
// the old player gives us back the position.
|
||||||
|
callback.saveCurrentPosition(false, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (info == null) {
|
||||||
|
info = new PlaybackServiceMediaPlayer.PSMPInfo(PlayerStatus.STOPPED, null);
|
||||||
|
}
|
||||||
|
callback.sendNotificationBroadcast(PlaybackService.NOTIFICATION_TYPE_RELOAD,
|
||||||
|
PlaybackService.EXTRA_CODE_CAST);
|
||||||
|
switchMediaPlayer(new RemotePSMP(context, callback.getMediaPlayerCallback()),
|
||||||
|
info,
|
||||||
|
wasLaunched);
|
||||||
|
// hardware volume buttons control the remote device volume
|
||||||
|
mediaRouter.setMediaSessionCompat(callback.getMediaSession());
|
||||||
|
registerWifiBroadcastReceiver();
|
||||||
|
callback.setupNotification(true, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void switchMediaPlayer(@NonNull PlaybackServiceMediaPlayer newPlayer,
|
||||||
|
@NonNull PlaybackServiceMediaPlayer.PSMPInfo info,
|
||||||
|
boolean wasLaunched) {
|
||||||
|
PlaybackServiceMediaPlayer mediaPlayer = callback.getMediaPlayer();
|
||||||
|
if (mediaPlayer != null) {
|
||||||
|
mediaPlayer.endPlayback(true, true);
|
||||||
|
mediaPlayer.shutdownQuietly();
|
||||||
|
}
|
||||||
|
mediaPlayer = newPlayer;
|
||||||
|
callback.setMediaPlayer(mediaPlayer);
|
||||||
|
Log.d(TAG, "switched to " + mediaPlayer.getClass().getSimpleName());
|
||||||
|
if (!wasLaunched) {
|
||||||
|
PlaybackServiceMediaPlayer.PSMPInfo candidate = mediaPlayer.getPSMPInfo();
|
||||||
|
if (candidate.playable != null &&
|
||||||
|
candidate.playerStatus.isAtLeast(PlayerStatus.PREPARING)) {
|
||||||
|
// do not automatically send new media to cast device
|
||||||
|
info.playable = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (info.playable != null) {
|
||||||
|
mediaPlayer.playMediaObject(info.playable,
|
||||||
|
!info.playable.localFileAvailable(),
|
||||||
|
info.playerStatus == PlayerStatus.PLAYING,
|
||||||
|
info.playerStatus.isAtLeast(PlayerStatus.PREPARING));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void registerWifiBroadcastReceiver() {
|
||||||
|
if (wifiBroadcastReceiver != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wifiBroadcastReceiver = new BroadcastReceiver() {
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
if (intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
|
||||||
|
NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
|
||||||
|
boolean isConnected = info.isConnected();
|
||||||
|
//apparently this method gets called twice when a change happens, but one run is enough.
|
||||||
|
if (isConnected && !wifiConnectivity) {
|
||||||
|
wifiConnectivity = true;
|
||||||
|
castManager.startCastDiscovery();
|
||||||
|
castManager.reconnectSessionIfPossible(RECONNECTION_ATTEMPT_PERIOD_S, NetworkUtils.getWifiSsid());
|
||||||
|
} else {
|
||||||
|
wifiConnectivity = isConnected;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
callback.registerReceiver(wifiBroadcastReceiver,
|
||||||
|
new IntentFilter(WifiManager.NETWORK_STATE_CHANGED_ACTION));
|
||||||
|
}
|
||||||
|
|
||||||
|
void unregisterWifiBroadcastReceiver() {
|
||||||
|
if (wifiBroadcastReceiver != null) {
|
||||||
|
callback.unregisterReceiver(wifiBroadcastReceiver);
|
||||||
|
wifiBroadcastReceiver = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean onSharedPreference(String key) {
|
||||||
|
if (UserPreferences.PREF_CAST_ENABLED.equals(key)) {
|
||||||
|
if (!UserPreferences.isCastEnabled()) {
|
||||||
|
if (castManager.isConnecting() || castManager.isConnected()) {
|
||||||
|
Log.d(TAG, "Disconnecting cast device due to a change in user preferences");
|
||||||
|
castManager.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue