-
-
Notifications
You must be signed in to change notification settings - Fork 481
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
"onSetRating" not getting called on pressing notification action button #376
Comments
I assume you're asking a question and not filing a bug report? I'll change your issue type. (Note that I tend to give a higher priority to bug reports, though). |
Hey there, this is quite the zombie, but I fail even earlier: I can't get the rating buttons to show up at all! class MyAudioHandler extends BaseAudioHandler {
final _player = initAudioPlayer();
final _config = getConfig();
MyAudioHandler() {
ratingStyle.add(RatingStyle.thumbUpDown);
_player.playbackEventStream.listen((PlaybackEvent event) {
// print("Playbackeventstream event: ${event.toString()}");
final playing = _player.playing;
playbackState.add(playbackState.value.copyWith(
controls: [
if (playing) MediaControl.pause else MediaControl.play,
MediaControl.skipToNext,
like,
dislike
],
systemActions: const {
MediaAction.seek,
// MediaAction.setRating
},
androidCompactActionIndices: const [
0,
],
processingState: const {
ProcessingState.idle: AudioProcessingState.idle,
ProcessingState.loading: AudioProcessingState.loading,
ProcessingState.buffering: AudioProcessingState.buffering,
ProcessingState.ready: AudioProcessingState.ready,
ProcessingState.completed: AudioProcessingState.completed,
}[_player.processingState]!,
playing: playing,
updatePosition: _player.position,
));
}
@override
Future<void> play() => setPlay();
@override
Future<void> pause() => setPause();
@override
Future<void> seek(Duration position) => _player.seek(position);
@override
Future<void> skipToNext() => setSkip();
@override
Future<void> setRating(Rating rating, [Map<String, dynamic>? extras]) async {
print("Rating: ${rating.toString()}, extras: ${extras.toString()}");
}
@override
Future customAction(String name, [Map<String, dynamic>? extras]) async {
if (name == 'dispose') {
await _player.dispose();
super.stop();
}
}
static MediaControl like = MediaControl(
androidIcon: 'drawable/ic_action_like',
label: 'Like',
action: MediaAction.setRating,
);
static MediaControl dislike = MediaControl(
androidIcon: 'drawable/ic_action_dislike',
label: 'Dislike',
action: MediaAction.setRating,
);
} Media Item Generation: MediaItem toMediaItem() {
return MediaItem(
id: id.toString(),
album: album,
title: title.isEmpty ? filename : title,
artist: artist,
rating: const Rating.newThumbRating(false),
extras: {"rating": rating},
);
} Any Idea on why this is not working? |
So far I found out that for the icons to appear I actually need to include them in my drawables (duh). |
Hi @chrisheib , I'd be happy to accept a PR if it needs a patch. I'll also tag @hacker1024 who contributed the original ratings about 4 years ago (wow, that's quite a long project history :-) ). Maybe there was some secret sauce to get it working. |
Hey Ryan, unfortunately I need to surrender. I spent waaaay to much time in the last couple of days to try to understand the structure, but as this is the first (and maybe only) mobile app I will write, it didn't seem a worthy investment to dig deeper. I managed to get the functionality working as I need it for my app with abusing two working events for my purpose, giving them custom icons. I did find a few interesting points which someone might look into further. The main problem seems to be the function In there is a attempt to convert from the action ID (128 for setRating) to a MediaKey-string. Unfortunately there are no MediaKeys for SetRating, so at this point the function returns null early, making the buttons in the notification 'intentless' and therefore nonfunctioning. When changing the function to something like this: PendingIntent buildMediaButtonPendingIntent(long action) {
int keyCode = toKeyCode(action);
Log.i("MYDEB buildMediaButtonPendingIntent", "action: " + action + ", keycode: " + keyCode);
if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
Intent intent = new Intent(this, MediaButtonReceiver.class);
intent.setAction(Intent.ACTION_MEDIA_BUTTON);
intent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
int flags = 0;
if (Build.VERSION.SDK_INT >= 23) {
flags |= PendingIntent.FLAG_IMMUTABLE;
}
return PendingIntent.getBroadcast(this, keyCode, intent, flags);
} else {
Intent intent = new Intent(this, MediaButtonReceiver.class);
intent.setAction("com.ryanheise.audioservice." + action);
int flags = 0;
if (Build.VERSION.SDK_INT >= 23) {
flags |= PendingIntent.FLAG_IMMUTABLE;
}
return PendingIntent.getBroadcast(this, keyCode, intent, flags);
}
} We DO get a callback, but the permission system of android blocks the call. We would need to set up another RECEIVER- and/or SERVICE-Element for every ID in the AndroidManifest.xml and implement the callback handler as done in MediaButtonReceiver.java. This would probably allow for arbitrary events to be handled. Seems too much of a hassle for me tho, especially as I think this will be super hard to upstream. My hacky workaround: static MediaControl like = const MediaControl(
androidIcon: 'drawable/thumbs_up',
label: 'Like',
action: MediaAction.skipToPrevious,
);
static MediaControl dislike = const MediaControl(
androidIcon: 'drawable/thumbs_down',
label: 'Dislike',
action: MediaAction.stop,
);
@override
Future<void> skipToPrevious() async {
setUpvote();
print("skipToPrevious -> upvote");
}
@override
Future<void> stop() async {
setDownvote();
print("stop -> downvote");
} I even added a few different MediaControls to display the current rating of the song (1-7 stars in my app): static MediaControl oneStar = const MediaControl(
androidIcon: 'drawable/onestar',
label: 'Dislike',
action: MediaAction.setRating,
);
static MediaControl twoStar = const MediaControl(
androidIcon: 'drawable/twostar',
label: 'Dislike',
action: MediaAction.setRating,
);
static MediaControl threeStar = const MediaControl(
androidIcon: 'drawable/threestar',
label: 'Dislike',
action: MediaAction.setRating,
);
..... and setting them every time the rating changes: void setControlsFromRating(int rating) {
final playing = _player.playing;
var pb = playbackState.value.copyWith(controls: [
if (playing) MediaControl.pause else MediaControl.play,
MediaControl.skipToNext,
like,
dislike,
]);
var ratingC = ratingToControl(rating);
if (ratingC != null) {
pb.controls.add(ratingC);
}
playbackState.add(pb);
}
MediaControl? ratingToControl(int rating) {
switch (rating) {
case 1:
return oneStar;
case 2:
return twoStar;
case 3:
return threeStar;
case 4:
return fourStar;
case 5:
return fiveStar;
case 6:
return sixStar;
case 7:
return sevenStar;
default:
return null;
}
} |
That's fair enough as a short term workaround. Another related feature request is #633 which is to support custom actions. |
Hey, @ryanheise thanks for creating and maintaining this awesome package. I am currently using it in one of my apps and it is working out great for me. I am just stock on adding the last workflow
i.e: Adding a like/dislike action in my notification.
I tried adding new actions in the notification and they both are getting visible.
But the problem here is the callback
onSetRating
is not getting called when clicking abovetwo media controls.
Can you please guide me on how to make it work.
The text was updated successfully, but these errors were encountered: