3

I managed to get my headset buttons get recognized by my app when pressed, but one of the buttons needs to call a method that's in MyCustomActivity. The problem is onReceive's 1st parameter is a Context that cannot be cast to Activity and so I am forced to implement my BroadcastReceiver as an inner class inside MyCustomActivity.

So far so good but how do I register this inner MediaButtonEventReceiver in the manifest?

For the independent class, this was simple:

<receiver android:name=".RemoteControlReceiver">
    <intent-filter>
        <action android:name="android.intent.action.MEDIA_BUTTON" />
    </intent-filter>
</receiver>

What is the trick/syntax to do the same for MyCustomActivity's mReceiver?

  private BroadcastReceiver mReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context ctx, Intent intent) {
         // ...
        }
  }
Cœur
  • 37,241
  • 25
  • 195
  • 267
an00b
  • 11,338
  • 13
  • 64
  • 101

2 Answers2

5

You don't, if it's meant to be part of the Activity, you register it dynamically:

BroadcastReceiver receiver;

@Override
protected void onCreate (Bundle b)
{
  super.onCreate (b);
  IntentFilter filter = new IntentFilter(Intent.ACTION_MEDIA_BUTTON);    
  filter.setPriority(10000);  
  receiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context ctx, Intent intent) {
      // ...
    }
  };
  registerReceiver (receiver, filter);
}

Then don't forget to unregister in onPause() (to avoid leaking).

@Override
protected void onPause()
{ 
  try{
    unregisterReceiver (receiver);
  }
  catch (IllegalStateException e)
  {
    e.printStackTrace();
  }
  super.onPause();
}

This dynamic registration does mean however, that if your Activity isn't in the foreground, the button won't work. You can try unregistering in onDestroy() instead, but the surest way to avoid leaking is onPause().

Alternatively, to make the button respond no matter what, consider making a Service, and having that register your receiver.

A--C
  • 36,351
  • 10
  • 106
  • 92
  • Thanks! I thought that I tried this but seeing `new BroadcastReceiver()` instantiated again in onCreate(), I am going to try this one more time and report back how it worked. +1 for now. – an00b Feb 25 '13 at 01:26
  • Strange. I tried this approach but it doesn't work for some reason. What am I missing? – an00b Feb 25 '13 at 01:40
  • 1
    @an00b are you leaving the Activity? Remember we're unregistering in `onPause()` to avoid leaking. Also not working as in compiles but doesn't do anything when ran? I recomment making a Toast in `onReceive()` to check if the Receiver is being called at all. – A--C Feb 25 '13 at 01:42
  • It compiles & builds fine. It's the receiver that doesn't get called. I'm not leaving the activity. – an00b Feb 25 '13 at 02:10
  • @an00b maybe what CommonsWare is referring to is something like [this](http://stackoverflow.com/questions/11074345/registermediabuttoneventreceiver-handling-volume-buttons-issue) question. `AudioManager#registerMediaButtonEventReceiver()` And I don't really see what `Intent.ACTION_MEDIA_BUTTON` does differently on account of that being the static variable that holds the String `"android.intent.action.MEDIA_BUTTON"`. Still worth a try though. – A--C Feb 25 '13 at 02:15
  • 1
    It's the `filter.setPriority(10000);` that eventually did the trick. Interesting. Plus the `ACTION_MEDIA_BUTTON` instead of `MEDIA_BUTTON`, of course. – an00b Feb 25 '13 at 02:21
  • @an00b hmm, I wonder why this is an ordered broadcast, i'd expect it to be unordered. But nice that you found that out :D Hopefully this will help more people. – A--C Feb 25 '13 at 02:23
  • 2
    @A--C my guess why it is ordered is so that say answering/ending a phone call takes precedence over starting/pausing music. – Steven Byle Feb 25 '13 at 02:26
  • BTW, that above posted code works great in Android 2.x but [doesn't work in Android 4.1 (Jelly Bean)](http://stackoverflow.com/a/13576130/636571). Android Fragmentation Uggrrr... – an00b Feb 25 '13 at 03:33
  • 1
    @an00b This is interesting. I guess you can make the receiver start the Activity with with the singleTop flag so that the new Intent gets routed to `onNewIntent()` and update the UI There. – A--C Feb 25 '13 at 03:56
  • @A--C Due to the fact that your wonderful solution doesn't work in 4.1, I am [still searching for a solution](http://stackoverflow.com/q/15102028/636571) (or workaround). Do you have additional suggestions? Thanks. – an00b Feb 27 '13 at 00:44
  • 2
    @an00b might be wasteful, but have **this** Receiver make a *custom* broadcast for *another* BroadCastReceiver implemented by your Activity. – A--C Feb 27 '13 at 00:46
  • 2
    It's not wasteful if this is the only way to solve this problem. :) Why did Google choose to make our lives so miserable by eliminating goodies that were available in Android 2.x? – an00b Feb 27 '13 at 01:25
  • @an00b You don't by any chance have your updated 4.1 code readily avaialble as a project of some sort? I'm on a custom ROM and the media button refuses to work, so I need someone's working implementation to check :) – A--C Mar 01 '13 at 22:19
1

So far so good but how do I register this inner MediaButtonEventReceiver in the manifest?

You can't. You can register it dynamically by calling registerReceiver() on the activity, though.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Ouch! I thought that would be the case, so I tried the tip provided [here](http://stackoverflow.com/a/4805733/636571) but for some reason it didn't work. Must I `new BroadcastReceiver()` in onCreate() or can I do it when initializing a private data member mReceiver? – an00b Feb 25 '13 at 01:24
  • @an00b: Either way works. Usually I set up a private data member for the receiver. – CommonsWare Feb 25 '13 at 01:26
  • private data member for the receiver that's what I have too, but none of the 2 approaches work. I may be missing something simple but I don't know what it is. The key presses do not get directed to my inner receiver as in the standalone one. – an00b Feb 25 '13 at 01:41
  • 1
    @an00b: The media button may be special. Check out `AudioManager` -- I seem to recall there are some things you need to set up on there to get control from a running app. Normally, A--C's approach works fine. – CommonsWare Feb 25 '13 at 02:09
  • I suspected so. Perhaps I should be using a receiver class other than BroadcastReceiver? Is there a "MediaButtonEventReceiver"? Also, [this answer](http://stackoverflow.com/a/10917769/636571) says "use ACTION_MEDIA_BUTTON instead of MEDIA_BUTTON". – an00b Feb 25 '13 at 02:11
  • @an00b: Not that I am aware of. – CommonsWare Feb 25 '13 at 02:13