fuyingang / media-button-router

Automatically exported from code.google.com/p/media-button-router
Apache License 2.0
0 stars 0 forks source link

Not working on ICS #10

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
1. Run Media Button Router on a phone with ICS

What is the expected output? What do you see instead?
My Nexus S was upgraded to ICS (Android Version 4.1, Build IML63B).
Prior to that, it ran perfectly on Gingerbread. Now it does not respond to any 
of the buttons (Play/Pause, FF, RW) on ICS.

What version of the product are you using? On what version of android? On what 
device?
Product: Latest from Market (Nov. 21 version)
Android OS: ICS 4.1 Build IML63B
Device: Nexus S

Please provide any additional information below.

Original issue reported on code.google.com by mi...@google.com on 7 Dec 2011 at 7:58

GoogleCodeExporter commented 9 years ago
I don't have an ICS phone yet. I hope to soon.  Once I do, I can look into 
this. It might be the functionality changed significantly in ICS and it's no 
longer possible to write an app like media button router. 

Original comment by harleens...@gmail.com on 7 Dec 2011 at 8:46

GoogleCodeExporter commented 9 years ago
A couple of additional data points:
A few other apps stopped taking bluetooth headset buttons commands with ICS:
- Audible
- Beyondpod

Beyondpod posted a beta version of their app on their site which fixed the 
problem.
I wrote to Audible about this but didn't yet get a response.

A couple of other applications seem to continue working fine:
- PowerAmp
- Music (the native app)

Not sure if all this helps, but there you go... and thanks for your prompt 
response!

Original comment by mi...@google.com on 7 Dec 2011 at 9:22

GoogleCodeExporter commented 9 years ago
I did get a Google Nexus but I haven't had time to investigate this yet. I will 
probably have some time over the holidays. 

Also, to anyone who is interested, please feel free to contribute a patch or 
anything to this project :) I wrote this app for when I was commuting by car. 
I've since moved and now commute by train. So, I'm not the most motivated 
driver of this project anymore (pun intended).

Original comment by harleens...@gmail.com on 20 Dec 2011 at 6:53

GoogleCodeExporter commented 9 years ago
tl;dr version: Difficult, if not impossible, to get media button router to work 
in Android 4.0

The problem is that the priority in Android's built in broadcast receiver 
(declared in AudioService.java) changed. This receiver is the one that forwards 
Media Button keys to a receiver registered to be the sole receiver via 
http://developer.android.com/reference/android/media/AudioManager.html#registerM
ediaButtonEventReceiver(android.content.ComponentName). It's used so that when 
a music app is opened and playing music, no other app can handle the media 
button keys. Before ICS, Android's broadcast receiver was being registered with 
priority IntentFilter.SYSTEM_HIGH_PRIORITY. But I guess because some music apps 
were always trying to take control and setting priorities higher than this 
(Integer.MAX_VALUE), Google changed how they're registering Android's own 
receiver to also be Integer.MAX_VALUE and it always wins. 

