diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index d183eef..0b7d59a 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -1,13 +1,45 @@
---
name: Bug report
-about: Create a report to help us improve
+about: Follow the instructions carefully on the next page.
title: ''
labels: 1 backlog, bug
assignees: ryanheise
---
-
+
**Which API doesn't behave as documented, and how does it misbehave?**
Name here the specific methods or fields that are not behaving as documented, and explain clearly what is happening.
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index 6284239..e4129d1 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -1,8 +1,8 @@
blank_issues_enabled: false
contact_links:
- - name: Community Support
+ - name: Stack Overflow
url: https://stackoverflow.com/search?q=audio_service
- about: Ask for help on Stack Overflow.
- - name: New to Flutter?
+ about: Ask here if it's not a bug report, documentation request or feature request.
+ - name: Gitter
url: https://gitter.im/flutter/flutter
- about: Chat with other Flutter developers on Gitter.
+ about: Ask here if you want to have a live chat with other Flutter developers.
diff --git a/.github/ISSUE_TEMPLATE/documentation-request.md b/.github/ISSUE_TEMPLATE/documentation-request.md
index 1d61cd1..b0ec11e 100644
--- a/.github/ISSUE_TEMPLATE/documentation-request.md
+++ b/.github/ISSUE_TEMPLATE/documentation-request.md
@@ -1,6 +1,6 @@
---
name: Documentation request
-about: Suggest an improvement to the documentation
+about: Follow the instructions carefully on the next page.
title: ''
labels: 1 backlog, documentation
assignees: ryanheise
@@ -9,15 +9,19 @@ assignees: ryanheise
**Describe the solution you'd like**
-A clear and concise description of what you want to happen.
+
**Describe alternatives you've considered**
-A clear and concise description of any alternative solutions or features you've considered.
+
**Additional context**
-Add any other context or screenshots about the feature request here.
+
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9df4bf5..eba0d9b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 0.15.1
+
+* Fix loading of file:// artUri values.
+* Allow booleans/doubles in MediaItems.
+* Silently ignore duplicate onStop requests.
+
## 0.15.0
* Web support (@keaganhilliard)
diff --git a/android/src/main/java/com/ryanheise/audioservice/AudioService.java b/android/src/main/java/com/ryanheise/audioservice/AudioService.java
index 53681fa..d6215bd 100644
--- a/android/src/main/java/com/ryanheise/audioservice/AudioService.java
+++ b/android/src/main/java/com/ryanheise/audioservice/AudioService.java
@@ -15,8 +15,6 @@ import android.graphics.BitmapFactory;
import android.media.AudioAttributes;
import android.media.AudioFocusRequest;
import android.media.AudioManager;
-import android.media.MediaDescription;
-import android.media.MediaMetadata;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -29,7 +27,6 @@ import android.support.v4.media.RatingCompat;
import android.support.v4.media.session.MediaControllerCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
-import android.util.Log;
import android.util.LruCache;
import android.view.KeyEvent;
@@ -161,8 +158,13 @@ public class AudioService extends MediaBrowserServiceCompat {
mediaSession.setActive(false);
releaseWakeLock();
stopForeground(true);
- notificationCreated = false;
stopSelf();
+ // This still does not solve the Android 11 problem.
+ // if (notificationCreated) {
+ // NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
+ // notificationManager.cancel(NOTIFICATION_ID);
+ // }
+ notificationCreated = false;
}
public static boolean isRunning() {
@@ -377,7 +379,7 @@ public class AudioService extends MediaBrowserServiceCompat {
wakeLock.release();
}
- static MediaMetadataCompat createMediaMetadata(String mediaId, String album, String title, String artist, String genre, Long duration, String artUri, String displayTitle, String displaySubtitle, String displayDescription, RatingCompat rating, Map, ?> extras) {
+ static MediaMetadataCompat createMediaMetadata(String mediaId, String album, String title, String artist, String genre, Long duration, String artUri, Boolean playable, String displayTitle, String displaySubtitle, String displayDescription, RatingCompat rating, Map, ?> extras) {
MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder()
.putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, mediaId)
.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, album)
@@ -402,7 +404,8 @@ public class AudioService extends MediaBrowserServiceCompat {
}
}
}
-
+ if (playable != null)
+ builder.putLong("playable_long", playable ? 1 : 0);
if (displayTitle != null)
builder.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, displayTitle);
if (displaySubtitle != null)
@@ -422,6 +425,10 @@ public class AudioService extends MediaBrowserServiceCompat {
builder.putLong("extra_long_" + key, (Integer)value);
} else if (value instanceof String) {
builder.putString("extra_string_" + key, (String)value);
+ } else if (value instanceof Boolean) {
+ builder.putLong("extra_boolean_" + key, (Boolean)value ? 1 : 0);
+ } else if (value instanceof Double) {
+ builder.putString("extra_double_" + key, value.toString());
}
}
}
@@ -554,7 +561,6 @@ public class AudioService extends MediaBrowserServiceCompat {
}
public class MediaSessionCallback extends MediaSessionCompat.Callback {
-
@Override
public void onAddQueueItem(MediaDescriptionCompat description) {
if (listener == null) return;
diff --git a/android/src/main/java/com/ryanheise/audioservice/AudioServicePlugin.java b/android/src/main/java/com/ryanheise/audioservice/AudioServicePlugin.java
index 64922a8..289a2ca 100644
--- a/android/src/main/java/com/ryanheise/audioservice/AudioServicePlugin.java
+++ b/android/src/main/java/com/ryanheise/audioservice/AudioServicePlugin.java
@@ -60,7 +60,6 @@ import io.flutter.embedding.engine.dart.DartExecutor;
import io.flutter.embedding.engine.dart.DartExecutor.DartCallback;
import android.content.res.AssetManager;
-import android.util.Log;
import io.flutter.view.FlutterNativeView;
import io.flutter.view.FlutterRunArguments;
@@ -997,6 +996,7 @@ public class AudioServicePlugin implements FlutterPlugin, ActivityAware {
raw.put("genre", metadataToString(mediaMetadata, MediaMetadataCompat.METADATA_KEY_GENRE));
if (mediaMetadata.containsKey(MediaMetadataCompat.METADATA_KEY_DURATION))
raw.put("duration", mediaMetadata.getLong(MediaMetadataCompat.METADATA_KEY_DURATION));
+ raw.put("playable", mediaMetadata.getLong("playable_long") != 0);
raw.put("displayTitle", metadataToString(mediaMetadata, MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE));
raw.put("displaySubtitle", metadataToString(mediaMetadata, MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE));
raw.put("displayDescription", metadataToString(mediaMetadata, MediaMetadataCompat.METADATA_KEY_DISPLAY_DESCRIPTION));
@@ -1011,6 +1011,12 @@ public class AudioServicePlugin implements FlutterPlugin, ActivityAware {
} else if (key.startsWith("extra_string_")) {
String rawKey = key.substring("extra_string_".length());
extras.put(rawKey, mediaMetadata.getString(key));
+ } else if (key.startsWith("extra_boolean_")) {
+ String rawKey = key.substring("extra_boolean_".length());
+ extras.put(rawKey, mediaMetadata.getLong(key) != 0);
+ } else if (key.startsWith("extra_double_")) {
+ String rawKey = key.substring("extra_double_".length());
+ extras.put(rawKey, new Double(mediaMetadata.getString(key)));
}
}
if (extras.size() > 0) {
@@ -1028,6 +1034,7 @@ public class AudioServicePlugin implements FlutterPlugin, ActivityAware {
(String)rawMediaItem.get("genre"),
getLong(rawMediaItem.get("duration")),
(String)rawMediaItem.get("artUri"),
+ (Boolean)rawMediaItem.get("playable"),
(String)rawMediaItem.get("displayTitle"),
(String)rawMediaItem.get("displaySubtitle"),
(String)rawMediaItem.get("displayDescription"),
diff --git a/audio_service.iml b/audio_service.iml
index 0ada17d..429df7d 100644
--- a/audio_service.iml
+++ b/audio_service.iml
@@ -12,6 +12,7 @@
+
diff --git a/lib/audio_service.dart b/lib/audio_service.dart
index ff59f58..30c80a6 100644
--- a/lib/audio_service.dart
+++ b/lib/audio_service.dart
@@ -329,8 +329,8 @@ class MediaItem {
duration: raw['duration'] != null
? Duration(milliseconds: raw['duration'])
: null,
- playable: raw['playable']??true,
artUri: raw['artUri'],
+ playable: raw['playable'],
displayTitle: raw['displayTitle'],
displaySubtitle: raw['displaySubtitle'],
displayDescription: raw['displayDescription'],
@@ -592,6 +592,16 @@ class AudioService {
static ReceivePort _customEventReceivePort;
static StreamSubscription _customEventSubscription;
+ /// A queue of tasks to be processed serially. Tasks that are processed on
+ /// this queue:
+ ///
+ /// - [connect]
+ /// - [disconnect]
+ /// - [start]
+ ///
+ /// TODO: Queue other tasks? Note, only short-running tasks should be queued.
+ static final _asyncTaskQueue = _AsyncTaskQueue();
+
/// Connects to the service from your UI so that audio playback can be
/// controlled.
///
@@ -600,93 +610,95 @@ class AudioService {
/// other methods in this class will work only while connected.
///
/// Use [AudioServiceWidget] to handle this automatically.
- static Future connect() async {
- _channel.setMethodCallHandler((MethodCall call) async {
- switch (call.method) {
- case 'onChildrenLoaded':
- final List