diff options
Diffstat (limited to 'News-Android-App/src/main/java/de/luhmer/owncloudnewsreader')
14 files changed, 715 insertions, 354 deletions
diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/Constants.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/Constants.java index 334bb935..15e7350a 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/Constants.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/Constants.java @@ -1,9 +1,7 @@ package de.luhmer.owncloudnewsreader; -import android.content.ContentProvider; import android.content.Context; import android.content.SharedPreferences; -import android.icu.text.DateFormat; import android.preference.PreferenceManager; import de.luhmer.owncloudnewsreader.reader.owncloud.API; diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/PodcastFragment.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/PodcastFragment.java index a0dec78b..cdd76750 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/PodcastFragment.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/PodcastFragment.java @@ -39,9 +39,11 @@ import de.luhmer.owncloudnewsreader.events.podcast.StartDownloadPodcast; 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.PodcastFeedItem; import de.luhmer.owncloudnewsreader.model.PodcastItem; import de.luhmer.owncloudnewsreader.services.PodcastDownloadService; +import de.luhmer.owncloudnewsreader.services.podcast.PlaybackService; import de.luhmer.owncloudnewsreader.view.PodcastSlidingUpPanelLayout; @@ -179,7 +181,7 @@ public class PodcastFragment extends Fragment { tvTitle.setText(podcast.getTitle()); tvTitleSlider.setText(podcast.getTitle()); - if(podcast.isPreparingFile()) { + if(podcast.getStatus() == PlaybackService.Status.PREPARING) { sb_progress.setVisibility(View.INVISIBLE); pb_progress2.setVisibility(View.VISIBLE); @@ -199,7 +201,7 @@ public class PodcastFragment extends Fragment { } private boolean loadPodcastFavIcon() { - PodcastItem podcastItem = ((PodcastFragmentActivity) getActivity()).getCurrentPlayingPodcast(); + MediaItem podcastItem = ((PodcastFragmentActivity) getActivity()).getCurrentPlayingPodcast(); if(podcastItem != null) { String favIconUrl = podcastItem.favIcon; DisplayImageOptions displayImageOptions = new DisplayImageOptions.Builder(). diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/PodcastFragmentActivity.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/PodcastFragmentActivity.java index ea7b721e..3a9698d1 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/PodcastFragmentActivity.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/PodcastFragmentActivity.java @@ -3,6 +3,7 @@ package de.luhmer.owncloudnewsreader; import android.animation.Animator; import android.app.ActivityManager; import android.app.AlertDialog; +import android.app.FragmentTransaction; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; @@ -21,9 +22,13 @@ import android.view.SurfaceView; import android.view.View; import android.view.ViewTreeObserver; import android.view.animation.Animation; +import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.Toast; +import com.google.android.youtube.player.YouTubeInitializationResult; +import com.google.android.youtube.player.YouTubePlayer; +import com.google.android.youtube.player.YouTubePlayerFragment; import com.sothree.slidinguppanel.SlidingUpPanelLayout; import org.greenrobot.eventbus.EventBus; @@ -37,15 +42,17 @@ import de.luhmer.owncloudnewsreader.database.DatabaseConnectionOrm; import de.luhmer.owncloudnewsreader.database.model.RssItem; 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.UpdatePodcastStatusEvent; +import de.luhmer.owncloudnewsreader.events.podcast.VideoDoubleClicked; import de.luhmer.owncloudnewsreader.helper.SizeAnimator; import de.luhmer.owncloudnewsreader.helper.TeslaUnreadManager; import de.luhmer.owncloudnewsreader.interfaces.IPlayPausePodcastClicked; import de.luhmer.owncloudnewsreader.model.MediaItem; import de.luhmer.owncloudnewsreader.model.PodcastItem; -import de.luhmer.owncloudnewsreader.model.TTSItem; import de.luhmer.owncloudnewsreader.services.PodcastDownloadService; import de.luhmer.owncloudnewsreader.services.PodcastPlaybackService; +import de.luhmer.owncloudnewsreader.services.podcast.PlaybackService; import de.luhmer.owncloudnewsreader.view.PodcastSlidingUpPanelLayout; import de.luhmer.owncloudnewsreader.view.ZoomableRelativeLayout; import de.luhmer.owncloudnewsreader.widget.WidgetProvider; @@ -63,6 +70,7 @@ public class PodcastFragmentActivity extends AppCompatActivity implements IPlayP @Bind(R.id.videoPodcastSurfaceWrapper) ZoomableRelativeLayout rlVideoPodcastSurfaceWrapper; @Bind(R.id.sliding_layout) PodcastSlidingUpPanelLayout sliding_layout; + //YouTubePlayerFragment youtubeplayerfragment; @Override @@ -71,6 +79,9 @@ public class PodcastFragmentActivity extends AppCompatActivity implements IPlayP ButterKnife.bind(this); + //youtubeplayerfragment = (YouTubePlayerFragment)getFragmentManager().findFragmentById(R.id.youtubeplayerfragment); + + ViewTreeObserver vto = rlVideoPodcastSurfaceWrapper.getViewTreeObserver(); vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override @@ -144,7 +155,18 @@ public class PodcastFragmentActivity extends AppCompatActivity implements IPlayP protected void onPause() { Log.d(TAG, "onPause"); eventBus.unregister(this); + + + //TODO THIS IS NEVER REACHED! + isVideoViewVisible = false; + videoViewInitialized = false; + eventBus.post(new RegisterVideoOutput(null, null)); + eventBus.post(new RegisterYoutubeOutput(null, false)); + + rlVideoPodcastSurfaceWrapper.setVisibility(View.GONE); + rlVideoPodcastSurfaceWrapper.removeAllViews(); + TeslaUnreadManager.PublishUnreadCount(this); WidgetProvider.UpdateWidget(this); @@ -181,7 +203,7 @@ public class PodcastFragmentActivity extends AppCompatActivity implements IPlayP } }; - public PodcastItem getCurrentPlayingPodcast() { + public MediaItem getCurrentPlayingPodcast() { if(mPodcastPlaybackService != null) return mPodcastPlaybackService.getCurrentlyPlayingPodcast(); return null; @@ -217,26 +239,38 @@ public class PodcastFragmentActivity extends AppCompatActivity implements IPlayP boolean currentlyPlaying = false; - boolean surfaceInitialized = false; + boolean videoViewInitialized = false; boolean isVideoViewVisible = true; @Subscribe public void onEvent(UpdatePodcastStatusEvent podcast) { + boolean playStateChanged = currentlyPlaying; //If file is loaded or preparing and podcast is paused/not running expand the view - if((podcast.isFileLoaded() || podcast.isPreparingFile()) && !currentlyPlaying) { + currentlyPlaying = podcast.getStatus() == PlaybackService.Status.PLAYING + || podcast.getStatus() == PlaybackService.Status.PAUSED; + + //Check if state was changed + playStateChanged = playStateChanged != currentlyPlaying; + + // If preparing or state changed and is now playing or paused + if(podcast.getStatus() == PlaybackService.Status.PREPARING + || (playStateChanged + && (podcast.getStatus() == PlaybackService.Status.PLAYING + || podcast.getStatus() == PlaybackService.Status.PAUSED + || podcast.getStatus() == PlaybackService.Status.STOPPED))) { //Expand view sliding_layout.setPanelHeight((int) dipToPx(68)); - currentlyPlaying = true; Log.v(TAG, "expanding podcast view!"); - } else if(!(podcast.isPreparingFile() || podcast.isFileLoaded()) && currentlyPlaying) { //If file is not loaded or podcast is not preparing file and is playing + } else if(playStateChanged) { //Hide view sliding_layout.setPanelHeight(0); currentlyPlaying = false; Log.v(TAG, "collapsing podcast view!"); } - if (podcast.isVideoFile()) { - if((!isVideoViewVisible || !surfaceInitialized) && rlVideoPodcastSurfaceWrapper.isPositionReady()) { - surfaceInitialized = true; + if (podcast.isVideoFile() && podcast.getVideoType() == PlaybackService.VideoType.Video) { + if ((!isVideoViewVisible || !videoViewInitialized) && rlVideoPodcastSurfaceWrapper.isPositionReady()) { + rlVideoPodcastSurfaceWrapper.removeAllViews(); + videoViewInitialized = true; isVideoViewVisible = true; rlVideoPodcastSurfaceWrapper.setVisibility(View.VISIBLE); @@ -252,10 +286,46 @@ public class PodcastFragmentActivity extends AppCompatActivity implements IPlayP eventBus.post(new RegisterVideoOutput(surfaceView, rlVideoPodcastSurfaceWrapper)); togglePodcastVideoViewAnimation(); } - } else if(isVideoViewVisible) { + } else if(podcast.getVideoType() == PlaybackService.VideoType.YouTube){ + if(!videoViewInitialized) { + isVideoViewVisible = true; + videoViewInitialized = true; + rlVideoPodcastSurfaceWrapper.removeAllViews(); + + rlVideoPodcastSurfaceWrapper.setVisibility(View.VISIBLE); + + togglePodcastVideoViewAnimation(); + + final int YOUTUBE_CONTENT_VIEW_ID = 10101010; + FrameLayout frame = new FrameLayout(this); + frame.setId(YOUTUBE_CONTENT_VIEW_ID); + rlVideoPodcastSurfaceWrapper.addView(frame); + //setContentView(frame, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)); + + + + YouTubePlayerFragment youTubePlayerFragment = YouTubePlayerFragment.newInstance(); + FragmentTransaction ft = getFragmentManager().beginTransaction(); + ft.add(YOUTUBE_CONTENT_VIEW_ID, youTubePlayerFragment).commit(); + youTubePlayerFragment.initialize("AIzaSyA2OHKWvF_hRVtPmLcwnO8yF6-iah2hjbk", new YouTubePlayer.OnInitializedListener() { + @Override + public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer youTubePlayer, boolean wasRestored) { + eventBus.post(new RegisterYoutubeOutput(youTubePlayer, wasRestored)); + togglePodcastVideoViewAnimation(); + } + + @Override + public void onInitializationFailure(YouTubePlayer.Provider provider, YouTubeInitializationResult youTubeInitializationResult) { + Toast.makeText(PodcastFragmentActivity.this, "Error while playing youtube video! (InitializationFailure)", Toast.LENGTH_LONG).show(); + } + }); + } + } else { isVideoViewVisible = false; + videoViewInitialized = false; eventBus.post(new RegisterVideoOutput(null, null)); + eventBus.post(new RegisterYoutubeOutput(null, false)); rlVideoPodcastSurfaceWrapper.setVisibility(View.GONE); //AlphaAnimator.AnimateVisibilityChange(rlVideoPodcastSurfaceWrapper, View.GONE); @@ -272,34 +342,7 @@ public class PodcastFragmentActivity extends AppCompatActivity implements IPlayP currentlyPlaying = false; } - /* - // This snippet hides the system bars. - @TargetApi(Build.VERSION_CODES.HONEYCOMB) - private void hideSystemUI() { - // Set the IMMERSIVE flag. - // Set the content to appear under the system bars so that the content - // doesn't resize when the system bars hide and show. - getWindow().getDecorView().setSystemUiVisibility( - View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar - //| View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar - | View.SYSTEM_UI_FLAG_IMMERSIVE - ); - } - // This snippet shows the system bars. It does this by removing all the flags - // except for the ones that make the content appear under the system bars. - @TargetApi(Build.VERSION_CODES.HONEYCOMB) - private void showSystemUI() { - getWindow().getDecorView().setSystemUiVisibility( - View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - ); - } - */ private static final int animationTime = 300; //Milliseconds float oldScaleFactor = 1; @@ -308,7 +351,7 @@ public class PodcastFragmentActivity extends AppCompatActivity implements IPlayP boolean useAnimation = false; @Subscribe - public void onEvent() { + public void onEvent(VideoDoubleClicked videoDoubleClicked) { appHeight = getWindow().getDecorView().findViewById(android.R.id.content).getHeight(); appWidth = getWindow().getDecorView().findViewById(android.R.id.content).getWidth(); @@ -489,14 +532,10 @@ public class PodcastFragmentActivity extends AppCompatActivity implements IPlayP } @VisibleForTesting - public void openMediaItem(MediaItem mediaItem) { + public void openMediaItem(final MediaItem mediaItem) { Intent intent = new Intent(this, PodcastPlaybackService.class); - if(mediaItem instanceof TTSItem) - intent.putExtra(PodcastPlaybackService.TTS_ITEM, mediaItem); - else - intent.putExtra(PodcastPlaybackService.PODCAST_ITEM, mediaItem); + intent.putExtra(PodcastPlaybackService.MEDIA_ITEM, mediaItem); startService(intent); - bindService(intent, mConnection, Context.BIND_AUTO_CREATE); } @@ -525,14 +564,13 @@ public class PodcastFragmentActivity extends AppCompatActivity implements IPlayP .setMessage("Choose if you want to download or stream the selected podcast"); - if(!podcastItem.mimeType.equals("youtube")) { - alertDialog.setPositiveButton("Stream", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - openMediaItem(podcastItem); - } - }); - } + + alertDialog.setPositiveButton("Stream", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + openMediaItem(podcastItem); + } + }); alertDialog.show(); } diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/events/podcast/RegisterYoutubeOutput.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/events/podcast/RegisterYoutubeOutput.java new file mode 100644 index 00000000..ffe3a2fa --- /dev/null +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/events/podcast/RegisterYoutubeOutput.java @@ -0,0 +1,15 @@ +package de.luhmer.owncloudnewsreader.events.podcast; + +import com.google.android.youtube.player.YouTubePlayer; + +public class RegisterYoutubeOutput { + + public RegisterYoutubeOutput(YouTubePlayer youTubePlayer, boolean wasRestored) { + this.youTubePlayer = youTubePlayer; + this.wasRestored = wasRestored; + } + + public YouTubePlayer youTubePlayer; + public boolean wasRestored; + +} diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/events/podcast/UpdatePodcastStatusEvent.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/events/podcast/UpdatePodcastStatusEvent.java index 0bc2ea21..066c0085 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/events/podcast/UpdatePodcastStatusEvent.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/events/podcast/UpdatePodcastStatusEvent.java @@ -1,14 +1,14 @@ package de.luhmer.owncloudnewsreader.events.podcast; +import de.luhmer.owncloudnewsreader.services.podcast.PlaybackService; + public class UpdatePodcastStatusEvent { private long current; private long max; private String title; - private boolean playing; - private boolean preparingFile; - private boolean fileLoaded; - private boolean isVideoFile; + private PlaybackService.Status status; + private PlaybackService.VideoType videoType; private long rssItemId; public long getRssItemId() { @@ -19,8 +19,12 @@ public class UpdatePodcastStatusEvent { return title; } + public PlaybackService.Status getStatus() { + return status; + } + public boolean isPlaying() { - return playing; + return status == PlaybackService.Status.PLAYING; } public long getCurrent() { @@ -31,24 +35,16 @@ public class UpdatePodcastStatusEvent { return max; } - public boolean isPreparingFile() { - return preparingFile; - } - - public boolean isFileLoaded() { - return fileLoaded; - } + public PlaybackService.VideoType getVideoType() { return videoType; } - public boolean isVideoFile() { return isVideoFile; } + public boolean isVideoFile() { return !(videoType == PlaybackService.VideoType.None); } - public UpdatePodcastStatusEvent(long current, long max, boolean playing, String title, boolean preparingFile, boolean fileLoaded, boolean isVideoFile, long rssItemId) { + public UpdatePodcastStatusEvent(long current, long max, PlaybackService.Status status, String title, PlaybackService.VideoType videoType, long rssItemId) { this.current = current; this.max = max; - this.playing = playing; + this.status = status; this.title = title; - this.preparingFile = preparingFile; - this.fileLoaded = fileLoaded; - this.isVideoFile = isVideoFile; + this.videoType = videoType; this.rssItemId = rssItemId; } diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/model/PodcastItem.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/model/PodcastItem.java index 834e2cd7..2b5e0b01 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/model/PodcastItem.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/model/PodcastItem.java @@ -24,4 +24,9 @@ public class PodcastItem extends MediaItem { public static Integer DOWNLOAD_COMPLETED = -1; public static Integer DOWNLOAD_NOT_STARTED = -2; + + + public boolean isYoutubeVideo() { + return link.matches("^https?://(www.)?youtube.com/.*"); + } } diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/reader/owncloud/InsertItemIntoDatabase.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/reader/owncloud/InsertItemIntoDatabase.java index 43acd9ef..69789b57 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/reader/owncloud/InsertItemIntoDatabase.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/reader/owncloud/InsertItemIntoDatabase.java @@ -52,17 +52,21 @@ public class InsertItemIntoDatabase implements IHandleJsonObject { Date pubDate = new Date(e.optLong("pubDate") * 1000); String content = e.optString("body"); + + // Remove some ads content = content.replaceAll("<img[^>]*feedsportal.com.*>", ""); content = content.replaceAll("<img[^>]*statisches.auslieferung.commindo-media-ressourcen.de.*>", ""); content = content.replaceAll("<img[^>]*auslieferung.commindo-media-ressourcen.de.*>", ""); content = content.replaceAll("<img[^>]*rss.buysellads.com.*>", ""); + + String url = e.optString("url"); String guid = e.optString("guid"); String enclosureLink = e.optString("enclosureLink"); String enclosureMime = e.optString("enclosureMime"); - if(enclosureLink.trim().equals("") && guid.startsWith("http://gdata.youtube.com/feeds/api/")) { + if(enclosureLink.trim().equals("") && url.matches("^https?://(www.)?youtube.com/.*")) { enclosureLink = url; enclosureMime = "youtube"; } 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 + "]"); + } + }; +} diff --git a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/view/PodcastNotification.java b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/view/PodcastNotification.java index a77c43bb..a2dd6fbd 100644 --- a/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/view/PodcastNotification.java +++ b/News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/view/PodcastNotification.java @@ -26,8 +26,9 @@ import de.luhmer.owncloudnewsreader.R; import de.luhmer.owncloudnewsreader.events.podcast.TogglePlayerStateEvent; import de.luhmer.owncloudnewsreader.events.podcast.UpdatePodcastStatusEvent; import de.luhmer.owncloudnewsreader.events.podcast.broadcastreceiver.PodcastNotificationToggle; -import de.luhmer.owncloudnewsreader.model.PodcastItem; +import de.luhmer.owncloudnewsreader.model.MediaItem; import de.luhmer.owncloudnewsreader.services.PodcastPlaybackService; +import de.luhmer.owncloudnewsreader.services.podcast.PlaybackService; public class PodcastNotification { @@ -89,7 +90,7 @@ public class PodcastNotification { @Subscribe public void onEvent(UpdatePodcastStatusEvent podcast) { - if(!podcast.isFileLoaded()) + if(podcast.getStatus() != PlaybackService.Status.NOT_INITIALIZED) return; int drawableId = podcast.isPlaying() ? android.R.drawable.ic_media_pause : android.R.drawable.ic_media_play; @@ -153,7 +154,7 @@ public class PodcastNotification { notificationBuilder .setContentText(fromText + " - " + toText) - .setProgress(100, progress, podcast.isPreparingFile()); + .setProgress(100, progress, podcast.getStatus() == PlaybackService.Status.PREPARING); notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build()); } @@ -180,7 +181,7 @@ public class PodcastNotification { .setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE).build()); - PodcastItem podcastItem = ((PodcastPlaybackService)mContext).getCurrentlyPlayingPodcast(); + MediaItem podcastItem = ((PodcastPlaybackService)mContext).getCurrentlyPlayingPodcast(); String favIconUrl = podcastItem.favIcon; DisplayImageOptions displayImageOptions = new DisplayImageOptions.Builder(). |