Unfortunately, media button receiver had a legitimate reason for using 
Integer.MAX_VALUE (we want to replace android's behavior for media buttons). In 
order for media button router to work with Ice Cream Sandwich, I'd have to 
change the approach significantly. I'd also have to have different code for ICS 
and prior versions of Android. I don't even know if there is a workable 
alternative. One possible solution would be to register Media Button Receiver 
also via AudioManager.registerMediaButtonReceiver. The difficulty is making 
sure MediaButtonRouter is always on top of the stack if no music is playing (or 
even if music is playing would be workable). 

I will leave this ticket open, but in all likelihood it won't be fixed anytime 
soon if ever. I will also open a ticket in Android's issue list asking for 
similar behavior to be a core part of Android, or way to swap out the handling 
behavior. 

Original comment by harleens...@gmail.com on 22 Dec 2011 at 1:31

GoogleCodeExporter commented 9 years ago
Here's a patch that gets it working again with ICS. It might need a little work 
to get it going on older versions of the SDK, but it should be compatible.

There were two problems with ICS:
1. The Android AudioService registers itself for the MEDIA_BUTTON intent with a 
priority of Integer.MAX_VALUE so that it can do its own thing which is to send 
the intent to whatever activity registered itself most recently using 
registerMediaButtonEventReceiver.
I'm getting around this problem by creating a service 
(MediaButtonMonitorService) that watches the system preference 
(Settings.System.MEDIA_BUTTON_RECEIVER). Whenever another package calls 
registerMediaButtonEventReceiver, AudioService updates that preference with the 
name of the class. So when MediaButtonMonitorService sees the preference change 
(and it isn't set to MediaButtonReciever), it changes it back to 
MediaButtonReceiver.

2. My Bluetooth device on ICS is sending different key codes when I press the 
media button. It's sending KEYCODE_MEDIA_PLAY (126) and KEYCODE_MEDIA_PAUSE 
(127). The latest version of Music has been fixed to work with these, but not 
older apps like Listen. I just adjusted the places where MediaButtonConfigure 
looks at the key codes to convert either of these key codes to 
KEYCODE_MEDIA_PLAY_PAUSE which works with both.

Original comment by pet...@sapros.com on 24 Dec 2011 at 4:52

Attachments:

GoogleCodeExporter commented 9 years ago
I forgot one more issue I had. In MediaButtonReceiver, it only looks for apps 
that have foreground set to true. That never worked for me. I had to take the 
foreground checks to get things to work, but I'm not really sure why.

Original comment by pet...@sapros.com on 24 Dec 2011 at 4:56

GoogleCodeExporter commented 9 years ago
Thank you so much for continuing to work on this project.  It is much safer
to use my phone while driving with this app.

Ryan Quellet

Original comment by rquel...@gmail.com on 24 Dec 2011 at 4:57

GoogleCodeExporter commented 9 years ago
Thanks Peter! I had no idea you could listen for an event to be informed when 
another app calls registerMediaButtonEventReceiver. That was my major hangup, 
having a way to always be on top of the stack without running a service that 
blindly re-registered itself every couple seconds. Is 
Settings.System.MEDIA_BUTTON_RECEIVER documented anywhere? I'm curious. 

The foreground check was just when I was guessing which app was currently 
playing music. It wasn't always used. I can make it a preference to disable 
this foreground check. Also, with this patch and ICS, I can always just 
de-register media button router when music is playing and re-fire the event. 
Then the receiver on the stack right below will get the event. This should be 
the correct media player in ICS since apparently media players that don't 
register themselves via registerMediaButtonEventReceiver don't get events.

Thanks for also informing me about the other key codes, I had no idea.

I'll test this out and try to release an updated media button receiver early 
January (if not sooner). 

Original comment by harleens...@gmail.com on 24 Dec 2011 at 5:06

GoogleCodeExporter commented 9 years ago
I had to go combing through the Android source code to figure it out. I don't 
think it's documented. It's a hack. The AudioService is just saving that value 
so that if the audio settings get reloaded (on a restart or whatever), it loads 
the same media button receiver. Since Android has a callback for watching 
settings, you get pretty much the effect of getting notified any time another 
service calls registerMediaButtonEventReceiver because every time that gets 
called AudioService updates the system setting.

Original comment by pet...@sapros.com on 24 Dec 2011 at 5:22

GoogleCodeExporter commented 9 years ago
Your last comment explains why it was sometimes starting Music whenever Listen 
was playing audio and I hit the button to stop it. Without the .foreground 
stuff its guesses about who was playing audio were wrong. So I went ahead and 
implemented your other idea. I couldn't figure out a good way to re-fire the 
event to the next receiver on the stack because we don't really have access to 
the stack. Instead I had the MediaButtonMonitorService store the value of the 
system preference whenever another app updated it and put in an app preference 
variable and then the MediaButtonReceiver takes a look at that and uses that to 
figure out who to pass the event on to. Seems to work well.

Original comment by pet...@sapros.com on 24 Dec 2011 at 6:42

Attachments:

GoogleCodeExporter commented 9 years ago
Thank you all for your efforts to fix this! 

Original comment by mi...@google.com on 24 Dec 2011 at 6:43

GoogleCodeExporter commented 9 years ago
I've incorporated Peter's changes. The big thing that remains and that I'm 
working on is getting list navigation in the selector to work again with the 
previous, next, and play buttons.

Original comment by harleens...@gmail.com on 24 Dec 2011 at 4:40

GoogleCodeExporter commented 9 years ago
I've fixed the problem with the list navigation in the selector. I ended up 
just having the MediaButtonReceiver just broadcast every media button event it 
gets. Then the 
ReceiverSelector just listens for that broadcast the same way it did the 
original media button broadcast. It seems to work okay, but the text to speech 
audio doesn't trigger after it changes the selection for some reason I haven't 
figured out yet.

I made this patch using 'hg export' this time (I'm new to Mercurial, so I was 
just using diff before). That might make it easier for you to pull it in. I 
think the MediaButtonMonitorService.java file didn't make it into your last 
commit.

Original comment by pet...@sapros.com on 26 Dec 2011 at 6:11

Attachments:

GoogleCodeExporter commented 9 years ago
Taking out the textToSpeech.stop(); line in ReceiverSelector.onPause fixes the 
audio problems for me.

Original comment by pet...@sapros.com on 26 Dec 2011 at 6:36

GoogleCodeExporter commented 9 years ago
Thanks Peter. Instead of taking textToSpeech.stop() in 
ReceiverSelector.onPause, I changed the MedaiButtonReceiver so that if the 
selector is open, it just broadcasts the custom action you created, and 
returns. Otherwise, what was happening is the receiver would get the custom 
action, but then also be shown (paused/resumed) again by the showSelector logic 
in the receiver. 

Original comment by harleens...@gmail.com on 26 Dec 2011 at 7:32

GoogleCodeExporter commented 9 years ago
Fixed in version 1.3.0 (should be on market shortly)

Original comment by harleens...@gmail.com on 26 Dec 2011 at 11:53