summaryrefslogtreecommitdiff
path: root/core/src/main
diff options
context:
space:
mode:
authorMeir Schwarz <meir@imdde.com>2016-06-29 16:09:55 -0700
committerMeir Schwarz <meir@imdde.com>2016-06-29 16:09:55 -0700
commitbfe7cadd15d44b925ec17bb1bfd3c95e9e498dae (patch)
tree5b6a6264d4fcfc1327038903d02c832e7b7d949b /core/src/main
parentd295614933bee7991ba65fe89cc34c0cbd17fb07 (diff)
downloadAntennaPod-bfe7cadd15d44b925ec17bb1bfd3c95e9e498dae.zip
Add preliminary support for Android Auto by changing PlaybackService to extend MediaBrowserServiceCompat. Allows playback from queue and basic control using Android Auto.
Diffstat (limited to 'core/src/main')
-rw-r--r--core/src/main/AndroidManifest.xml10
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java17
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java99
-rw-r--r--core/src/main/res/drawable/ic_notification.pngbin0 -> 3887 bytes
-rw-r--r--core/src/main/res/values/strings.xml1
5 files changed, 119 insertions, 8 deletions
diff --git a/core/src/main/AndroidManifest.xml b/core/src/main/AndroidManifest.xml
index 4caad5f96..ee035c9fa 100644
--- a/core/src/main/AndroidManifest.xml
+++ b/core/src/main/AndroidManifest.xml
@@ -17,10 +17,14 @@
<service
android:name=".service.download.DownloadService"
android:enabled="true" />
- <service
- android:name=".service.playback.PlaybackService"
+ <service android:name=".service.playback.PlaybackService"
+ android:label="@string/app_name"
android:enabled="true"
- android:exported="true" />
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.media.browse.MediaBrowserService"/>
+ </intent-filter>
+ </service>
<service
android:name=".service.GpodnetSyncService"
android:enabled="true" />
diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java
index b8b154ff0..64d4d14fd 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java
@@ -7,6 +7,8 @@ import android.media.MediaMetadataRetriever;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.Nullable;
+import android.support.v4.media.MediaBrowserCompat;
+import android.support.v4.media.MediaDescriptionCompat;
import java.util.Date;
import java.util.List;
@@ -148,6 +150,21 @@ public class FeedMedia extends FeedFile implements Playable {
}
/**
+ * Returns a MediaItem representing the FeedMedia object.
+ * This is used by the MediaBrowserService
+ */
+ public MediaBrowserCompat.MediaItem getMediaItem() {
+ Playable p = this;
+ MediaDescriptionCompat description = new MediaDescriptionCompat.Builder()
+ .setMediaId(String.valueOf(id))
+ .setTitle(p.getEpisodeTitle())
+ .setDescription(p.getFeedTitle())
+ .setSubtitle(p.getFeedTitle())
+ .build();
+ return new MediaBrowserCompat.MediaItem(description, MediaBrowserCompat.MediaItem.FLAG_PLAYABLE);
+ }
+
+ /**
* Uses mimetype to determine the type of media.
*/
public MediaType getMediaType() {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
index 88b2c70de..10386a423 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
@@ -17,10 +17,15 @@ import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Binder;
import android.os.Build;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.Vibrator;
import android.preference.PreferenceManager;
+import android.support.annotation.NonNull;
import android.support.annotation.StringRes;
+import android.support.v4.media.MediaBrowserCompat;
+import android.support.v4.media.MediaBrowserServiceCompat;
+import android.support.v4.media.MediaDescriptionCompat;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
@@ -37,6 +42,7 @@ import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.Target;
import java.util.List;
+import java.util.ArrayList;
import de.danoeh.antennapod.core.ClientConfig;
import de.danoeh.antennapod.core.R;
@@ -51,6 +57,7 @@ import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.receiver.MediaButtonReceiver;
+import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.IntList;
@@ -62,7 +69,7 @@ import de.danoeh.antennapod.core.util.playback.Playable;
/**
* Controls the MediaPlayer that plays a FeedMedia-file
*/
-public class PlaybackService extends Service {
+public class PlaybackService extends MediaBrowserServiceCompat {
public static final String FORCE_WIDGET_UPDATE = "de.danoeh.antennapod.FORCE_WIDGET_UPDATE";
public static final String STOP_WIDGET_UPDATE = "de.danoeh.antennapod.STOP_WIDGET_UPDATE";
/**
@@ -194,7 +201,7 @@ public class PlaybackService extends Service {
private PlaybackServiceFlavorHelper flavorHelper;
/**
- * Only used for Lollipop notifications.
+ * Used for Lollipop notifications, Android Wear, and Android Auto.
*/
private MediaSessionCompat mediaSession;
@@ -202,8 +209,6 @@ public class PlaybackService extends Service {
private static volatile MediaType currentMediaType = MediaType.UNKNOWN;
- private final IBinder mBinder = new LocalBinder();
-
public class LocalBinder extends Binder {
public PlaybackService getService() {
return PlaybackService.this;
@@ -248,6 +253,8 @@ public class PlaybackService extends Service {
Log.d(TAG, "Service created.");
isRunning = true;
+ registerReceiver(autoStateUpdated, new IntentFilter(
+ "com.google.android.gms.car.media.STATUS"));
registerReceiver(headsetDisconnected, new IntentFilter(
Intent.ACTION_HEADSET_PLUG));
registerReceiver(shutdownReceiver, new IntentFilter(
@@ -277,6 +284,7 @@ public class PlaybackService extends Service {
PendingIntent buttonReceiverIntent = PendingIntent.getBroadcast(this, 0, mediaButtonIntent, PendingIntent.FLAG_UPDATE_CURRENT);
mediaSession = new MediaSessionCompat(getApplicationContext(), TAG, eventReceiver, buttonReceiverIntent);
+ setSessionToken(mediaSession.getSessionToken());
try {
mediaSession.setCallback(sessionCallback);
@@ -290,6 +298,16 @@ public class PlaybackService extends Service {
npe.printStackTrace();
}
+ List<MediaSessionCompat.QueueItem> queueItems = new ArrayList<>();
+ try {
+ for (FeedItem feedItem: taskManager.getQueue()) {
+ queueItems.add(new MediaSessionCompat.QueueItem(feedItem.getMedia().getMediaItem().getDescription(), feedItem.getId()));
+ }
+ mediaSession.setQueue(queueItems);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
flavorHelper.initializeMediaPlayer(PlaybackService.this);
mediaSession.setActive(true);
@@ -308,6 +326,7 @@ public class PlaybackService extends Service {
if (mediaSession != null) {
mediaSession.release();
}
+ unregisterReceiver(autoStateUpdated);
unregisterReceiver(headsetDisconnected);
unregisterReceiver(shutdownReceiver);
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
@@ -324,9 +343,48 @@ public class PlaybackService extends Service {
}
@Override
+ public BrowserRoot onGetRoot(String clientPackageName, int clientUid, Bundle rootHints) {
+ Log.d(TAG, "OnGetRoot: clientPackageName=" + clientPackageName +
+ "; clientUid=" + clientUid + " ; rootHints=" + rootHints);
+ return new BrowserRoot(
+ getResources().getString(R.string.app_name), // Name visible in Android Auto
+ null); // Bundle of optional extras
+ }
+
+ private MediaBrowserCompat.MediaItem createBrowsableMediaItemForRoot() {
+ MediaDescriptionCompat description = new MediaDescriptionCompat.Builder()
+ .setMediaId(getResources().getString(R.string.queue_label))
+ .setTitle(getResources().getString(R.string.queue_label))
+ .build();
+ return new MediaBrowserCompat.MediaItem(description,
+ MediaBrowserCompat.MediaItem.FLAG_BROWSABLE);
+ }
+
+ @Override
+ public void onLoadChildren(String parentId,
+ Result<List<MediaBrowserCompat.MediaItem>> result) {
+ Log.d(TAG, "OnLoadChildren: parentMediaId=" + parentId);
+ List<MediaBrowserCompat.MediaItem> mediaItems = new ArrayList<MediaBrowserCompat.MediaItem>();
+ if (parentId.equals(getResources().getString(R.string.app_name))) {
+ // Root List
+ mediaItems.add(createBrowsableMediaItemForRoot());
+ } else if (parentId.equals(getResources().getString(R.string.queue_label))){
+ // Child List
+ try {
+ for (FeedItem feedItem: taskManager.getQueue()) {
+ mediaItems.add(feedItem.getMedia().getMediaItem());
+ }
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ result.sendResult(mediaItems);
+ }
+
+ @Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "Received onBind event");
- return mBinder;
+ return super.onBind(intent);
}
@Override
@@ -1221,6 +1279,22 @@ public class PlaybackService extends Service {
}
}
+ private final BroadcastReceiver autoStateUpdated = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String status = intent.getStringExtra("media_connection_status");
+ boolean isConnectedToCar = "media_connected".equals(status);
+ Log.d(TAG, "Received Auto Connection update: " + status);
+ if(!isConnectedToCar) {
+ Log.d(TAG, "Car was unplugged during playback.");
+ pauseIfPauseOnDisconnect();
+ } else {
+ mediaPlayer.setStartWhenPrepared(true);
+ mediaPlayer.prepare();
+ }
+ }
+ };
+
/**
* Pauses playback when the headset is disconnected and the preference is
* set
@@ -1500,6 +1574,21 @@ public class PlaybackService extends Service {
}
@Override
+ public void onPlayFromMediaId(String mediaId, Bundle extras) {
+ Log.d(TAG, "onPlayFromMediaId: mediaId: " + mediaId + " extras: " + extras.toString());
+ FeedMedia p = DBReader.getFeedMedia(Long.parseLong(mediaId));
+ if(p != null) {
+ mediaPlayer.playMediaObject(p, !p.localFileAvailable(), true, true);
+ }
+ }
+
+ @Override
+ public void onPlayFromSearch (String query, Bundle extras) {
+ //Until we parse the query just play from queue
+ onPlay();
+ }
+
+ @Override
public void onPause() {
Log.d(TAG, "onPause()");
if (getStatus() == PlayerStatus.PLAYING) {
diff --git a/core/src/main/res/drawable/ic_notification.png b/core/src/main/res/drawable/ic_notification.png
new file mode 100644
index 000000000..8bd22b54a
--- /dev/null
+++ b/core/src/main/res/drawable/ic_notification.png
Binary files differ
diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml
index f1936b76e..783f6c1d9 100644
--- a/core/src/main/res/values/strings.xml
+++ b/core/src/main/res/values/strings.xml
@@ -4,6 +4,7 @@
tools:ignore="MissingTranslation">
<!-- Activitiy and fragment titles -->
+ <string name="app_name" translate="false">AntennaPod</string>
<string name="feeds_label">Feeds</string>
<string name="statistics_label">Statistics</string>
<string name="add_feed_label">Add Podcast</string>