package de.luhmer.owncloudnewsreader.services; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import android.util.Log; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import de.luhmer.owncloudnewsreader.events.podcast.NewPodcastPlaybackListener; import de.luhmer.owncloudnewsreader.events.podcast.PodcastCompletedEvent; import de.luhmer.owncloudnewsreader.events.podcast.RegisterVideoOutput; import de.luhmer.owncloudnewsreader.events.podcast.RegisterYoutubeOutput; import de.luhmer.owncloudnewsreader.events.podcast.TogglePlayerStateEvent; import de.luhmer.owncloudnewsreader.events.podcast.UpdatePodcastStatusEvent; import de.luhmer.owncloudnewsreader.events.podcast.WindPodcast; import de.luhmer.owncloudnewsreader.model.MediaItem; import de.luhmer.owncloudnewsreader.model.PodcastItem; import de.luhmer.owncloudnewsreader.model.TTSItem; import de.luhmer.owncloudnewsreader.services.podcast.MediaPlayerPlaybackService; import de.luhmer.owncloudnewsreader.services.podcast.PlaybackService; import de.luhmer.owncloudnewsreader.services.podcast.TTSPlaybackService; import de.luhmer.owncloudnewsreader.services.podcast.YoutubePlaybackService; import de.luhmer.owncloudnewsreader.view.PodcastNotification; public class PodcastPlaybackService extends Service { // Binder given to clients private final IBinder mBinder = new LocalBinder(); public MediaItem getCurrentlyPlayingPodcast() { if(mPlaybackService != null) { return mPlaybackService.getMediaItem(); } return null; } public boolean isActive() { return mPlaybackService != null; } /** * Class used for the client Binder. Because we know this service always * runs in the same process as its clients, we don't need to deal with IPC. */ public class LocalBinder extends Binder { public PodcastPlaybackService getService() { // Return this instance of LocalService so clients can call public methods return PodcastPlaybackService.this; } } @Override public IBinder onBind(Intent intent) { return mBinder; } @Override public boolean onUnbind(Intent intent) { if (!isActive()) { Log.v(TAG, "Stopping PodcastPlaybackService because of inactivity"); stopSelf(); } if(podcastNotification != null) { podcastNotification.unbind(); } return super.onUnbind(intent); } public static final String MEDIA_ITEM = "MediaItem"; private static final String TAG = "PodcastPlaybackService"; private PodcastNotification podcastNotification; private EventBus eventBus; private Handler mHandler; private PlaybackService mPlaybackService; @Override public void onCreate() { Log.v(TAG, "onCreate PodcastPlaybackService"); TelephonyManager mgr = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); if(mgr != null) { mgr.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); } podcastNotification = new PodcastNotification(this); mHandler = new Handler(); eventBus = EventBus.getDefault(); eventBus.register(this); eventBus.post(new PodcastPlaybackServiceStarted()); mHandler.postDelayed(mUpdateTimeTask, 0); super.onCreate(); } @Override public void onDestroy() { Log.v(TAG, "onDestroy PodcastPlaybackService"); TelephonyManager mgr = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); if (mgr != null) { mgr.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE); } podcastNotification.cancel(); super.onDestroy(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { if (intent != null) { if(mPlaybackService != null) { mPlaybackService.destroy(); mPlaybackService = null; } MediaItem mediaItem = (MediaItem) intent.getSerializableExtra(MEDIA_ITEM); if (mediaItem instanceof PodcastItem) { if(((PodcastItem)mediaItem).isYoutubeVideo()) { mPlaybackService = new YoutubePlaybackService(this, podcastStatusListener, mediaItem); } else { mPlaybackService = new MediaPlayerPlaybackService(this, podcastStatusListener, mediaItem); } } else if(mediaItem instanceof TTSItem) { mPlaybackService = new TTSPlaybackService(this, podcastStatusListener, mediaItem); } podcastNotification.podcastChanged(); sendMediaStatus(); } return Service.START_STICKY; } private PlaybackService.PodcastStatusListener podcastStatusListener = new PlaybackService.PodcastStatusListener() { @Override public void podcastStatusUpdated() { sendMediaStatus(); } @Override public void podcastCompleted() { Log.d(TAG, "Podcast completed, cleaning up"); mHandler.removeCallbacks(mUpdateTimeTask); podcastNotification.cancel(); mPlaybackService.destroy(); mPlaybackService = null; EventBus.getDefault().post(new PodcastCompletedEvent()); } }; public static final int delay = 500; //In milliseconds /** * Background Runnable thread * */ private Runnable mUpdateTimeTask = new Runnable() { public void run() { sendMediaStatus(); mHandler.postDelayed(this, delay); } }; @Subscribe public void onEvent(TogglePlayerStateEvent event) { if(event.getState() == TogglePlayerStateEvent.State.Toggle) { if (isPlaying()) { Log.v(TAG, "calling pause()"); pause(); } else { Log.v(TAG, "calling play()"); play(); } } else if(event.getState() == TogglePlayerStateEvent.State.Play) { Log.v(TAG, "calling play()"); play(); } else if(event.getState() == TogglePlayerStateEvent.State.Pause) { Log.v(TAG, "calling pause()"); pause(); } } private boolean isPlaying() { return (mPlaybackService != null && mPlaybackService.getStatus() == PlaybackService.Status.PLAYING); } @Subscribe public void onEvent(WindPodcast event) { if(mPlaybackService != null) { mPlaybackService.seekTo(event.toPositionInPercent); } } @Subscribe public void onEvent(RegisterVideoOutput videoOutput) { if(mPlaybackService != null && mPlaybackService instanceof MediaPlayerPlaybackService) { ((MediaPlayerPlaybackService) mPlaybackService).setVideoView(videoOutput.surfaceView, videoOutput.parentResizableView); } } @Subscribe public void onEvent(RegisterYoutubeOutput videoOutput) { if(mPlaybackService != null && mPlaybackService instanceof YoutubePlaybackService) { if(videoOutput.youTubePlayer == null) { mPlaybackService.destroy(); } else { ((YoutubePlaybackService) mPlaybackService).setYoutubePlayer(videoOutput.youTubePlayer, videoOutput.wasRestored); } } } @Subscribe public void onEvent(NewPodcastPlaybackListener newListener) { sendMediaStatus(); } public void play() { if(mPlaybackService != null) { mPlaybackService.play(); } mHandler.removeCallbacks(mUpdateTimeTask); mHandler.postDelayed(mUpdateTimeTask, 0); } public void pause() { if(mPlaybackService != null) { mPlaybackService.pause(); } mHandler.removeCallbacks(mUpdateTimeTask); sendMediaStatus(); } public void sendMediaStatus() { UpdatePodcastStatusEvent audioPodcastEvent; if(mPlaybackService == null) { audioPodcastEvent = new UpdatePodcastStatusEvent(0, 0, PlaybackService.Status.NOT_INITIALIZED, "", PlaybackService.VideoType.None, -1); } else { audioPodcastEvent = new UpdatePodcastStatusEvent( mPlaybackService.getCurrentDuration(), mPlaybackService.getTotalDuration(), mPlaybackService.getStatus(), mPlaybackService.getMediaItem().title, mPlaybackService.getVideoType(), mPlaybackService.getMediaItem().itemId); } eventBus.post(audioPodcastEvent); } public class PodcastPlaybackServiceStarted { } PhoneStateListener phoneStateListener = new PhoneStateListener() { @Override public void onCallStateChanged(int state, String incomingNumber) { if (state == TelephonyManager.CALL_STATE_RINGING) { //Incoming call: Pause music pause(); } else if(state == TelephonyManager.CALL_STATE_IDLE) { //Not in call: Play music } else if(state == TelephonyManager.CALL_STATE_OFFHOOK) { //A call is dialing, active or on hold } super.onCallStateChanged(state, incomingNumber); } }; }