Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/news-android.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid-Development <david-dev@live.de>2017-02-01 02:32:22 +0300
committerDavid-Development <david-dev@live.de>2017-02-01 02:32:22 +0300
commit1ad975f3d574dfa04fb4f4a960b701e99119e9f1 (patch)
tree5297dfd35a96de60fc532683e8fdbdd6c9978764 /News-Android-App
parent95147eeea88874ab140d0d4447fab136d33121a1 (diff)
Fix #549
Diffstat (limited to 'News-Android-App')
-rw-r--r--News-Android-App/build.gradle3
-rw-r--r--News-Android-App/src/debug/AndroidManifest.xml3
-rw-r--r--News-Android-App/src/main/AndroidManifest.xml2
-rw-r--r--News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/Constants.java2
-rw-r--r--News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/PodcastFragment.java6
-rw-r--r--News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/PodcastFragmentActivity.java142
-rw-r--r--News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/events/podcast/RegisterYoutubeOutput.java15
-rw-r--r--News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/events/podcast/UpdatePodcastStatusEvent.java32
-rw-r--r--News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/model/PodcastItem.java5
-rw-r--r--News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/reader/owncloud/InsertItemIntoDatabase.java6
-rw-r--r--News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/services/OwnCloudSyncService.java1
-rw-r--r--News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/services/PodcastPlaybackService.java351
-rw-r--r--News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/services/podcast/MediaPlayerPlaybackService.java185
-rw-r--r--News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/services/podcast/PlaybackService.java63
-rw-r--r--News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/services/podcast/TTSPlaybackService.java89
-rw-r--r--News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/services/podcast/YoutubePlaybackService.java163
-rw-r--r--News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/view/PodcastNotification.java9
-rw-r--r--News-Android-App/src/main/res/layout/activity_news_detail.xml2
-rw-r--r--News-Android-App/src/main/res/layout/activity_newsreader.xml19
-rw-r--r--News-Android-App/src/main/res/values/dimens.xml3
20 files changed, 739 insertions, 362 deletions
diff --git a/News-Android-App/build.gradle b/News-Android-App/build.gradle
index ed8c762b..11a49c34 100644
--- a/News-Android-App/build.gradle
+++ b/News-Android-App/build.gradle
@@ -123,6 +123,9 @@ dependencies {
compile 'com.nbsp:library:1.02'
+ compile 'com.github.tommus:youtube-android-player-api:1.2.2'
+
+
androidTestCompile 'tools.fastlane:screengrab:0.3.1'
androidTestCompile("org.mockito:mockito-core:1.10.19") {
exclude group: 'org.hamcrest'
diff --git a/News-Android-App/src/debug/AndroidManifest.xml b/News-Android-App/src/debug/AndroidManifest.xml
index fbede6ec..d329170b 100644
--- a/News-Android-App/src/debug/AndroidManifest.xml
+++ b/News-Android-App/src/debug/AndroidManifest.xml
@@ -10,9 +10,6 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
-
- <uses-sdk tools:overrideLibrary="android.support.customtabs"/>
-
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
diff --git a/News-Android-App/src/main/AndroidManifest.xml b/News-Android-App/src/main/AndroidManifest.xml
index cc3b96a4..4a865ef3 100644
--- a/News-Android-App/src/main/AndroidManifest.xml
+++ b/News-Android-App/src/main/AndroidManifest.xml
@@ -20,8 +20,6 @@
<uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />
- <uses-sdk tools:overrideLibrary="android.support.customtabs"/>
-
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
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().
diff --git a/News-Android-App/src/main/res/layout/activity_news_detail.xml b/News-Android-App/src/main/res/layout/activity_news_detail.xml
index 8811cfe5..30dd4bad 100644
--- a/News-Android-App/src/main/res/layout/activity_news_detail.xml
+++ b/News-Android-App/src/main/res/layout/activity_news_detail.xml
@@ -56,7 +56,7 @@
<de.luhmer.owncloudnewsreader.view.ZoomableRelativeLayout
android:id="@+id/videoPodcastSurfaceWrapper"
android:layout_width="@dimen/podcast_video_player_width"
- android:layout_height="100dp"
+ android:layout_height="@dimen/podcast_video_player_height"
android:background="#ff7c7c7c"
android:padding="2dp"
android:layout_gravity="bottom|end"
diff --git a/News-Android-App/src/main/res/layout/activity_newsreader.xml b/News-Android-App/src/main/res/layout/activity_newsreader.xml
index 833f33e2..972cdc1e 100644
--- a/News-Android-App/src/main/res/layout/activity_newsreader.xml
+++ b/News-Android-App/src/main/res/layout/activity_newsreader.xml
@@ -34,10 +34,11 @@
android:id="@+id/toolbar_layout"
layout="@layout/toolbar_layout" />
+
<de.luhmer.owncloudnewsreader.view.ZoomableRelativeLayout
android:id="@+id/videoPodcastSurfaceWrapper"
android:layout_width="@dimen/podcast_video_player_width"
- android:layout_height="100dp"
+ android:layout_height="@dimen/podcast_video_player_height"
android:background="#ff7c7c7c"
android:padding="2dp"
android:layout_gravity="bottom|end"
@@ -45,8 +46,24 @@
android:layout_marginEnd="@dimen/podcast_horizontal_margin"
android:layout_marginBottom="@dimen/activity_vertical_margin" >
+ <!--
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="#ff7c7c7c">
+ <fragment
+ android:name="com.google.android.youtube.player.YouTubePlayerFragment"
+ android:id="@+id/youtubeplayerfragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+ </FrameLayout>
+ -->
+
+
</de.luhmer.owncloudnewsreader.view.ZoomableRelativeLayout>
+
+
</android.support.design.widget.CoordinatorLayout>
<FrameLayout
diff --git a/News-Android-App/src/main/res/values/dimens.xml b/News-Android-App/src/main/res/values/dimens.xml
index 11d69a02..4b4e97a9 100644
--- a/News-Android-App/src/main/res/values/dimens.xml
+++ b/News-Android-App/src/main/res/values/dimens.xml
@@ -12,7 +12,8 @@
<dimen name="exp_listview_row_height">48dp</dimen>
- <dimen name="podcast_video_player_width">170dp</dimen>
+ <dimen name="podcast_video_player_width">210dp</dimen>
+ <dimen name="podcast_video_player_height">120dp</dimen>
<dimen name="podcast_horizontal_margin">16dp</dimen>