Merge branch 'master' into fixBlackBgLostOnOrientationChange
This commit is contained in:
commit
694b1d09fa
33 changed files with 601 additions and 249 deletions
|
@ -83,13 +83,6 @@
|
|||
|
||||
<activity android:name="DirectoryChooserActivity" />
|
||||
|
||||
<receiver android:name=".events.podcast.broadcastreceiver.PodcastNotificationToggle">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MEDIA_BUTTON" />
|
||||
<action android:name="android.media.AUDIO_BECOMING_NOISY" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
|
||||
<!--
|
||||
**********************************************************************
|
||||
|
|
|
@ -22,7 +22,7 @@ public class YoutubePlaybackService extends PlaybackService {
|
|||
Context context;
|
||||
|
||||
public YoutubePlaybackService(Context context, PodcastStatusListener podcastStatusListener, MediaItem mediaItem) {
|
||||
super(context, podcastStatusListener, mediaItem);
|
||||
super(podcastStatusListener, mediaItem);
|
||||
this.context = context;
|
||||
setStatus(Status.PREPARING);
|
||||
}
|
||||
|
|
|
@ -99,12 +99,6 @@
|
|||
</activity>
|
||||
<activity android:name=".DirectoryChooserActivity" />
|
||||
|
||||
<receiver android:name=".events.podcast.broadcastreceiver.PodcastNotificationToggle">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MEDIA_BUTTON" />
|
||||
<action android:name="android.intent.action.HEADSET_PLUG" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<!--
|
||||
**********************************************************************
|
||||
|
@ -181,9 +175,9 @@
|
|||
</receiver>
|
||||
|
||||
<!--
|
||||
**********************************************************************
|
||||
* Widget Provider Receiver
|
||||
**********************************************************************
|
||||
**********************************************************************
|
||||
* Widget Provider Receiver
|
||||
**********************************************************************
|
||||
-->
|
||||
<receiver android:name=".widget.WidgetProvider">
|
||||
<intent-filter>
|
||||
|
@ -199,13 +193,37 @@
|
|||
android:name=".widget.WidgetService"
|
||||
android:exported="false"
|
||||
android:permission="android.permission.BIND_REMOTEVIEWS" />
|
||||
|
||||
<!--
|
||||
**********************************************************************
|
||||
* Podcast
|
||||
**********************************************************************
|
||||
-->
|
||||
<service
|
||||
android:name=".services.PodcastPlaybackService"
|
||||
android:enabled="true"
|
||||
android:exported="true" /> <!-- android:process=":podcastPlaybackService" -->
|
||||
android:exported="true" >
|
||||
<intent-filter>
|
||||
<action android:name="android.media.browse.MediaBrowserService" />
|
||||
</intent-filter>
|
||||
</service> <!-- android:process=":podcastPlaybackService" -->
|
||||
|
||||
<receiver android:name="android.support.v4.media.session.MediaButtonReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MEDIA_BUTTON" />
|
||||
<action android:name="android.media.AUDIO_BECOMING_NOISY" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<service
|
||||
android:name=".services.PodcastDownloadService"
|
||||
android:exported="false" />
|
||||
|
||||
<!--
|
||||
**********************************************************************
|
||||
* Chrome-Custom Tabs
|
||||
**********************************************************************
|
||||
-->
|
||||
<service
|
||||
android:name=".chrometabs.KeepAliveService"
|
||||
android:exported="true"
|
||||
|
|
|
@ -444,7 +444,7 @@ public class NewsDetailActivity extends PodcastFragmentActivity {
|
|||
break;
|
||||
|
||||
case R.id.action_tts:
|
||||
TTSItem ttsItem = new TTSItem(rssItem.getId(), rssItem.getTitle(), rssItem.getTitle() + "\n\n " + Html.fromHtml(rssItem.getBody()).toString(), rssItem.getFeed().getFaviconUrl());
|
||||
TTSItem ttsItem = new TTSItem(rssItem.getId(), rssItem.getAuthor(), rssItem.getTitle(), rssItem.getTitle() + "\n\n " + Html.fromHtml(rssItem.getBody()).toString(), rssItem.getFeed().getFaviconUrl());
|
||||
openMediaItem(ttsItem);
|
||||
break;
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ import org.greenrobot.eventbus.Subscribe;
|
|||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
|
@ -168,7 +169,7 @@ public class PodcastFragment extends Fragment {
|
|||
}
|
||||
|
||||
if(lastPodcastRssItemId != podcast.getRssItemId() && imgFavIcon != null) {
|
||||
if(loadPodcastFavIcon()) { //Returns false if PodcastItem is not found (e.g. Service is not connected to Activity yet)
|
||||
if(loadPodcastFavIcon()) {
|
||||
lastPodcastRssItemId = podcast.getRssItemId();
|
||||
}
|
||||
}
|
||||
|
@ -177,15 +178,15 @@ public class PodcastFragment extends Fragment {
|
|||
int minutes = (int)(podcast.getCurrent() % (1000*60*60)) / (1000*60);
|
||||
int seconds = (int) ((podcast.getCurrent() % (1000*60*60)) % (1000*60) / 1000);
|
||||
minutes += hours * 60;
|
||||
tvFrom.setText(String.format("%02d:%02d", minutes, seconds));
|
||||
tvFromSlider.setText(String.format("%02d:%02d", minutes, seconds));
|
||||
tvFrom.setText(String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds));
|
||||
tvFromSlider.setText(String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds));
|
||||
|
||||
hours = (int)( podcast.getMax() / (1000*60*60));
|
||||
minutes = (int)(podcast.getMax() % (1000*60*60)) / (1000*60);
|
||||
seconds = (int) ((podcast.getMax() % (1000*60*60)) % (1000*60) / 1000);
|
||||
minutes += hours * 60;
|
||||
tvTo.setText(String.format("%02d:%02d", minutes, seconds));
|
||||
tvToSlider.setText(String.format("%02d:%02d", minutes, seconds));
|
||||
tvTo.setText(String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds));
|
||||
tvToSlider.setText(String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds));
|
||||
|
||||
tvTitle.setText(podcast.getTitle());
|
||||
tvTitleSlider.setText(podcast.getTitle());
|
||||
|
@ -210,17 +211,23 @@ public class PodcastFragment extends Fragment {
|
|||
}
|
||||
|
||||
private boolean loadPodcastFavIcon() {
|
||||
MediaItem podcastItem = ((PodcastFragmentActivity) getActivity()).getCurrentPlayingPodcast();
|
||||
if(podcastItem != null) {
|
||||
String favIconUrl = podcastItem.favIcon;
|
||||
DisplayImageOptions displayImageOptions = new DisplayImageOptions.Builder().
|
||||
showImageOnLoading(R.drawable.default_feed_icon_light).
|
||||
showImageForEmptyUri(R.drawable.default_feed_icon_light).
|
||||
showImageOnFail(R.drawable.default_feed_icon_light).
|
||||
build();
|
||||
ImageLoader.getInstance().displayImage(favIconUrl, imgFavIcon, displayImageOptions);
|
||||
}
|
||||
return podcastItem != null;
|
||||
return ((PodcastFragmentActivity) getActivity()).getCurrentPlayingPodcast(
|
||||
new PodcastFragmentActivity.OnCurrentPlayingPodcastCallback() {
|
||||
@Override
|
||||
public void currentPlayingPodcastReceived(MediaItem mediaItem) {
|
||||
Log.d(TAG, "currentPlayingPodcastReceived() called with: mediaItem = [" + mediaItem + "]");
|
||||
if(mediaItem != null) {
|
||||
String favIconUrl = mediaItem.favIcon;
|
||||
Log.d(TAG, "currentPlayingPodcastReceived: " + favIconUrl);
|
||||
DisplayImageOptions displayImageOptions = new DisplayImageOptions.Builder().
|
||||
showImageOnLoading(R.drawable.default_feed_icon_light).
|
||||
showImageForEmptyUri(R.drawable.default_feed_icon_light).
|
||||
showImageOnFail(R.drawable.default_feed_icon_light).
|
||||
build();
|
||||
ImageLoader.getInstance().displayImage(favIconUrl, imgFavIcon, displayImageOptions);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
@ -258,10 +265,11 @@ public class PodcastFragment extends Fragment {
|
|||
|
||||
boolean hasTitleInCache = false;
|
||||
@OnClick(R.id.fl_playPausePodcastWrapper) void playPause() {
|
||||
if(!hasTitleInCache)
|
||||
if(!hasTitleInCache) {
|
||||
Toast.makeText(getActivity(), "Please select a title first", Toast.LENGTH_SHORT).show();
|
||||
else
|
||||
} else {
|
||||
eventBus.post(new TogglePlayerStateEvent());
|
||||
}
|
||||
}
|
||||
|
||||
@OnClick(R.id.btn_playPausePodcastSlider) void playPauseSlider() {
|
||||
|
@ -437,9 +445,14 @@ public class PodcastFragment extends Fragment {
|
|||
});
|
||||
|
||||
if(getActivity() instanceof PodcastFragmentActivity) {
|
||||
float playbackSpeed = ((PodcastFragmentActivity) getActivity()).getCurrentPlaybackSpeed();
|
||||
int position = Arrays.binarySearch(PodcastPlaybackService.PLAYBACK_SPEEDS, playbackSpeed);
|
||||
numberPicker.setValue(position);
|
||||
((PodcastFragmentActivity) getActivity()).getCurrentPlaybackSpeed(new PodcastFragmentActivity.OnPlaybackSpeedCallback() {
|
||||
@Override
|
||||
public void currentPlaybackReceived(float playbackSpeed) {
|
||||
int position = Arrays.binarySearch(PodcastPlaybackService.PLAYBACK_SPEEDS, playbackSpeed);
|
||||
numberPicker.setValue(position);
|
||||
}
|
||||
});
|
||||
|
||||
} else {
|
||||
numberPicker.setValue(3);
|
||||
}
|
||||
|
|
|
@ -7,13 +7,17 @@ import android.content.ComponentName;
|
|||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.Handler;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ResultReceiver;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
import android.support.v4.media.MediaBrowserCompat;
|
||||
import android.support.v4.media.session.MediaControllerCompat;
|
||||
import android.support.v4.media.session.MediaSessionCompat;
|
||||
import android.support.v4.view.GravityCompat;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.util.Log;
|
||||
|
@ -63,24 +67,27 @@ import de.luhmer.owncloudnewsreader.view.ZoomableRelativeLayout;
|
|||
import de.luhmer.owncloudnewsreader.widget.WidgetProvider;
|
||||
|
||||
import static de.luhmer.owncloudnewsreader.Constants.MIN_NEXTCLOUD_FILES_APP_VERSION_CODE;
|
||||
import static de.luhmer.owncloudnewsreader.services.PodcastPlaybackService.CURRENT_PODCAST_ITEM_MEDIA_ITEM;
|
||||
import static de.luhmer.owncloudnewsreader.services.PodcastPlaybackService.PLAYBACK_SPEED_FLOAT;
|
||||
|
||||
public class PodcastFragmentActivity extends AppCompatActivity implements IPlayPausePodcastClicked {
|
||||
|
||||
private static final String TAG = PodcastFragmentActivity.class.getCanonicalName();
|
||||
|
||||
@Inject SharedPreferences mPrefs;
|
||||
@Inject ApiProvider mApi;
|
||||
@Inject public MemorizingTrustManager mMTM;
|
||||
@Inject protected SharedPreferences mPrefs;
|
||||
@Inject protected ApiProvider mApi;
|
||||
@Inject protected MemorizingTrustManager mMTM;
|
||||
|
||||
private PodcastPlaybackService mPodcastPlaybackService;
|
||||
private boolean mBound = false;
|
||||
private MediaBrowserCompat mMediaBrowser;
|
||||
private EventBus eventBus;
|
||||
private PodcastFragment mPodcastFragment;
|
||||
private int appHeight;
|
||||
private int appWidth;
|
||||
|
||||
@BindView(R.id.videoPodcastSurfaceWrapper) ZoomableRelativeLayout rlVideoPodcastSurfaceWrapper;
|
||||
@BindView(R.id.sliding_layout) PodcastSlidingUpPanelLayout sliding_layout;
|
||||
@BindView(R.id.videoPodcastSurfaceWrapper)
|
||||
protected ZoomableRelativeLayout rlVideoPodcastSurfaceWrapper;
|
||||
@BindView(R.id.sliding_layout)
|
||||
protected PodcastSlidingUpPanelLayout sliding_layout;
|
||||
//YouTubePlayerFragment youtubeplayerfragment;
|
||||
|
||||
private boolean currentlyPlaying = false;
|
||||
|
@ -103,7 +110,7 @@ public class PodcastFragmentActivity extends AppCompatActivity implements IPlayP
|
|||
|
||||
((NewsReaderApplication) getApplication()).getAppComponent().injectActivity(this);
|
||||
|
||||
if(mApi.getAPI() instanceof API_SSO) {
|
||||
if (mApi.getAPI() instanceof API_SSO) {
|
||||
VersionCheckHelper.verifyMinVersion(this, MIN_NEXTCLOUD_FILES_APP_VERSION_CODE);
|
||||
}
|
||||
|
||||
|
@ -149,10 +156,16 @@ public class PodcastFragmentActivity extends AppCompatActivity implements IPlayP
|
|||
|
||||
updatePodcastView();
|
||||
|
||||
if(isMyServiceRunning(PodcastPlaybackService.class, this)) {
|
||||
/*
|
||||
if (isMyServiceRunning(PodcastPlaybackService.class, this)) {
|
||||
Intent intent = new Intent(this, PodcastPlaybackService.class);
|
||||
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
|
||||
}
|
||||
*/
|
||||
mMediaBrowser = new MediaBrowserCompat(this,
|
||||
new ComponentName(this, PodcastPlaybackService.class),
|
||||
mConnectionCallbacks,
|
||||
null); // optional Bundle
|
||||
|
||||
super.onPostCreate(savedInstanceState);
|
||||
}
|
||||
|
@ -163,20 +176,12 @@ public class PodcastFragmentActivity extends AppCompatActivity implements IPlayP
|
|||
|
||||
super.onStop();
|
||||
|
||||
unbindPodcastService();
|
||||
}
|
||||
|
||||
private void unbindPodcastService() {
|
||||
// Unbind from the service
|
||||
if (mBound) {
|
||||
unbindService(mConnection);
|
||||
mBound = false;
|
||||
}
|
||||
mMediaBrowser.disconnect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasWindowFocus) {
|
||||
if(hasWindowFocus) {
|
||||
if (hasWindowFocus) {
|
||||
int currentOrientation = getResources().getConfiguration().orientation;
|
||||
if (currentOrientation != lastOrientation) {
|
||||
sliding_layout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
|
||||
|
@ -188,13 +193,13 @@ public class PodcastFragmentActivity extends AppCompatActivity implements IPlayP
|
|||
}
|
||||
|
||||
|
||||
|
||||
int lastOrientation = -1;
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
eventBus.register(this);
|
||||
|
||||
if(mPodcastPlaybackService != null && !mPodcastPlaybackService.isActive()) {
|
||||
if (mMediaBrowser != null && !mMediaBrowser.isConnected()) {
|
||||
sliding_layout.setPanelHeight(0);
|
||||
sliding_layout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
|
||||
}
|
||||
|
@ -221,12 +226,12 @@ public class PodcastFragmentActivity extends AppCompatActivity implements IPlayP
|
|||
WidgetProvider.UpdateWidget(this);
|
||||
|
||||
|
||||
if(NextcloudNotificationManager.isUnreadRssCountNotificationVisible(this)) {
|
||||
if (NextcloudNotificationManager.isUnreadRssCountNotificationVisible(this)) {
|
||||
DatabaseConnectionOrm dbConn = new DatabaseConnectionOrm(this);
|
||||
int count = Integer.parseInt(dbConn.getUnreadItemsCountForSpecificFolder(SubscriptionExpandableListAdapter.SPECIAL_FOLDERS.ALL_UNREAD_ITEMS));
|
||||
NextcloudNotificationManager.showUnreadRssItemsNotification(this, count);
|
||||
|
||||
if(count == 0) {
|
||||
if (count == 0) {
|
||||
NextcloudNotificationManager.removeRssItemsNotification(this);
|
||||
}
|
||||
}
|
||||
|
@ -246,31 +251,72 @@ public class PodcastFragmentActivity extends AppCompatActivity implements IPlayP
|
|||
return false;
|
||||
}
|
||||
|
||||
private final MediaBrowserCompat.ConnectionCallback mConnectionCallbacks =
|
||||
new MediaBrowserCompat.ConnectionCallback() {
|
||||
@Override
|
||||
public void onConnected() {
|
||||
Log.d(TAG, "onConnected() called");
|
||||
|
||||
/** Defines callbacks for service binding, passed to bindService() */
|
||||
private ServiceConnection mConnection = new ServiceConnection() {
|
||||
// Get the token for the MediaSession
|
||||
MediaSessionCompat.Token token = mMediaBrowser.getSessionToken();
|
||||
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName className,
|
||||
IBinder service) {
|
||||
// We've bound to LocalService, cast the IBinder and get LocalService instance
|
||||
PodcastPlaybackService.LocalBinder binder = (PodcastPlaybackService.LocalBinder) service;
|
||||
mPodcastPlaybackService = binder.getService();
|
||||
mBound = true;
|
||||
try {
|
||||
// Create a MediaControllerCompat
|
||||
MediaControllerCompat mediaController = new MediaControllerCompat(PodcastFragmentActivity.this, token);
|
||||
|
||||
// Save the controller
|
||||
MediaControllerCompat.setMediaController(PodcastFragmentActivity.this, mediaController);
|
||||
|
||||
// Finish building the UI
|
||||
//buildTransportControls();
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Connecting to podcast service failed!", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionSuspended() {
|
||||
Log.d(TAG, "onConnectionSuspended() called");
|
||||
// The Service has crashed. Disable transport controls until it automatically reconnects
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionFailed() {
|
||||
Log.e(TAG, "onConnectionFailed() called");
|
||||
// The Service has refused our connection
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
private void buildTransportControls() {
|
||||
// Grab the view for the play/pause button
|
||||
|
||||
int pbState = MediaControllerCompat.getMediaController(PodcastFragmentActivity.this).getPlaybackState().getState();
|
||||
if (pbState == PlaybackStateCompat.STATE_PLAYING) {
|
||||
MediaControllerCompat.getMediaController(PodcastFragmentActivity.this).getTransportControls().pause();
|
||||
} else {
|
||||
MediaControllerCompat.getMediaController(PodcastFragmentActivity.this).getTransportControls().play();
|
||||
}
|
||||
MediaControllerCompat mediaController = MediaControllerCompat.getMediaController(PodcastFragmentActivity.this);
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName arg0) {
|
||||
mBound = false;
|
||||
}
|
||||
};
|
||||
// Display the initial state
|
||||
MediaMetadataCompat metadata = mediaController.getMetadata();
|
||||
PlaybackStateCompat pbState = mediaController.getPlaybackState();
|
||||
|
||||
public MediaItem getCurrentPlayingPodcast() {
|
||||
if(mPodcastPlaybackService != null)
|
||||
return mPodcastPlaybackService.getCurrentlyPlayingPodcast();
|
||||
return null;
|
||||
// Register a Callback to stay in sync
|
||||
mediaController.registerCallback(controllerCallback);
|
||||
}
|
||||
|
||||
MediaControllerCompat.Callback controllerCallback =
|
||||
new MediaControllerCompat.Callback() {
|
||||
@Override
|
||||
public void onMetadataChanged(MediaMetadataCompat metadata) {}
|
||||
|
||||
@Override
|
||||
public void onPlaybackStateChanged(PlaybackStateCompat state) {}
|
||||
};
|
||||
*/
|
||||
|
||||
public PodcastSlidingUpPanelLayout getSlidingLayout() {
|
||||
return sliding_layout;
|
||||
}
|
||||
|
@ -581,7 +627,12 @@ public class PodcastFragmentActivity extends AppCompatActivity implements IPlayP
|
|||
Intent intent = new Intent(this, PodcastPlaybackService.class);
|
||||
intent.putExtra(PodcastPlaybackService.MEDIA_ITEM, mediaItem);
|
||||
startService(intent);
|
||||
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
|
||||
|
||||
if(!mMediaBrowser.isConnected()) {
|
||||
mMediaBrowser.connect();
|
||||
}
|
||||
//bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -623,11 +674,44 @@ public class PodcastFragmentActivity extends AppCompatActivity implements IPlayP
|
|||
|
||||
@Override
|
||||
public void pausePodcast() {
|
||||
mPodcastPlaybackService.pause();
|
||||
MediaControllerCompat.getMediaController(PodcastFragmentActivity.this).getTransportControls().pause();
|
||||
}
|
||||
|
||||
public float getCurrentPlaybackSpeed() {
|
||||
return mPodcastPlaybackService.getPlaybackSpeed();
|
||||
public void getCurrentPlaybackSpeed(final OnPlaybackSpeedCallback callback) {
|
||||
MediaControllerCompat.getMediaController(PodcastFragmentActivity.this)
|
||||
.sendCommand(PLAYBACK_SPEED_FLOAT,
|
||||
null,
|
||||
new ResultReceiver(new Handler()) {
|
||||
@Override
|
||||
protected void onReceiveResult(int resultCode, Bundle resultData) {
|
||||
callback.currentPlaybackReceived(resultData.getFloat(PLAYBACK_SPEED_FLOAT));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean getCurrentPlayingPodcast(final OnCurrentPlayingPodcastCallback callback) {
|
||||
if(mMediaBrowser != null && mMediaBrowser.isConnected()) {
|
||||
MediaControllerCompat.getMediaController(PodcastFragmentActivity.this)
|
||||
.sendCommand(CURRENT_PODCAST_ITEM_MEDIA_ITEM,
|
||||
null,
|
||||
new ResultReceiver(new Handler()) {
|
||||
@Override
|
||||
protected void onReceiveResult(int resultCode, Bundle resultData) {
|
||||
callback.currentPlayingPodcastReceived((MediaItem) resultData.getSerializable(CURRENT_PODCAST_ITEM_MEDIA_ITEM));
|
||||
}
|
||||
});
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnPlaybackSpeedCallback {
|
||||
void currentPlaybackReceived(float playbackSpeed);
|
||||
}
|
||||
|
||||
public interface OnCurrentPlayingPodcastCallback {
|
||||
void currentPlayingPodcastReceived(MediaItem mediaItem);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ public class UpdatePodcastStatusEvent {
|
|||
|
||||
private long current;
|
||||
private long max;
|
||||
private String author;
|
||||
private String title;
|
||||
private PlaybackService.Status status;
|
||||
private PlaybackService.VideoType videoType;
|
||||
|
@ -16,6 +17,10 @@ public class UpdatePodcastStatusEvent {
|
|||
return rssItemId;
|
||||
}
|
||||
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
@ -42,10 +47,11 @@ public class UpdatePodcastStatusEvent {
|
|||
|
||||
public boolean isVideoFile() { return !(videoType == PlaybackService.VideoType.None); }
|
||||
|
||||
public UpdatePodcastStatusEvent(long current, long max, PlaybackService.Status status, String title, PlaybackService.VideoType videoType, long rssItemId, float speed) {
|
||||
public UpdatePodcastStatusEvent(long current, long max, PlaybackService.Status status, String author, String title, PlaybackService.VideoType videoType, long rssItemId, float speed) {
|
||||
this.current = current;
|
||||
this.max = max;
|
||||
this.status = status;
|
||||
this.author = author;
|
||||
this.title = title;
|
||||
this.videoType = videoType;
|
||||
this.rssItemId = rssItemId;
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
package de.luhmer.owncloudnewsreader.events.podcast.broadcastreceiver;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
import de.luhmer.owncloudnewsreader.events.podcast.TogglePlayerStateEvent;
|
||||
|
||||
public class PodcastNotificationToggle extends BroadcastReceiver {
|
||||
|
||||
public static final String TAG = PodcastNotificationToggle.class.getCanonicalName();
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Log.v(TAG, "onReceive() called with: context = [" + context + "], intent = [" + intent + "]");
|
||||
|
||||
//TODO problem: only the headphone unplug event is triggered. Somehow the headphone plug-in event is not triggered at all..
|
||||
//TODO expected: receive the headphone plug-in event and trigger the "play" event
|
||||
if(intent.getAction() != null && intent.getAction().equals("android.media.AUDIO_BECOMING_NOISY")) {
|
||||
EventBus.getDefault().post(new TogglePlayerStateEvent(TogglePlayerStateEvent.State.Pause));
|
||||
} else {
|
||||
EventBus.getDefault().post(new TogglePlayerStateEvent());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ import java.io.Serializable;
|
|||
|
||||
public abstract class MediaItem implements Serializable {
|
||||
public long itemId;
|
||||
public String author;
|
||||
public String title;
|
||||
public String favIcon;
|
||||
public String link;
|
||||
|
|
|
@ -6,8 +6,9 @@ public class PodcastItem extends MediaItem {
|
|||
|
||||
}
|
||||
|
||||
public PodcastItem(long itemId, String title, String link, String mimeType, boolean offlineCached, String favIcon, boolean isVideoPodcast) {
|
||||
public PodcastItem(long itemId, String author, String title, String link, String mimeType, boolean offlineCached, String favIcon, boolean isVideoPodcast) {
|
||||
this.itemId = itemId;
|
||||
this.author = author;
|
||||
this.title = title;
|
||||
this.link = link;
|
||||
this.mimeType = mimeType;
|
||||
|
|
|
@ -2,12 +2,9 @@ package de.luhmer.owncloudnewsreader.model;
|
|||
|
||||
public class TTSItem extends MediaItem {
|
||||
|
||||
public TTSItem() {
|
||||
|
||||
}
|
||||
|
||||
public TTSItem(long itemId, String title, String text, String favIcon) {
|
||||
public TTSItem(long itemId, String author, String title, String text, String favIcon) {
|
||||
this.itemId = itemId;
|
||||
this.author = author;
|
||||
this.title = title;
|
||||
this.text = text;
|
||||
this.favIcon = favIcon;
|
||||
|
|
|
@ -8,11 +8,18 @@ import android.content.Context;
|
|||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.support.v4.content.FileProvider;
|
||||
import android.support.v4.media.MediaDescriptionCompat;
|
||||
import android.support.v4.media.MediaMetadataCompat;
|
||||
import android.support.v4.media.session.MediaButtonReceiver;
|
||||
import android.support.v4.media.session.MediaControllerCompat;
|
||||
import android.support.v4.media.session.MediaSessionCompat;
|
||||
import android.support.v4.media.session.PlaybackStateCompat;
|
||||
|
||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||
import com.nostra13.universalimageloader.core.assist.ImageSize;
|
||||
|
@ -116,10 +123,17 @@ public class NextcloudNotificationManager {
|
|||
notificationManager.notify(123, notify);
|
||||
}
|
||||
|
||||
|
||||
public static NotificationCompat.Builder buildPodcastNotification(Context context, String channelId) {
|
||||
/**
|
||||
* Build a notification using the information from the given media session. Makes heavy use
|
||||
* of {@link MediaMetadataCompat#getDescription()} to extract the appropriate information.
|
||||
* @param context Context used to construct the notification.
|
||||
* @param mediaSession Media session to get information.
|
||||
* @return A pre-built notification with information from the given media session.
|
||||
*/
|
||||
public static NotificationCompat.Builder buildPodcastNotification(Context context, String channelId, MediaSessionCompat mediaSession) {
|
||||
getNotificationManagerAndCreateChannel(context, channelId);
|
||||
|
||||
/*
|
||||
// Creates an explicit intent for an ResultActivity to receive.
|
||||
Intent resultIntent = new Intent(context, NewsReaderListActivity.class);
|
||||
// Because clicking the notification opens a new ("special") activity, there's
|
||||
|
@ -138,6 +152,57 @@ public class NextcloudNotificationManager {
|
|||
.setOngoing(true)
|
||||
.setOnlyAlertOnce(true)
|
||||
.setContentIntent(resultPendingIntent);
|
||||
*/
|
||||
|
||||
Bitmap bitmapIcon = BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher);
|
||||
|
||||
MediaControllerCompat controller = mediaSession.getController();
|
||||
MediaMetadataCompat mediaMetadata = controller.getMetadata();
|
||||
MediaDescriptionCompat description = mediaMetadata.getDescription();
|
||||
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, channelId)
|
||||
/*
|
||||
.setStyle(new NotificationCompat.MediaStyle()
|
||||
.setShowActionsInCompactView(
|
||||
new int[]{playPauseButtonPosition}) // show only play/pause in compact view
|
||||
.setMediaSession(mSession.getSessionToken()))
|
||||
*/
|
||||
//.setUsesChronometer(true)
|
||||
.setContentTitle(description.getTitle())
|
||||
.setSmallIcon(R.drawable.ic_notification)
|
||||
//.setContentText(description.getSubtitle())
|
||||
//.setContentText(mediaMetadata.getText(MediaMetadataCompat.METADATA_KEY_ARTIST))
|
||||
//.setSubText(description.getDescription())
|
||||
//.setLargeIcon(description.getIconBitmap())
|
||||
.setLargeIcon(bitmapIcon)
|
||||
.setContentIntent(controller.getSessionActivity())
|
||||
.setDeleteIntent(MediaButtonReceiver.buildMediaButtonPendingIntent(context, PlaybackStateCompat.ACTION_STOP))
|
||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||
.setOnlyAlertOnce(true);
|
||||
|
||||
boolean isPlaying = controller.getPlaybackState().getState() == PlaybackStateCompat.STATE_PLAYING;
|
||||
builder.addAction(getPlayPauseAction(context, isPlaying));
|
||||
|
||||
builder.setStyle(new android.support.v4.media.app.NotificationCompat.MediaStyle()
|
||||
//.setShowActionsInCompactView(0) // show only play/pause in compact view
|
||||
.setMediaSession(mediaSession.getSessionToken())
|
||||
.setShowCancelButton(true)
|
||||
.setCancelButtonIntent(
|
||||
MediaButtonReceiver.buildMediaButtonPendingIntent(
|
||||
context, PlaybackStateCompat.ACTION_STOP)));
|
||||
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
private static NotificationCompat.Action getPlayPauseAction(Context context, boolean isPlaying) {
|
||||
int drawableId = isPlaying ? android.R.drawable.ic_media_pause : android.R.drawable.ic_media_play;
|
||||
String actionText = isPlaying ? "Pause" : "Play"; // TODO extract as string resource
|
||||
|
||||
PendingIntent pendingIntent = MediaButtonReceiver.buildMediaButtonPendingIntent(context,
|
||||
isPlaying ? PlaybackStateCompat.ACTION_PAUSE : PlaybackStateCompat.ACTION_PLAY);
|
||||
return new NotificationCompat.Action(drawableId, actionText, pendingIntent);
|
||||
|
||||
}
|
||||
|
||||
public static NotificationCompat.Builder buildDownloadPodcastNotification(Context context, String channelId) {
|
||||
|
@ -223,6 +288,9 @@ public class NextcloudNotificationManager {
|
|||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
||||
int importance = NotificationManager.IMPORTANCE_DEFAULT;
|
||||
NotificationChannel mChannel = new NotificationChannel(channelId, channelId, importance);
|
||||
mChannel.setSound(null, null);
|
||||
mChannel.enableVibration(false);
|
||||
//mChannel.setShowBadge(false);
|
||||
//mChannel.enableLights(true);
|
||||
notificationManager.createNotificationChannel(mChannel);
|
||||
}
|
||||
|
|
|
@ -1,17 +1,34 @@
|
|||
package de.luhmer.owncloudnewsreader.services;
|
||||
|
||||
import android.app.Service;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Binder;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.ResultReceiver;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.media.MediaBrowserCompat;
|
||||
import android.support.v4.media.MediaBrowserServiceCompat;
|
||||
import android.support.v4.media.MediaMetadataCompat;
|
||||
import android.support.v4.media.session.MediaButtonReceiver;
|
||||
import android.support.v4.media.session.MediaSessionCompat;
|
||||
import android.support.v4.media.session.PlaybackStateCompat;
|
||||
import android.telephony.PhoneStateListener;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import de.luhmer.owncloudnewsreader.NewsReaderListActivity;
|
||||
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;
|
||||
|
@ -29,23 +46,27 @@ 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 {
|
||||
import static android.view.KeyEvent.KEYCODE_MEDIA_STOP;
|
||||
|
||||
public class PodcastPlaybackService extends MediaBrowserServiceCompat {
|
||||
|
||||
public static final String MEDIA_ITEM = "MediaItem";
|
||||
|
||||
private static final String TAG = "PodcastPlaybackService";
|
||||
|
||||
public static final String PLAYBACK_SPEED_FLOAT = "PLAYBACK_SPEED";
|
||||
public static final String CURRENT_PODCAST_ITEM_MEDIA_ITEM= "CURRENT_PODCAST_ITEM";
|
||||
private PodcastNotification podcastNotification;
|
||||
|
||||
private EventBus eventBus;
|
||||
private Handler mHandler;
|
||||
|
||||
private PlaybackService mPlaybackService;
|
||||
private MediaSessionCompat mSession;
|
||||
|
||||
public static final float PLAYBACK_SPEEDS[] = { 0.25f, 0.5f, 0.75f, 1.0f, 1.25f, 1.5f, 1.75f, 2.0f, 2.5f, 3.0f };
|
||||
private float currentPlaybackSpeed = 1;
|
||||
|
||||
// Binder given to clients
|
||||
private final IBinder mBinder = new LocalBinder();
|
||||
|
||||
public MediaItem getCurrentlyPlayingPodcast() {
|
||||
if(mPlaybackService != null) {
|
||||
|
@ -58,20 +79,18 @@ public class PodcastPlaybackService extends Service {
|
|||
return mPlaybackService != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class used for the client Binder. Because we know this service always
|
||||
* runs in the same process as its clients, we don't need to deal with IPC.
|
||||
*/
|
||||
public class LocalBinder extends Binder {
|
||||
public PodcastPlaybackService getService() {
|
||||
// Return this instance of LocalService so clients can call public methods
|
||||
return PodcastPlaybackService.this;
|
||||
}
|
||||
@Nullable
|
||||
@Override
|
||||
public BrowserRoot onGetRoot(@NonNull String s, int i, @Nullable Bundle bundle) {
|
||||
return new MediaBrowserServiceCompat.BrowserRoot(
|
||||
getString(R.string.app_name),// Name visible in Android Auto
|
||||
null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return mBinder;
|
||||
public void onLoadChildren(@NonNull String s, @NonNull Result<List<MediaBrowserCompat.MediaItem>> result) {
|
||||
Log.d(TAG, "onLoadChildren() called with: s = [" + s + "], result = [" + result + "]");
|
||||
result.sendResult(new ArrayList<MediaBrowserCompat.MediaItem>());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -98,16 +117,31 @@ public class PodcastPlaybackService extends Service {
|
|||
mgr.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
|
||||
}
|
||||
|
||||
podcastNotification = new PodcastNotification(this);
|
||||
initMediaSessions();
|
||||
|
||||
podcastNotification = new PodcastNotification(this, mSession);
|
||||
mHandler = new Handler();
|
||||
eventBus = EventBus.getDefault();
|
||||
eventBus.register(this);
|
||||
eventBus.post(new PodcastPlaybackServiceStarted());
|
||||
//eventBus.post(new PodcastPlaybackServiceStarted());
|
||||
|
||||
mHandler.postDelayed(mUpdateTimeTask, 0);
|
||||
|
||||
|
||||
setSessionToken(mSession.getSessionToken());
|
||||
|
||||
Intent intent = new Intent(this, NewsReaderListActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
PendingIntent pi = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
mSession.setSessionActivity(pi);
|
||||
|
||||
//startForeground(PodcastNotification.NOTIFICATION_ID, podcastNotification.getNotification());
|
||||
|
||||
/*
|
||||
//Handles headphones coming unplugged. cannot be done through a manifest receiver
|
||||
IntentFilter filter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
|
||||
registerReceiver(mNoisyReceiver, filter);
|
||||
*/
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -119,6 +153,7 @@ public class PodcastPlaybackService extends Service {
|
|||
mgr.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);
|
||||
}
|
||||
|
||||
mHandler.removeCallbacks(mUpdateTimeTask);
|
||||
podcastNotification.cancel();
|
||||
|
||||
super.onDestroy();
|
||||
|
@ -127,31 +162,36 @@ public class PodcastPlaybackService extends Service {
|
|||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
MediaButtonReceiver.handleIntent(mSession, intent);
|
||||
|
||||
if (intent != null) {
|
||||
if(mPlaybackService != null) {
|
||||
if (mPlaybackService != null) {
|
||||
mPlaybackService.destroy();
|
||||
mPlaybackService = null;
|
||||
}
|
||||
mHandler.removeCallbacks(mUpdateTimeTask);
|
||||
|
||||
MediaItem mediaItem = (MediaItem) intent.getSerializableExtra(MEDIA_ITEM);
|
||||
if(intent.hasExtra(MEDIA_ITEM)) {
|
||||
MediaItem mediaItem = (MediaItem) intent.getSerializableExtra(MEDIA_ITEM);
|
||||
|
||||
if (mediaItem instanceof PodcastItem) {
|
||||
if(((PodcastItem)mediaItem).isYoutubeVideo()) {
|
||||
mPlaybackService = new YoutubePlaybackService(this, podcastStatusListener, mediaItem);
|
||||
} else {
|
||||
mPlaybackService = new MediaPlayerPlaybackService(this, podcastStatusListener, mediaItem);
|
||||
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 if(mediaItem instanceof TTSItem) {
|
||||
mPlaybackService = new TTSPlaybackService(this, podcastStatusListener, mediaItem);
|
||||
|
||||
podcastNotification.podcastChanged();
|
||||
sendMediaStatus();
|
||||
|
||||
mPlaybackService.playbackSpeedChanged(currentPlaybackSpeed);
|
||||
}
|
||||
|
||||
podcastNotification.podcastChanged();
|
||||
sendMediaStatus();
|
||||
|
||||
mPlaybackService.playbackSpeedChanged(currentPlaybackSpeed);
|
||||
}
|
||||
|
||||
return Service.START_STICKY;
|
||||
return super.onStartCommand(intent, flags, startId);
|
||||
}
|
||||
|
||||
private PlaybackService.PodcastStatusListener podcastStatusListener = new PlaybackService.PodcastStatusListener() {
|
||||
|
@ -188,6 +228,7 @@ public class PodcastPlaybackService extends Service {
|
|||
|
||||
@Subscribe
|
||||
public void onEvent(TogglePlayerStateEvent event) {
|
||||
Log.d(TAG, "onEvent() called with: event = [" + event + "]");
|
||||
if(event.getState() == TogglePlayerStateEvent.State.Toggle) {
|
||||
if (isPlaying()) {
|
||||
Log.v(TAG, "calling pause()");
|
||||
|
@ -275,24 +316,29 @@ public class PodcastPlaybackService extends Service {
|
|||
UpdatePodcastStatusEvent audioPodcastEvent;
|
||||
|
||||
if(mPlaybackService == null) {
|
||||
audioPodcastEvent = new UpdatePodcastStatusEvent(0, 0, PlaybackService.Status.NOT_INITIALIZED, "", PlaybackService.VideoType.None, -1, -1);
|
||||
audioPodcastEvent = new UpdatePodcastStatusEvent(0, 0, PlaybackService.Status.NOT_INITIALIZED, "", "", PlaybackService.VideoType.None, -1, -1);
|
||||
} else {
|
||||
audioPodcastEvent = new UpdatePodcastStatusEvent(
|
||||
mPlaybackService.getCurrentDuration(),
|
||||
mPlaybackService.getTotalDuration(),
|
||||
mPlaybackService.getStatus(),
|
||||
mPlaybackService.getMediaItem().link,
|
||||
mPlaybackService.getMediaItem().title,
|
||||
mPlaybackService.getVideoType(),
|
||||
mPlaybackService.getMediaItem().itemId,
|
||||
getPlaybackSpeed());
|
||||
}
|
||||
eventBus.post(audioPodcastEvent);
|
||||
|
||||
if(audioPodcastEvent.isPlaying()) {
|
||||
startForeground(PodcastNotification.NOTIFICATION_ID, podcastNotification.getNotification());
|
||||
} else {
|
||||
stopForeground(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class PodcastPlaybackServiceStarted {
|
||||
|
||||
}
|
||||
//public class PodcastPlaybackServiceStarted { }
|
||||
|
||||
PhoneStateListener phoneStateListener = new PhoneStateListener() {
|
||||
@Override
|
||||
|
@ -308,4 +354,91 @@ public class PodcastPlaybackService extends Service {
|
|||
super.onCallStateChanged(state, incomingNumber);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private final class MediaSessionCallback extends MediaSessionCompat.Callback {
|
||||
@Override
|
||||
public void onPlay() {
|
||||
EventBus.getDefault().post(new TogglePlayerStateEvent());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
EventBus.getDefault().post(new TogglePlayerStateEvent());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCommand(String command, Bundle extras, ResultReceiver cb) {
|
||||
if (command.equals(PLAYBACK_SPEED_FLOAT)) {
|
||||
Bundle b = new Bundle();
|
||||
b.putFloat(PLAYBACK_SPEED_FLOAT, currentPlaybackSpeed);
|
||||
cb.send(0, b);
|
||||
} else if(command.equals(CURRENT_PODCAST_ITEM_MEDIA_ITEM)) {
|
||||
Bundle b = new Bundle();
|
||||
b.putSerializable(CURRENT_PODCAST_ITEM_MEDIA_ITEM, mPlaybackService.getMediaItem());
|
||||
cb.send(0, b);
|
||||
}
|
||||
super.onCommand(command, extras, cb);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMediaButtonEvent(Intent mediaButtonEvent) {
|
||||
Log.d(TAG, mediaButtonEvent.getAction());
|
||||
|
||||
if(mediaButtonEvent.hasExtra("android.intent.extra.KEY_EVENT")) {
|
||||
KeyEvent keyEvent = mediaButtonEvent.getParcelableExtra("android.intent.extra.KEY_EVENT");
|
||||
Log.d(TAG, keyEvent.toString());
|
||||
|
||||
// Stop requested (e.g. notification was swiped away)
|
||||
if(keyEvent.getKeyCode() == KEYCODE_MEDIA_STOP) {
|
||||
pause();
|
||||
stopSelf();
|
||||
/*
|
||||
boolean isPlaying = mSession.getController().getPlaybackState().getState() == PlaybackStateCompat.STATE_PLAYING;
|
||||
if(isPlaying) {
|
||||
EventBus.getDefault().post(new TogglePlayerStateEvent());
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
return super.onMediaButtonEvent(mediaButtonEvent);
|
||||
}
|
||||
}
|
||||
|
||||
private void initMediaSessions() {
|
||||
//String packageName = PodcastNotificationToggle.class.getPackage().getName();
|
||||
//ComponentName receiver = new ComponentName(packageName, PodcastNotificationToggle.class.getName());
|
||||
ComponentName mediaButtonReceiver = new ComponentName(this, MediaButtonReceiver.class);
|
||||
mSession = new MediaSessionCompat(this, "PlayerService", mediaButtonReceiver, null);
|
||||
mSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
|
||||
MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
|
||||
mSession.setPlaybackState(new PlaybackStateCompat.Builder()
|
||||
.setState(PlaybackStateCompat.STATE_PAUSED, 0, 0)
|
||||
.setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE).build());
|
||||
|
||||
mSession.setCallback(new MediaSessionCallback());
|
||||
|
||||
//Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
|
||||
//mediaButtonIntent.setClass(mContext, MediaButtonReceiver.class);
|
||||
//PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, mediaButtonIntent, 0);
|
||||
//mSession.setMediaButtonReceiver(pendingIntent);
|
||||
|
||||
|
||||
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
|
||||
audioManager.requestAudioFocus(new AudioManager.OnAudioFocusChangeListener() {
|
||||
@Override
|
||||
public void onAudioFocusChange(int focusChange) {
|
||||
// Ignore
|
||||
}
|
||||
}, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
|
||||
|
||||
//MediaControllerCompat controller = mSession.getController();
|
||||
|
||||
//mSession.setActive(true);
|
||||
|
||||
mSession.setMetadata(new MediaMetadataCompat.Builder()
|
||||
.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, "")
|
||||
.putString(MediaMetadataCompat.METADATA_KEY_TITLE, "")
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ public class MediaPlayerPlaybackService extends PlaybackService {
|
|||
private View parentResizableView;
|
||||
|
||||
public MediaPlayerPlaybackService(final Context context, PodcastStatusListener podcastStatusListener, MediaItem mediaItem) {
|
||||
super(context, podcastStatusListener, mediaItem);
|
||||
super(podcastStatusListener, mediaItem);
|
||||
|
||||
mMediaPlayer = new MediaPlayer();
|
||||
mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package de.luhmer.owncloudnewsreader.services.podcast;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import de.luhmer.owncloudnewsreader.model.MediaItem;
|
||||
|
||||
/**
|
||||
|
@ -22,7 +20,7 @@ public abstract class PlaybackService {
|
|||
private PodcastStatusListener podcastStatusListener;
|
||||
private MediaItem mediaItem;
|
||||
|
||||
public PlaybackService(Context context, PodcastStatusListener podcastStatusListener, MediaItem mediaItem) {
|
||||
public PlaybackService(PodcastStatusListener podcastStatusListener, MediaItem mediaItem) {
|
||||
this.podcastStatusListener = podcastStatusListener;
|
||||
this.mediaItem = mediaItem;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ public class TTSPlaybackService extends PlaybackService implements TextToSpeech.
|
|||
private TextToSpeech ttsController;
|
||||
|
||||
public TTSPlaybackService(Context context, PodcastStatusListener podcastStatusListener, MediaItem mediaItem) {
|
||||
super(context, podcastStatusListener, mediaItem);
|
||||
super(podcastStatusListener, mediaItem);
|
||||
|
||||
try {
|
||||
ttsController = new TextToSpeech(context, this);
|
||||
|
|
|
@ -2,11 +2,7 @@ package de.luhmer.owncloudnewsreader.view;
|
|||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Build;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.support.v4.media.MediaMetadataCompat;
|
||||
|
@ -14,17 +10,12 @@ import android.support.v4.media.session.MediaSessionCompat;
|
|||
import android.support.v4.media.session.PlaybackStateCompat;
|
||||
import android.util.Log;
|
||||
|
||||
import com.nostra13.universalimageloader.core.DisplayImageOptions;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
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.MediaItem;
|
||||
import de.luhmer.owncloudnewsreader.notification.NextcloudNotificationManager;
|
||||
import de.luhmer.owncloudnewsreader.services.PodcastPlaybackService;
|
||||
|
@ -41,21 +32,20 @@ public class PodcastNotification {
|
|||
|
||||
private final Context mContext;
|
||||
private final NotificationManager notificationManager;
|
||||
private final NotificationCompat.Builder notificationBuilder;
|
||||
private NotificationCompat.Builder notificationBuilder;
|
||||
private final String CHANNEL_ID = "Podcast Notification";
|
||||
|
||||
//private MediaSessionManager mManager;
|
||||
private MediaSessionCompat mSession;
|
||||
//private MediaControllerCompat mController;
|
||||
private int lastDrawableId = -1;
|
||||
|
||||
private PlaybackService.Status lastStatus = PlaybackService.Status.NOT_INITIALIZED;
|
||||
|
||||
public final static int NOTIFICATION_ID = 1111;
|
||||
|
||||
public PodcastNotification(Context context) {
|
||||
public PodcastNotification(Context context, MediaSessionCompat session) {
|
||||
this.mContext = context;
|
||||
this.mSession = session;
|
||||
this.notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
this.notificationBuilder = NextcloudNotificationManager.buildPodcastNotification(mContext, CHANNEL_ID);
|
||||
|
||||
this.notificationBuilder = NextcloudNotificationManager.buildPodcastNotification(mContext, CHANNEL_ID, mSession);
|
||||
|
||||
EventBus.getDefault().register(this);
|
||||
}
|
||||
|
@ -66,7 +56,6 @@ public class PodcastNotification {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
@Subscribe
|
||||
public void onEvent(UpdatePodcastStatusEvent podcast) {
|
||||
if(mSession == null) {
|
||||
|
@ -74,12 +63,12 @@ public class PodcastNotification {
|
|||
return;
|
||||
}
|
||||
|
||||
int drawableId = podcast.isPlaying() ? android.R.drawable.ic_media_pause : android.R.drawable.ic_media_play;
|
||||
String actionText = podcast.isPlaying() ? "Pause" : "Play";
|
||||
|
||||
if(lastDrawableId != drawableId) {
|
||||
lastDrawableId = drawableId;
|
||||
|
||||
if (podcast.getStatus() != lastStatus) {
|
||||
lastStatus = podcast.getStatus();
|
||||
|
||||
/*
|
||||
notificationBuilder.setContentTitle(podcast.getTitle());
|
||||
notificationBuilder.mActions.clear();
|
||||
notificationBuilder.addAction(
|
||||
|
@ -88,7 +77,9 @@ public class PodcastNotification {
|
|||
PendingIntent.getBroadcast(mContext, 0, new Intent(mContext, PodcastNotificationToggle.class),
|
||||
PendingIntent.FLAG_ONE_SHOT));
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
if(podcast.isPlaying()) {
|
||||
//Prevent the Podcast Player from getting killed because of low memory
|
||||
//For more info see: http://developer.android.com/reference/android/app/Service.html#startForeground(int, android.app.Notification)
|
||||
|
@ -100,6 +91,7 @@ public class PodcastNotification {
|
|||
|
||||
notificationBuilder.setOngoing(false); // cancelable
|
||||
}
|
||||
*/
|
||||
|
||||
//Lock screen notification
|
||||
/*
|
||||
|
@ -108,7 +100,9 @@ public class PodcastNotification {
|
|||
.build());
|
||||
*/
|
||||
|
||||
if(podcast.isPlaying()) {
|
||||
|
||||
mSession.setActive(true);
|
||||
if (podcast.isPlaying()) {
|
||||
mSession.setPlaybackState(new PlaybackStateCompat.Builder()
|
||||
.setState(PlaybackStateCompat.STATE_PLAYING, podcast.getCurrent(), 1.0f)
|
||||
.setActions(PlaybackStateCompat.ACTION_PAUSE).build());
|
||||
|
@ -117,6 +111,18 @@ public class PodcastNotification {
|
|||
.setState(PlaybackStateCompat.STATE_PAUSED, podcast.getCurrent(), 0.0f)
|
||||
.setActions(PlaybackStateCompat.ACTION_PLAY).build());
|
||||
}
|
||||
|
||||
//mSession.setActive(podcast.isPlaying());
|
||||
|
||||
|
||||
notificationBuilder = NextcloudNotificationManager.buildPodcastNotification(mContext, CHANNEL_ID, mSession);
|
||||
|
||||
//int drawableId = podcast.isPlaying() ? android.R.drawable.ic_media_pause : android.R.drawable.ic_media_play;
|
||||
//String actionText = podcast.isPlaying() ? "Pause" : "Play";
|
||||
//notificationBuilder.addAction(new NotificationCompat.Action(drawableId, actionText, intent));
|
||||
|
||||
|
||||
notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
|
||||
}
|
||||
|
||||
|
||||
|
@ -156,76 +162,42 @@ public class PodcastNotification {
|
|||
}
|
||||
|
||||
public void podcastChanged() {
|
||||
initMediaSessions();
|
||||
}
|
||||
|
||||
private void initMediaSessions() {
|
||||
String packageName = PodcastNotificationToggle.class.getPackage().getName();
|
||||
ComponentName receiver = new ComponentName(packageName, PodcastNotificationToggle.class.getName());
|
||||
mSession = new MediaSessionCompat(mContext, "PlayerService", receiver, null);
|
||||
mSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
|
||||
MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
|
||||
mSession.setPlaybackState(new PlaybackStateCompat.Builder()
|
||||
.setState(PlaybackStateCompat.STATE_PAUSED, 0, 0)
|
||||
.setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE).build());
|
||||
|
||||
|
||||
MediaItem podcastItem = ((PodcastPlaybackService)mContext).getCurrentlyPlayingPodcast();
|
||||
|
||||
/*
|
||||
String favIconUrl = podcastItem.favIcon;
|
||||
DisplayImageOptions displayImageOptions = new DisplayImageOptions.Builder().
|
||||
showImageOnLoading(R.drawable.default_feed_icon_light).
|
||||
showImageForEmptyUri(R.drawable.default_feed_icon_light).
|
||||
showImageOnFail(R.drawable.default_feed_icon_light).
|
||||
build();
|
||||
*/
|
||||
|
||||
//TODO networkOnMainThreadExceptionHere!
|
||||
//Bitmap bmpAlbumArt = ImageLoader.getInstance().loadImageSync(favIconUrl, displayImageOptions);
|
||||
|
||||
mSession.setMetadata(new MediaMetadataCompat.Builder()
|
||||
.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, "Test")
|
||||
.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, "Test")
|
||||
.putString(MediaMetadataCompat.METADATA_KEY_TITLE, "Test")
|
||||
//.putString(MediaMetadataCompat.METADATA_KEY_TITLE, podcastItem.title)
|
||||
.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, 100)
|
||||
//.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, bmpAlbumArt)
|
||||
/* .putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART,
|
||||
BitmapFactory.decodeResource(mContext.getResources(), R.drawable.ic_launcher)) */
|
||||
.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, podcastItem.author)
|
||||
.putString(MediaMetadataCompat.METADATA_KEY_TITLE, podcastItem.title)
|
||||
.build());
|
||||
|
||||
mSession.setCallback(new MediaSessionCallback());
|
||||
/*
|
||||
mSession.setMetadata(new MediaMetadataCompat.Builder()
|
||||
.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, "NA")
|
||||
.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, "")
|
||||
.putString(MediaMetadataCompat.METADATA_KEY_TITLE, "NA")
|
||||
//.putString(MediaMetadataCompat.METADATA_KEY_TITLE, podcastItem.title)
|
||||
.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, 100)
|
||||
//.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, bmpAlbumArt)
|
||||
//.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, BitmapFactory.decodeResource(mContext.getResources(), R.drawable.ic_launcher))
|
||||
.build());
|
||||
*/
|
||||
|
||||
|
||||
AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
|
||||
audioManager.requestAudioFocus(new AudioManager.OnAudioFocusChangeListener() {
|
||||
@Override
|
||||
public void onAudioFocusChange(int focusChange) {
|
||||
// Ignore
|
||||
}
|
||||
}, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
|
||||
|
||||
|
||||
|
||||
//MediaControllerCompat controller = mSession.getController();
|
||||
|
||||
mSession.setActive(true);
|
||||
this.notificationBuilder = NextcloudNotificationManager.buildPodcastNotification(mContext, CHANNEL_ID, mSession);
|
||||
notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
|
||||
}
|
||||
|
||||
public Notification getNotification() {
|
||||
return notificationBuilder.build();
|
||||
}
|
||||
|
||||
|
||||
private final class MediaSessionCallback extends MediaSessionCompat.Callback {
|
||||
@Override
|
||||
public void onPlay() {
|
||||
EventBus.getDefault().post(new TogglePlayerStateEvent());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
EventBus.getDefault().post(new TogglePlayerStateEvent());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -101,7 +101,7 @@
|
|||
android:textAlignment="viewStart"
|
||||
android:ellipsize="end"
|
||||
tools:text="Body"
|
||||
android:textColor="@color/material_grey_600"
|
||||
android:textColor="@color/text_medium_emphasis"
|
||||
android:textSize="14sp"
|
||||
android:autoLink="none"
|
||||
android:layout_below="@+id/summary"
|
||||
|
|
|
@ -97,7 +97,7 @@
|
|||
android:textAlignment="viewStart"
|
||||
android:ellipsize="end"
|
||||
tools:text="Body"
|
||||
android:textColor="@color/material_grey_600"
|
||||
android:textColor="@color/text_medium_emphasis"
|
||||
android:textSize="14sp"
|
||||
android:autoLink="none"
|
||||
android:layout_below="@+id/summary"
|
||||
|
|
|
@ -71,7 +71,7 @@
|
|||
android:layout_marginBottom="8dp"
|
||||
android:maxLines="5"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/material_grey_600"
|
||||
android:textColor="@color/text_medium_emphasis"
|
||||
android:textSize="15sp"
|
||||
android:textStyle="normal"
|
||||
tools:text="Anruf-Info djkas dhask dhas dashdajs dha dhas dhas djka a jsa das djsa djas dash djas dashdja sljda dhjas ja dkla da ja da djas djkasas jkas dklas dsa djla hkjdsahkdas hd ashjdas jsak dsada" />
|
||||
|
|
|
@ -152,6 +152,9 @@
|
|||
<string name="no_podcast_selected">Kein Podcast ausgewählt</string>
|
||||
<string name="no_chapters_available">Keine Kapitel verfügbar</string>
|
||||
<string name="podcast_playback_speed_dialog_title">Wiedergabegeschwindigkeit</string>
|
||||
<string name="notification_downloading_podcast_title">Podcast wird herunterladen</string>
|
||||
|
||||
|
||||
<!-- Settings for Display -->
|
||||
<string name="pref_header_display">Anzeige</string>
|
||||
<string name="pref_title_app_theme">Nachtmodus</string>
|
||||
|
|
|
@ -153,6 +153,9 @@
|
|||
<string name="no_podcast_selected">Benötigt keine Übersetzung. Für Android wird nur die formelle Übersetzung verwendet (de_DE).</string>
|
||||
<string name="no_chapters_available">Benötigt keine Übersetzung. Für Android wird nur die formelle Übersetzung verwendet (de_DE).</string>
|
||||
<string name="podcast_playback_speed_dialog_title">Benötigt keine Übersetzung. Für Android wird nur die formelle Übersetzung verwendet (de_DE).</string>
|
||||
<string name="notification_downloading_podcast_title">Podcast wird herunterladen</string>
|
||||
|
||||
|
||||
<!-- Settings for Display -->
|
||||
<string name="pref_header_display">Benötigt keine Übersetzung. Für Android wird nur die formelle Übersetzung verwendet (de_DE).</string>
|
||||
<string name="pref_title_app_theme">Benötigt keine Übersetzung. Für Android wird nur die formelle Übersetzung verwendet (de_DE).</string>
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
<string name="menu_StartImageCaching">Descargar imágenes</string>
|
||||
<string name="menu_downloadMoreItems">Descargar más artículos</string>
|
||||
|
||||
<string name="tv_showing_cached_version">Mostrando versión en caché</string>
|
||||
|
||||
<!-- Action Bar Items -->
|
||||
<string name="action_starred">Destacado</string>
|
||||
<string name="action_read">Leer</string>
|
||||
|
@ -37,6 +39,7 @@
|
|||
<string name="action_sync_settings">Ajustes de sincronización</string>
|
||||
<string name="action_add_new_feed">Añadir nueva fuente</string>
|
||||
<string name="action_textToSpeech">Recopilar información</string>
|
||||
<string name="action_download_articles_offline">Descargar los artículos sin conexión</string>
|
||||
<plurals name="notification_new_items_ticker">
|
||||
<item quantity="one">Tienes %d elemento nuevo sin leer</item>
|
||||
<item quantity="other">Tienes %d elementos nuevos sin leer</item>
|
||||
|
@ -149,6 +152,9 @@
|
|||
<string name="no_podcast_selected">Ningún podcast seleccionado</string>
|
||||
<string name="no_chapters_available">No hay capítulos disponibles</string>
|
||||
<string name="podcast_playback_speed_dialog_title">Velocidad de reproducción</string>
|
||||
<string name="notification_downloading_podcast_title">Descargando podcast</string>
|
||||
|
||||
|
||||
<!-- Settings for Display -->
|
||||
<string name="pref_header_display">Mostrar</string>
|
||||
<string name="pref_title_app_theme">Modo Oscuro</string>
|
||||
|
@ -172,6 +178,12 @@
|
|||
<string name="pref_display_browser_built_in">Navegador integrado</string>
|
||||
<string name="pref_display_browser_external">Navegador externo</string>
|
||||
|
||||
<string name="pref_display_feed_list_layout_thumbnails">Miniaturas</string>
|
||||
<string name="pref_display_feed_list_layout_simple_text">Texto sencillo</string>
|
||||
<string name="pref_display_feed_list_layout_full_text">Texto completo</string>
|
||||
<string name="pref_display_feed_list_layout_web_layout">Disposición web</string>
|
||||
<string name="pref_display_feed_list_layout_card_view">Vista de tarjetas</string>
|
||||
|
||||
<!-- font size scaling definitions -->
|
||||
<string name="pref_display_font_size_s">Pequeño</string>
|
||||
<string name="pref_display_font_size_d">Por defecto</string>
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
<string name="menu_StartImageCaching">Télécharger les images</string>
|
||||
<string name="menu_downloadMoreItems">+ d\'articles</string>
|
||||
|
||||
<string name="tv_showing_cached_version">Affichage de la version en cache</string>
|
||||
|
||||
<!-- Action Bar Items -->
|
||||
<string name="action_starred">Favori</string>
|
||||
<string name="action_read">Lu</string>
|
||||
|
@ -37,6 +39,7 @@
|
|||
<string name="action_sync_settings">Paramètres de synchronisation</string>
|
||||
<string name="action_add_new_feed">Ajouter un nouveau flux</string>
|
||||
<string name="action_textToSpeech">Lire à haute voix</string>
|
||||
<string name="action_download_articles_offline">Télécharger les articles hors ligne</string>
|
||||
<plurals name="notification_new_items_ticker">
|
||||
<item quantity="one">Il y a %d nouvel article non lu</item>
|
||||
<item quantity="other">Il y a %d nouveaux articles non lus</item>
|
||||
|
@ -149,6 +152,9 @@
|
|||
<string name="no_podcast_selected">Aucun podcast sélectionné</string>
|
||||
<string name="no_chapters_available">Aucun chapitre disponible</string>
|
||||
<string name="podcast_playback_speed_dialog_title">Vitesse de lecture</string>
|
||||
<string name="notification_downloading_podcast_title">Téléchargement du podcast</string>
|
||||
|
||||
|
||||
<!-- Settings for Display -->
|
||||
<string name="pref_header_display">Affichage</string>
|
||||
<string name="pref_title_app_theme">Mode nuit</string>
|
||||
|
@ -172,7 +178,7 @@
|
|||
<string name="pref_display_browser_built_in">Navigateur intégré</string>
|
||||
<string name="pref_display_browser_external">Navigateur externe</string>
|
||||
|
||||
<string name="pref_display_feed_list_layout_thumbnails">Miniatures</string>
|
||||
<string name="pref_display_feed_list_layout_thumbnails">Vignettes</string>
|
||||
<!-- font size scaling definitions -->
|
||||
<string name="pref_display_font_size_s">Petit</string>
|
||||
<string name="pref_display_font_size_d">Par défaut</string>
|
||||
|
|
|
@ -152,6 +152,9 @@
|
|||
<string name="no_podcast_selected">Nessun podcast selezionato</string>
|
||||
<string name="no_chapters_available">Nessun capitolo disponibile</string>
|
||||
<string name="podcast_playback_speed_dialog_title">Velocità di riproduzione</string>
|
||||
<string name="notification_downloading_podcast_title">Scaricamento podcast</string>
|
||||
|
||||
|
||||
<!-- Settings for Display -->
|
||||
<string name="pref_header_display">Schermo</string>
|
||||
<string name="pref_title_app_theme">Modalità notte</string>
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
<string name="action_starred">共有</string>
|
||||
<string name="action_read">読込</string>
|
||||
<string name="action_playPodacst">Podcast を再生</string>
|
||||
<string name="action_openInBrowser">ブラウザで開く</string>
|
||||
<string name="action_Share">共有</string>
|
||||
<string name="action_login">サーバー設定</string>
|
||||
<string name="action_save">保存</string>
|
||||
|
@ -101,6 +102,10 @@
|
|||
<string name="pref_header_general">一般</string>
|
||||
<string name="pref_title_general_sort_order">ソート順</string>
|
||||
|
||||
<string name="pref_general_sort_order_new_old">新 -> 旧</string>
|
||||
<string name="pref_general_sort_order_old_new">旧 -> 新</string>
|
||||
|
||||
<string name="pref_general_search_in_title">タイトル</string>
|
||||
<string name="dialog_clearing_cache">キャッシュをクリアしています。</string>
|
||||
<string name="dialog_clearing_cache_please_wait">キャッシュをクリアしています…しばらくお待ちください。</string>
|
||||
<string name="reset_cache_unsaved_changes">未同期の変更があります。とにかくキャッシュをリセットしますか?</string>
|
||||
|
@ -120,11 +125,38 @@
|
|||
<!-- Podcast -->
|
||||
<string name="no_podcast_selected">Podcast が選択されていません</string>
|
||||
<string name="no_chapters_available">チャプターがありません</string>
|
||||
<string name="podcast_playback_speed_dialog_title">再生速度</string>
|
||||
<!-- Settings for Display -->
|
||||
<string name="pref_header_display">表示</string>
|
||||
<string name="pref_title_app_theme">ナイトモード</string>
|
||||
<string name="pref_title_feed_list_layout">フィードリストのレイアウト</string>
|
||||
<string name="pref_title_font_size">フォントサイズ</string>
|
||||
<string name="pref_display_browser">ブラウザ</string>
|
||||
|
||||
|
||||
|
||||
|
||||
<string name="pref_display_apptheme_auto">ライト / ダーク(時刻に基づく)</string>
|
||||
<string name="pref_display_apptheme_light">ライト</string>
|
||||
<string name="pref_display_apptheme_dark">ダーク</string>
|
||||
|
||||
<string name="pref_display_browser_cct">内蔵のChromeカスタムタブ</string>
|
||||
<string name="pref_display_browser_built_in">組み込みブラウザ</string>
|
||||
<string name="pref_display_browser_external">外部ブラウザ</string>
|
||||
|
||||
<string name="pref_display_feed_list_layout_thumbnails">サムネイル</string>
|
||||
<string name="pref_display_feed_list_layout_web_layout">ウェブレイアウト</string>
|
||||
<string name="pref_display_feed_list_layout_card_view">カード表示</string>
|
||||
|
||||
<!-- font size scaling definitions -->
|
||||
<string name="pref_display_font_size_s">小</string>
|
||||
<string name="pref_display_font_size_d">デフォルト</string>
|
||||
<string name="pref_display_font_size_l">大</string>
|
||||
<string name="pref_display_font_size_xl">巨大</string>
|
||||
|
||||
<string name="content_desc_play">再生</string>
|
||||
<string name="content_desc_pause">一時停止</string>
|
||||
<string name="content_desc_playback_speed">再生速度</string>
|
||||
<string name="content_desc_rewind">巻戻し</string>
|
||||
<string name="content_desc_forward">早送り</string>
|
||||
<string name="content_desc_expand">展開</string>
|
||||
|
@ -158,4 +190,20 @@
|
|||
|
||||
|
||||
|
||||
<string name="pref_data_sync_image_cache_never">しない</string>
|
||||
<string name="pref_data_sync_image_cache_wifi_only">WiFiのみ</string>
|
||||
<string name="pref_data_sync_image_cache_wifi_and_mobile">WiFi & モバイル</string>
|
||||
<string name="pref_data_sync_image_cache_ask">WiFi接続がない場合は尋ねる</string>
|
||||
|
||||
<string name="array_sync_interval_min_5">5 分</string>
|
||||
<string name="array_sync_interval_min_15">15 分</string>
|
||||
<string name="array_sync_interval_min_30">30 分</string>
|
||||
<string name="array_sync_interval_min_45">45 分</string>
|
||||
<string name="array_sync_interval_hour_1">1 時間</string>
|
||||
<string name="array_sync_interval_hour_2">2 時間</string>
|
||||
<string name="array_sync_interval_hour_3">3 時間</string>
|
||||
<string name="array_sync_interval_hour_6">6 時間</string>
|
||||
<string name="array_sync_interval_hour_12">12 時間</string>
|
||||
<string name="array_sync_interval_hour_24">24 時間</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
<color name="owncloudBlue">#1D2D44</color>
|
||||
<color name="nextcloudBlue">#006AA3</color>
|
||||
|
||||
<color name="text_medium_emphasis">#a0ffffff</color>
|
||||
|
||||
<color name="colorPrimary">@color/nextcloudBlue</color>
|
||||
<color name="colorPrimaryDark">@color/nextcloudBlue</color>
|
||||
<color name="colorAccent">#8698af</color>
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
<string name="menu_StartImageCaching">Downloaden afbeeldingen</string>
|
||||
<string name="menu_downloadMoreItems">Download meer berichten</string>
|
||||
|
||||
<string name="tv_showing_cached_version">Tonen van cached versie</string>
|
||||
|
||||
<!-- Action Bar Items -->
|
||||
<string name="action_starred">Gemarkeerd</string>
|
||||
<string name="action_read">Lees</string>
|
||||
|
@ -37,6 +39,7 @@
|
|||
<string name="action_sync_settings">Sync Settings</string>
|
||||
<string name="action_add_new_feed">Voeg nieuwe feed toe</string>
|
||||
<string name="action_textToSpeech">Voorlezen</string>
|
||||
<string name="action_download_articles_offline">Download artikels offline</string>
|
||||
<plurals name="notification_new_items_ticker">
|
||||
<item quantity="one">U hebt %d nieuw ongelezen bericht</item>
|
||||
<item quantity="other">Je hebt %d nieuwe ongelezen berichten</item>
|
||||
|
@ -149,9 +152,12 @@
|
|||
<string name="no_podcast_selected">Geen podcast geselecteerd</string>
|
||||
<string name="no_chapters_available">Geen hoofdstukken beschikbaar</string>
|
||||
<string name="podcast_playback_speed_dialog_title">Afspeelsnelheid</string>
|
||||
<string name="notification_downloading_podcast_title">Downloaden podcast</string>
|
||||
|
||||
|
||||
<!-- Settings for Display -->
|
||||
<string name="pref_header_display">Weergeven</string>
|
||||
<string name="pref_title_app_theme">Nochtmodus</string>
|
||||
<string name="pref_title_app_theme">Nachtmodus</string>
|
||||
<string name="pref_title_feed_list_layout">Feed lijst overzicht</string>
|
||||
<string name="pref_title_font_size">Fontgrootte</string>
|
||||
<string name="pref_display_browser">Browser</string>
|
||||
|
@ -176,6 +182,8 @@
|
|||
<string name="pref_display_feed_list_layout_simple_text">Verkorte tekst</string>
|
||||
<string name="pref_display_feed_list_layout_full_text">Volledige tekst</string>
|
||||
<string name="pref_display_feed_list_layout_web_layout">Weblayout</string>
|
||||
<string name="pref_display_feed_list_layout_card_view">Kaart weergave</string>
|
||||
|
||||
<!-- font size scaling definitions -->
|
||||
<string name="pref_display_font_size_s">Klein</string>
|
||||
<string name="pref_display_font_size_d">Standaard</string>
|
||||
|
@ -207,7 +215,7 @@
|
|||
|
||||
<!-- Login Dialog -->
|
||||
<string name="login_dialog_title_error">Fout</string>
|
||||
<string name="login_dialog_text_news_app_not_installed_on_server" formatted="true">het lijkt erop dat je nieuwsapp niet is geïnstalleerd of geactiveerd op je server. Volg eerst de instructies hier om de nieuwsapp op je server te installeren: %1$s</string>
|
||||
<string name="login_dialog_text_news_app_not_installed_on_server" formatted="true">Het lijkt erop dat je nieuwsapp niet is geïnstalleerd of geactiveerd op je server. Volg eerst de instructies hier om de nieuwsapp op je server te installeren: %1$s</string>
|
||||
<string name="login_dialog_text_something_went_wrong">Er ging iets verkeerd :(</string>
|
||||
<string name="login_dialog_text_zero_version_code">De Web News App gaf Versie \"0\". Bekijk alsjeblieft het volgende bug report: https://github.com/nextcloud/news/issues/5#issuecomment-242883795</string>
|
||||
<string name="login_dialog_text_not_compatible">Deze app versie is niet compatibel met je Nextcloud Nieuws App. Werk de Nieuws App en het Appframework bij.</string>
|
||||
|
|
|
@ -152,6 +152,9 @@
|
|||
<string name="no_podcast_selected">Nenhum podcast selecionado</string>
|
||||
<string name="no_chapters_available">Nenhum capítulo disponível</string>
|
||||
<string name="podcast_playback_speed_dialog_title">Velocidade do Playback</string>
|
||||
<string name="notification_downloading_podcast_title">Baixando podcast</string>
|
||||
|
||||
|
||||
<!-- Settings for Display -->
|
||||
<string name="pref_header_display">Exibir</string>
|
||||
<string name="pref_title_app_theme">Modo Noturno</string>
|
||||
|
|
|
@ -157,6 +157,9 @@
|
|||
<string name="no_podcast_selected">Није изабрана подемисија</string>
|
||||
<string name="no_chapters_available">Нема доступних поглавља</string>
|
||||
<string name="podcast_playback_speed_dialog_title">Брзина пуштања</string>
|
||||
<string name="notification_downloading_podcast_title">Преузимам подкаст</string>
|
||||
|
||||
|
||||
<!-- Settings for Display -->
|
||||
<string name="pref_header_display">Приказ</string>
|
||||
<string name="pref_title_app_theme">Ноћни режим</string>
|
||||
|
|
|
@ -152,6 +152,9 @@
|
|||
<string name="no_podcast_selected">Herhangi bir podcast seçilmemiş</string>
|
||||
<string name="no_chapters_available">Kullanılabilecek bir bölüm yok</string>
|
||||
<string name="podcast_playback_speed_dialog_title">Oynatma Hızı</string>
|
||||
<string name="notification_downloading_podcast_title">Podcast indiriliyor</string>
|
||||
|
||||
|
||||
<!-- Settings for Display -->
|
||||
<string name="pref_header_display">Görüntüle</string>
|
||||
<string name="pref_title_app_theme">Gece Kipi</string>
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
|
||||
<color name="options_menu_item_text">@color/options_menu_item</color>
|
||||
|
||||
<color name="material_red_600" tools:override="true">#e53935</color>
|
||||
|
||||
<color name="text_medium_emphasis">#a0000000</color>
|
||||
|
||||
<!-- see also assets/web.css -->
|
||||
<color name="news_detail_background_color">#eeeeee</color>
|
||||
<color name="news_detail_background_color_oled">#eeeeee</color>
|
||||
|
@ -51,4 +51,6 @@
|
|||
<color name="material_grey_700" tools:override="true">#ff717171</color>
|
||||
<color name="material_grey_800" tools:override="true">#424242</color>
|
||||
<color name="material_grey_900" tools:override="true">#212121</color>
|
||||
|
||||
<color name="material_red_600" tools:override="true">#e53935</color>
|
||||
</resources>
|
||||
|
|
|
@ -11,7 +11,7 @@ import de.luhmer.owncloudnewsreader.model.MediaItem;
|
|||
public class YoutubePlaybackService extends PlaybackService {
|
||||
|
||||
public YoutubePlaybackService(Context context, PodcastStatusListener podcastStatusListener, MediaItem mediaItem) {
|
||||
super(context, podcastStatusListener, mediaItem);
|
||||
super(podcastStatusListener, mediaItem);
|
||||
setStatus(Status.FAILED);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue