diff options
Diffstat (limited to 'News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/services')
6 files changed, 577 insertions, 275 deletions
diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/services/OwnCloudSyncService.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/services/OwnCloudSyncService.java index 681e2f33..7c89cdfd 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/services/OwnCloudSyncService.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/services/OwnCloudSyncService.java @@ -42,7 +42,6 @@ import org.greenrobot.eventbus.EventBus; import java.util.List; import java.util.concurrent.CountDownLatch; -import de.luhmer.owncloudnewsreader.Constants; import de.luhmer.owncloudnewsreader.ListView.SubscriptionExpandableListAdapter; import de.luhmer.owncloudnewsreader.R; import de.luhmer.owncloudnewsreader.SettingsActivity; diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/services/PodcastPlaybackService.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/services/PodcastPlaybackService.java index 4bbc45f3..7476d19d 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/services/PodcastPlaybackService.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/services/PodcastPlaybackService.java @@ -2,47 +2,47 @@ package de.luhmer.owncloudnewsreader.services; import android.app.Service; import android.content.Intent; -import android.media.MediaPlayer; import android.os.Binder; import android.os.Handler; import android.os.IBinder; -import android.speech.tts.TextToSpeech; -import android.speech.tts.UtteranceProgressListener; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import android.util.Log; -import android.view.SurfaceHolder; import android.view.View; -import android.widget.Toast; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; -import java.io.IOException; -import java.util.HashMap; - -import de.luhmer.owncloudnewsreader.R; 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 implements TextToSpeech.OnInitListener { +public class PodcastPlaybackService extends Service { // Binder given to clients private final IBinder mBinder = new LocalBinder(); - public PodcastItem getCurrentlyPlayingPodcast() { - return mCurrentlyPlayingPodcast; + public MediaItem getCurrentlyPlayingPodcast() { + if(mPlaybackService != null) { + return mPlaybackService.getMediaItem(); + } + return null; } public boolean isActive() { - return mCurrentlyPlayingPodcast != null || mCurrentlyPlayingTTS != null; + return mPlaybackService != null; } /** @@ -75,72 +75,33 @@ public class PodcastPlaybackService extends Service implements TextToSpeech.OnIn return super.onUnbind(intent); } - public static final String PODCAST_ITEM = "PODCAST_ITEM"; - public static final String TTS_ITEM = "TTS_ITEM"; - - private PodcastItem mCurrentlyPlayingPodcast; - private TTSItem mCurrentlyPlayingTTS; + public static final String MEDIA_ITEM = "MediaItem"; private static final String TAG = "PodcastPlaybackService"; private PodcastNotification podcastNotification; private EventBus eventBus; private Handler mHandler; - private MediaPlayer mMediaPlayer; - - private TextToSpeech ttsController; - private String mediaTitle; - private PlaybackType mPlaybackType; + private PlaybackService mPlaybackService; private View parentResizableView; - private enum PlaybackType { PODCAST, TTS } + @Override public void onCreate() { Log.v(TAG, "onCreate PodcastPlaybackService"); - mediaTitle = getString(R.string.no_podcast_selected); - TelephonyManager mgr = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); if(mgr != null) { mgr.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); } - mMediaPlayer = new MediaPlayer(); + podcastNotification = new PodcastNotification(this); mHandler = new Handler(); eventBus = EventBus.getDefault(); - eventBus.register(this); - - mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() { - @Override - public boolean onError(MediaPlayer mediaPlayer, int i, int i2) { - isPreparing = false; - Toast.makeText(PodcastPlaybackService.this, "Failed to open podcast", Toast.LENGTH_LONG).show(); - return false; - } - }); - - mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { - @Override - public void onPrepared(MediaPlayer mediaPlayer) { - play(); - isPreparing = false; - canCallGetDuration = true; - } - }); - - mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { - @Override - public void onCompletion(MediaPlayer mediaPlayer) { - pause();//Send the over signal - podcastCompleted(); - } - }); - - eventBus.post(new PodcastPlaybackServiceStarted()); mHandler.postDelayed(mUpdateTimeTask, 0); @@ -166,118 +127,51 @@ public class PodcastPlaybackService extends Service implements TextToSpeech.OnIn @Override public int onStartCommand(Intent intent, int flags, int startId) { if (intent != null) { - if (intent.hasExtra(PODCAST_ITEM)) { - openFile((PodcastItem) intent.getSerializableExtra(PODCAST_ITEM)); - } else if(intent.hasExtra(TTS_ITEM)) { - openTtsFeed((TTSItem) intent.getSerializableExtra(TTS_ITEM)); + if(mPlaybackService != null) { + mPlaybackService.destroy(); + mPlaybackService = null; } - } - - return Service.START_STICKY; - } - - - public static final int delay = 500; //In milliseconds - - private boolean canCallGetDuration = false;//Otherwise the player would call getDuration all the time without loading a media file - private boolean isPreparing = false; - private boolean isVideoFile = false; - - public void openTtsFeed(TTSItem textToSpeechItem) { - this.mCurrentlyPlayingTTS = textToSpeechItem; - this.mCurrentlyPlayingPodcast = null; - this.mPlaybackType = PlaybackType.TTS; - this.isVideoFile = false; + MediaItem mediaItem = (MediaItem) intent.getSerializableExtra(MEDIA_ITEM); - try { - if(mMediaPlayer.isPlaying()) - pause(); - - this.mediaTitle = textToSpeechItem.title; - - isPreparing = true; - mHandler.postDelayed(mUpdateTimeTask, 0); - - if(ttsController == null) { - ttsController = new TextToSpeech(this, this); - ttsController.setOnUtteranceProgressListener(new UtteranceProgressListener() { - @Override - public void onDone(String utteranceId) { - podcastCompleted(); - } - - @Override public void onStart(String utteranceId) {} - @Override public void onError(String utteranceId) {} - }); + 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); } - else - onInit(TextToSpeech.SUCCESS); - } catch (Exception e) { - e.printStackTrace(); - } - } - private void podcastCompleted() { - Log.d(TAG, "Podcast completed, cleaning up"); - mHandler.removeCallbacks(mUpdateTimeTask); - podcastNotification.cancel(); - mCurrentlyPlayingPodcast = null; - mCurrentlyPlayingTTS = null; + sendMediaStatus(); + podcastNotification.podcastChanged(); + } - EventBus.getDefault().post(new PodcastCompletedEvent()); + return Service.START_STICKY; } - @Override - public void onInit(int status) { - if (status == TextToSpeech.SUCCESS) { - /* - int result = ttsController.setLanguage(Locale.US); - - if (result == TextToSpeech.LANG_MISSING_DATA - || result == TextToSpeech.LANG_NOT_SUPPORTED) { - Log.e("TTS", "This Language is not supported"); - } else { - ttsController.speak(text, TextToSpeech.QUEUE_FLUSH, null); - }*/ - - HashMap<String,String> ttsParams = new HashMap<>(); - ttsParams.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID,"dummyId"); - ttsController.speak(mCurrentlyPlayingTTS.text, TextToSpeech.QUEUE_FLUSH, ttsParams); - - isPreparing = false; - - } else { - Log.e("TTS", "Initilization Failed!"); - ttsController = null; + private PlaybackService.PodcastStatusListener podcastStatusListener = new PlaybackService.PodcastStatusListener() { + @Override + public void podcastStatusUpdated() { + sendMediaStatus(); } - } - - public void openFile(PodcastItem podcastItem) { - this.mPlaybackType = PlaybackType.PODCAST; - this.mCurrentlyPlayingPodcast = podcastItem; - this.mCurrentlyPlayingTTS = null; - - this.isVideoFile = podcastItem.isVideoPodcast; - try { - if(mMediaPlayer.isPlaying()) - pause(); - this.mediaTitle = podcastItem.title; + @Override + public void podcastCompleted() { + Log.d(TAG, "Podcast completed, cleaning up"); + mHandler.removeCallbacks(mUpdateTimeTask); + podcastNotification.cancel(); - isPreparing = true; - mHandler.postDelayed(mUpdateTimeTask, 0); + mPlaybackService.destroy(); + mPlaybackService = null; - mMediaPlayer.reset(); - mMediaPlayer.setDataSource(podcastItem.link); - mMediaPlayer.prepareAsync(); - } catch (IOException e) { - e.printStackTrace(); - isPreparing = false; + EventBus.getDefault().post(new PodcastCompletedEvent()); } + }; + + public static final int delay = 500; //In milliseconds - podcastNotification.podcastChanged(); - } /** * Background Runnable thread @@ -302,45 +196,30 @@ public class PodcastPlaybackService extends Service implements TextToSpeech.OnIn } private boolean isPlaying() { - return (mPlaybackType == PlaybackType.PODCAST && mMediaPlayer.isPlaying()) || //If podcast is running - mPlaybackType == PlaybackType.TTS && ttsController.isSpeaking(); // or if tts is running + return (mPlaybackService != null && mPlaybackService.getStatus() == PlaybackService.Status.PLAYING); } @Subscribe public void onEvent(WindPodcast event) { - if(mMediaPlayer != null) { - double totalDuration = mMediaPlayer.getDuration(); - int position = (int)((totalDuration / 100d) * event.toPositionInPercent); - mMediaPlayer.seekTo(position); + if(mPlaybackService != null) { + mPlaybackService.seekTo(event.toPositionInPercent); } } - /* - public void onEventBackgroundThread(OpenPodcastEvent event) { - this.isVideoFile = event.isVideoFile; - openFile(event.pathToFile, event.mediaTitle); - } - */ - @Subscribe public void onEvent(RegisterVideoOutput videoOutput) { - if(mMediaPlayer != null) { - if(videoOutput.surfaceView == null) { - mMediaPlayer.setDisplay(null); - Log.d(TAG, "Disable Screen output!"); + if(mPlaybackService != null && mPlaybackService instanceof MediaPlayerPlaybackService) { + ((MediaPlayerPlaybackService) mPlaybackService).setVideoView(videoOutput.surfaceView, videoOutput.parentResizableView); + } + } - mMediaPlayer.setScreenOnWhilePlaying(false); + @Subscribe + public void onEvent(RegisterYoutubeOutput videoOutput) { + if(mPlaybackService != null && mPlaybackService instanceof YoutubePlaybackService) { + if(videoOutput.youTubePlayer == null) { + mPlaybackService.destroy(); } else { - if(videoOutput.surfaceView.getHolder() != mSurfaceHolder) { - parentResizableView = videoOutput.parentResizableView; - - videoOutput.surfaceView.getHolder().addCallback(mSHCallback); - //videoOutput.surfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); //holder.setType(SurfaceHolder.SURFACE_TYPE_GPU); - - populateVideo(); - - Log.d(TAG, "Enable Screen output!"); - } + ((YoutubePlaybackService) mPlaybackService).setYoutubePlayer(videoOutput.youTubePlayer, videoOutput.wasRestored); } } } @@ -351,59 +230,18 @@ public class PodcastPlaybackService extends Service implements TextToSpeech.OnIn } - - public void play() { - if(mPlaybackType == PlaybackType.PODCAST) { - try { - int progress = mMediaPlayer.getCurrentPosition() / mMediaPlayer.getDuration(); - if (progress >= 1) { - mMediaPlayer.seekTo(0); - } - } catch (Exception ex) { - ex.printStackTrace(); - } - - mMediaPlayer.start(); - } else { - onInit(TextToSpeech.SUCCESS);//restart last tts + if(mPlaybackService != null) { + mPlaybackService.play(); } mHandler.removeCallbacks(mUpdateTimeTask); mHandler.postDelayed(mUpdateTimeTask, 0); - - populateVideo(); - } - - private void populateVideo() { - double videoHeightRel = (double) mSurfaceWidth / (double) mMediaPlayer.getVideoWidth(); - int videoHeight = (int) (mMediaPlayer.getVideoHeight() * videoHeightRel); - - if (mSurfaceWidth != 0 && videoHeight != 0 && mSurfaceHolder != null) { - //mSurfaceHolder.setFixedSize(mSurfaceWidth, videoHeight); - - parentResizableView.getLayoutParams().height = videoHeight; - parentResizableView.setLayoutParams(parentResizableView.getLayoutParams()); - } } public void pause() { - if(mPlaybackType == PlaybackType.PODCAST) { - if (mMediaPlayer.isPlaying()) - mMediaPlayer.pause(); - } - - if(mPlaybackType == PlaybackType.TTS) { - if (ttsController.isSpeaking()) { - ttsController.stop(); - - //The tts service needs a few ms's to end playing. So wait 100ms - try { - Thread.sleep(100); - } catch (Exception ex) { - ex.printStackTrace(); - } - } + if(mPlaybackService != null) { + mPlaybackService.pause(); } mHandler.removeCallbacks(mUpdateTimeTask); @@ -411,25 +249,20 @@ public class PodcastPlaybackService extends Service implements TextToSpeech.OnIn } public void sendMediaStatus() { - long totalDuration = 0; - long currentDuration = 0; - - if(mPlaybackType == PlaybackType.PODCAST) { - if (!isPreparing && canCallGetDuration) { - totalDuration = mMediaPlayer.getDuration(); - currentDuration = mMediaPlayer.getCurrentPosition(); - } - - long currentRssItemId = -1; - if (mCurrentlyPlayingPodcast != null) - currentRssItemId = mCurrentlyPlayingPodcast.itemId; + UpdatePodcastStatusEvent audioPodcastEvent; - UpdatePodcastStatusEvent audioPodcastEvent = new UpdatePodcastStatusEvent(currentDuration, totalDuration, mMediaPlayer.isPlaying(), mediaTitle, isPreparing, canCallGetDuration, isVideoFile, currentRssItemId); - eventBus.post(audioPodcastEvent); - } else if(mPlaybackType == PlaybackType.TTS) { - UpdatePodcastStatusEvent audioPodcastEvent = new UpdatePodcastStatusEvent(0, 0, ttsController.isSpeaking(), mediaTitle, isPreparing, true, false, mCurrentlyPlayingTTS.itemId); - eventBus.post(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); } @@ -451,34 +284,4 @@ public class PodcastPlaybackService extends Service implements TextToSpeech.OnIn super.onCallStateChanged(state, incomingNumber); } }; - - - - - int mSurfaceWidth; - int mSurfaceHeight; - SurfaceHolder mSurfaceHolder; - SurfaceHolder.Callback mSHCallback = new SurfaceHolder.Callback() - { - public void surfaceChanged(SurfaceHolder holder, int format, int surfaceWidth, int surfaceHeight) - { - mSurfaceWidth = surfaceWidth; - mSurfaceHeight = surfaceHeight; - } - - public void surfaceCreated(SurfaceHolder holder) - { - mSurfaceHolder = holder; - mMediaPlayer.setDisplay(mSurfaceHolder); - - mMediaPlayer.setScreenOnWhilePlaying(true); - - Log.d(TAG, "surfaceCreated"); - } - - public void surfaceDestroyed(SurfaceHolder holder) - { - Log.d(TAG, "surfaceDestroyed"); - } - }; } diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/services/podcast/MediaPlayerPlaybackService.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/services/podcast/MediaPlayerPlaybackService.java new file mode 100644 index 00000000..63c3a46e --- /dev/null +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/services/podcast/MediaPlayerPlaybackService.java @@ -0,0 +1,185 @@ +package de.luhmer.owncloudnewsreader.services.podcast; + +import android.content.Context; +import android.media.MediaPlayer; +import android.util.Log; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.View; +import android.widget.Toast; + +import java.io.IOException; + +import de.luhmer.owncloudnewsreader.model.MediaItem; +import de.luhmer.owncloudnewsreader.model.PodcastItem; + +/** + * Created by david on 31.01.17. + */ + +public class MediaPlayerPlaybackService extends PlaybackService { + private static final String TAG = MediaPlayerPlaybackService.class.getCanonicalName(); + private MediaPlayer mMediaPlayer; + private View parentResizableView; + + public MediaPlayerPlaybackService(final Context context, PodcastStatusListener podcastStatusListener, MediaItem mediaItem) { + super(context, podcastStatusListener, mediaItem); + + mMediaPlayer = new MediaPlayer(); + mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() { + @Override + public boolean onError(MediaPlayer mediaPlayer, int i, int i2) { + setStatus(Status.FAILED); + Toast.makeText(context, "Failed to open podcast", Toast.LENGTH_LONG).show(); + return false; + } + }); + + mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { + @Override + public void onPrepared(MediaPlayer mediaPlayer) { + setStatus(Status.PAUSED); + play(); + } + }); + + mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mediaPlayer) { + pause();//Send the over signal + podcastCompleted(); + } + }); + + + try { + setStatus(Status.PREPARING); + + mMediaPlayer.setDataSource(((PodcastItem) mediaItem).link); + mMediaPlayer.prepareAsync(); + } catch (IOException e) { + e.printStackTrace(); + setStatus(Status.FAILED); + } + } + + @Override + public void destroy() { + mMediaPlayer.stop(); + mMediaPlayer.reset(); + mMediaPlayer.release(); + } + + @Override + public void play() { + try { + int progress = mMediaPlayer.getCurrentPosition() / mMediaPlayer.getDuration(); + if (progress >= 1) { + mMediaPlayer.seekTo(0); + } + setStatus(Status.PLAYING); + } catch (Exception ex) { + ex.printStackTrace(); + } + + mMediaPlayer.start(); + + populateVideo(); + } + + @Override + public void pause() { + if (mMediaPlayer.isPlaying()) { + mMediaPlayer.pause(); + } + setStatus(Status.PAUSED); + } + + @Override + public void seekTo(double percent) { + double totalDuration = mMediaPlayer.getDuration(); + int position = (int) ((totalDuration / 100d) * percent); + mMediaPlayer.seekTo(position); + } + + @Override + public int getCurrentDuration() { + if (mMediaPlayer != null && isMediaLoaded()) { + return mMediaPlayer.getCurrentPosition(); + } + return 0; + } + + @Override + public int getTotalDuration() { + if (mMediaPlayer != null && isMediaLoaded()) { + return mMediaPlayer.getDuration(); + } + return 0; + } + + @Override + public VideoType getVideoType() { + return ((PodcastItem) getMediaItem()).isVideoPodcast ? VideoType.Video : VideoType.None; + } + + + private void populateVideo() { + double videoHeightRel = (double) mSurfaceWidth / (double) mMediaPlayer.getVideoWidth(); + int videoHeight = (int) (mMediaPlayer.getVideoHeight() * videoHeightRel); + + if (mSurfaceWidth != 0 && videoHeight != 0 && mSurfaceHolder != null) { + //mSurfaceHolder.setFixedSize(mSurfaceWidth, videoHeight); + + parentResizableView.getLayoutParams().height = videoHeight; + parentResizableView.setLayoutParams(parentResizableView.getLayoutParams()); + } + } + + public void setVideoView(SurfaceView surfaceView, View parentResizableView) { + if (surfaceView == null) { + mMediaPlayer.setDisplay(null); + Log.d(TAG, "Disable Screen output!"); + + mMediaPlayer.setScreenOnWhilePlaying(false); + } else { + if (surfaceView.getHolder() != mSurfaceHolder) { + this.parentResizableView = parentResizableView; + + surfaceView.getHolder().addCallback(mSHCallback); + //videoOutput.surfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); //holder.setType(SurfaceHolder.SURFACE_TYPE_GPU); + + populateVideo(); + + Log.d(TAG, "Enable Screen output!"); + } + } + } + + + private int mSurfaceWidth; + private int mSurfaceHeight; + private SurfaceHolder mSurfaceHolder; + SurfaceHolder.Callback mSHCallback = new SurfaceHolder.Callback() + { + public void surfaceChanged(SurfaceHolder holder, int format, int surfaceWidth, int surfaceHeight) + { + mSurfaceWidth = surfaceWidth; + mSurfaceHeight = surfaceHeight; + } + + public void surfaceCreated(SurfaceHolder holder) + { + mSurfaceHolder = holder; + mMediaPlayer.setDisplay(mSurfaceHolder); //TODO required + mMediaPlayer.setScreenOnWhilePlaying(true); //TODO required + + Log.d(TAG, "surfaceCreated"); + } + + public void surfaceDestroyed(SurfaceHolder holder) + { + Log.d(TAG, "surfaceDestroyed"); + } + }; +} diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/services/podcast/PlaybackService.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/services/podcast/PlaybackService.java new file mode 100644 index 00000000..15fdc19f --- /dev/null +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/services/podcast/PlaybackService.java @@ -0,0 +1,63 @@ +package de.luhmer.owncloudnewsreader.services.podcast; + +import android.content.Context; + +import de.luhmer.owncloudnewsreader.model.MediaItem; + +/** + * Created by david on 31.01.17. + */ + +public abstract class PlaybackService { + + public interface PodcastStatusListener { + void podcastStatusUpdated(); + void podcastCompleted(); + } + + public enum Status { NOT_INITIALIZED, FAILED, PREPARING, PLAYING, PAUSED, STOPPED }; + public enum VideoType { None, Video, VideoType, YouTube } + + private Status mStatus = Status.NOT_INITIALIZED; + private PodcastStatusListener podcastStatusListener; + private MediaItem mediaItem; + + public PlaybackService(Context context, PodcastStatusListener podcastStatusListener, MediaItem mediaItem) { + this.podcastStatusListener = podcastStatusListener; + this.mediaItem = mediaItem; + } + + public abstract void destroy(); + public abstract void play(); + public abstract void pause(); + + + public void seekTo(double percent) { } + public int getCurrentDuration() { return 0; } + public int getTotalDuration() { return 0; } + public VideoType getVideoType() { return VideoType.None; } + + public MediaItem getMediaItem() { + return mediaItem; + } + + public Status getStatus() { + return mStatus; + } + + protected void setStatus(Status status) { + this.mStatus = status; + podcastStatusListener.podcastStatusUpdated(); + } + + protected void podcastCompleted() { + podcastStatusListener.podcastCompleted(); + } + + public boolean isMediaLoaded() { + return getStatus() != Status.NOT_INITIALIZED + && getStatus() != Status.PREPARING + && getStatus() != Status.FAILED; + } + +} diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/services/podcast/TTSPlaybackService.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/services/podcast/TTSPlaybackService.java new file mode 100644 index 00000000..430109f6 --- /dev/null +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/services/podcast/TTSPlaybackService.java @@ -0,0 +1,89 @@ +package de.luhmer.owncloudnewsreader.services.podcast; + +import android.content.Context; +import android.speech.tts.TextToSpeech; +import android.speech.tts.UtteranceProgressListener; +import android.util.Log; + +import java.util.HashMap; + +import de.luhmer.owncloudnewsreader.model.MediaItem; +import de.luhmer.owncloudnewsreader.model.TTSItem; + +/** + * Created by david on 31.01.17. + */ + +public class TTSPlaybackService extends PlaybackService implements TextToSpeech.OnInitListener { + private TextToSpeech ttsController; + + public TTSPlaybackService(Context context, PodcastStatusListener podcastStatusListener, MediaItem mediaItem) { + super(context, podcastStatusListener, mediaItem); + + try { + ttsController = new TextToSpeech(context, this); + setStatus(Status.PREPARING); + + if(ttsController == null) { + + ttsController.setOnUtteranceProgressListener(new UtteranceProgressListener() { + @Override + public void onDone(String utteranceId) { + podcastCompleted(); + } + + @Override public void onStart(String utteranceId) {} + @Override public void onError(String utteranceId) {} + }); + } + else + onInit(TextToSpeech.SUCCESS); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void destroy() { + pause(); + ttsController.shutdown(); + ttsController = null; + } + + @Override + public void play() { + onInit(TextToSpeech.SUCCESS);//restart last tts + } + + @Override + public void pause() { + if (ttsController.isSpeaking()) { + ttsController.stop(); + setStatus(Status.PAUSED); + } + } + + @Override + public void onInit(int status) { + if (status == TextToSpeech.SUCCESS) { + /* + int result = ttsController.setLanguage(Locale.US); + + if (result == TextToSpeech.LANG_MISSING_DATA + || result == TextToSpeech.LANG_NOT_SUPPORTED) { + Log.e("TTS", "This Language is not supported"); + } else { + ttsController.speak(text, TextToSpeech.QUEUE_FLUSH, null); + }*/ + + HashMap<String,String> ttsParams = new HashMap<>(); + ttsParams.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID,"dummyId"); + ttsController.speak(((TTSItem)getMediaItem()).text, TextToSpeech.QUEUE_FLUSH, ttsParams); + setStatus(Status.PLAYING); + } else { + Log.e("TTS", "Initilization Failed!"); + ttsController = null; + } + } + +} diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/services/podcast/YoutubePlaybackService.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/services/podcast/YoutubePlaybackService.java new file mode 100644 index 00000000..29e3c87f --- /dev/null +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/services/podcast/YoutubePlaybackService.java @@ -0,0 +1,163 @@ +package de.luhmer.owncloudnewsreader.services.podcast; + +import android.content.Context; +import android.util.Log; +import android.widget.Toast; + +import com.google.android.youtube.player.YouTubePlayer; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import de.luhmer.owncloudnewsreader.model.MediaItem; + +/** + * Created by david on 31.01.17. + */ + +public class YoutubePlaybackService extends PlaybackService { + + private static final String TAG = YoutubePlaybackService.class.getCanonicalName(); + YouTubePlayer youTubePlayer; + Context context; + + public YoutubePlaybackService(Context context, PodcastStatusListener podcastStatusListener, MediaItem mediaItem) { + super(context, podcastStatusListener, mediaItem); + this.context = context; + setStatus(Status.PREPARING); + } + + @Override + public void destroy() { + if(youTubePlayer != null) { + youTubePlayer.pause(); + youTubePlayer = null; + } + } + + @Override + public void play() { + if(youTubePlayer != null) { + youTubePlayer.play(); + } + } + + @Override + public void pause() { + if(youTubePlayer != null) { + youTubePlayer.pause(); + } + } + + public void seekTo(double percent) { + if(youTubePlayer != null) { + double totalDuration = getTotalDuration(); + int position = (int) ((totalDuration / 100d) * percent); + youTubePlayer.seekToMillis(position); + } + } + public int getCurrentDuration() { + if(youTubePlayer != null) { + return youTubePlayer.getCurrentTimeMillis(); + } + return 0; + } + + public int getTotalDuration() { + if(youTubePlayer != null) { + return youTubePlayer.getDurationMillis(); + } + return 0; + } + + @Override + public VideoType getVideoType() { + return VideoType.YouTube; + } + + public void setYoutubePlayer(YouTubePlayer youTubePlayer, boolean wasRestored) { + this.youTubePlayer = youTubePlayer; + youTubePlayer.setPlaybackEventListener(youtubePlaybackEventListener); + youTubePlayer.setPlayerStateChangeListener(youtubePlayerStateChangeListener); + + youTubePlayer.setPlayerStyle(YouTubePlayer.PlayerStyle.MINIMAL); + + // Start buffering + if (!wasRestored) { + Pattern youtubeIdPattern = Pattern.compile(".*?v=([^&]*)"); + Matcher matcher = youtubeIdPattern.matcher(getMediaItem().link); + if(matcher.matches()) { + String youtubeId = matcher.group(1); + youTubePlayer.cueVideo(youtubeId); + } else { + Toast.makeText(context, "Cannot find youtube video id", Toast.LENGTH_LONG).show(); + setStatus(Status.FAILED); + } + } + } + + + YouTubePlayer.PlayerStateChangeListener youtubePlayerStateChangeListener = new YouTubePlayer.PlayerStateChangeListener() { + @Override + public void onLoading() { + Log.d(TAG, "onLoading() called"); + } + + @Override + public void onLoaded(String s) { + Log.d(TAG, "onLoaded() called with: s = [" + s + "]"); + youTubePlayer.play(); + } + + @Override + public void onAdStarted() { + Log.d(TAG, "onAdStarted() called"); + } + + @Override + public void onVideoStarted() { + Log.d(TAG, "onVideoStarted() called"); + } + + @Override + public void onVideoEnded() { + Log.d(TAG, "onVideoEnded() called"); + } + + @Override + public void onError(YouTubePlayer.ErrorReason errorReason) { + Log.d(TAG, "onError() called with: errorReason = [" + errorReason + "]"); + } + }; + + + YouTubePlayer.PlaybackEventListener youtubePlaybackEventListener = new YouTubePlayer.PlaybackEventListener() { + @Override + public void onPlaying() { + Log.d(TAG, "onPlaying() called"); + setStatus(Status.PLAYING); + } + + @Override + public void onPaused() { + Log.d(TAG, "onPaused() called"); + setStatus(Status.PAUSED); + } + + @Override + public void onStopped() { + Log.d(TAG, "onStopped() called"); + setStatus(Status.PAUSED); + } + + @Override + public void onBuffering(boolean b) { + Log.d(TAG, "onBuffering() called with: b = [" + b + "]"); + } + + @Override + public void onSeekTo(int i) { + Log.d(TAG, "onSeekTo() called with: i = [" + i + "]"); + } + }; +} |