7

I am trying to receive the physical button events such as volume button clicks on the side of the phone. I need to do that in a Service because I want to receive if the user clicks on the Volume up/down button at any time. I read a lot in the net, but I cannot make it work and don't know what could be wrong. This is my code:

In the Manifest:

    <receiver android:name=".clsMediaButtonReceiver" >
        <intent-filter android:priority="1000" >
            <action android:name="android.intent.action.MEDIA_BUTTON" />               
        </intent-filter>
    </receiver>  

In the service OnStart():

   AudioManager manager = (AudioManager) getSystemService(AUDIO_SERVICE);
   manager.registerMediaButtonEventReceiver(new ComponentName(getPackageName(), clsMediaButtonReceiver.class.getName())); 

An the broascastreceiver:

public class clsMediaButtonReceiver extends BroadcastReceiver
{  

   @Override public void onReceive(Context context, Intent intent)
   {  //This is never shown
      Toast toast1 = Toast.makeText(Context, intent.getAction(), Toast.LENGTH_SHORT);
      toast1.show();
   }

} 
Ton
  • 9,235
  • 15
  • 59
  • 103
  • @Hi Ton, Which android version is allowing you to use registerMediaButtonEventReceiver()? Actually I want to use this in my app, but its not compiling. It seems this method is not present in AudioManager. Can you plz reply? – Chandra Sekhar Aug 13 '13 at 06:41

3 Answers3

9

I added <action android:name="android.media.VOLUME_CHANGED_ACTION" /> to my intent filter and now i get the volume key events. I have yet to figure out how to distribute them properly in my app though... Hope it helps!

  • I now got my code working! I have a volume slider that wants to listen on music volume changes. I register a receiver like in the question (plus the action from my answer) and then broadcast events from that using a listener pattern. What I realized after some time of pulling my hair is that the receiver is not instantiated until an event is received. I bypassed this this by keeping a static list of listeners that other components could be registered to and that the receiver would use to broadcast events. – matrixsmurfen Jul 03 '13 at 11:07
  • Avoid static references. You may easily leak resources. For communication between a broadcast receiver and a service, implement onBind in your service and call peekService in your broadcast receiver's onReceive. I'd show you the code, but it's too long for a comment. – 0xF Jun 26 '14 at 07:34
4

I know that this is an old Question, I came across this same issue and found that we must register the registerMediaButtonEventReceiver(..) only after holding the AudioManager.AUDIOFOCUS_GAIN otherwise it is not working.

I tried with the same Manifest and BroadcastReciever written by @Ton

private class ClassOnAudioFocusChangeListener implements AudioManager.OnAudioFocusChangeListener {
    @Override
    public void onAudioFocusChange(int focusChange) {
         if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT){    
             Log.e("ClassOnAudioFocusChangeListener: ", "AUDIOFOCUS_LOSS_TRANSIENT");
         }
         else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
             Log.e("ClassOnAudioFocusChangeListener: ", "AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK");
         }
         else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
             Log.e("ClassOnAudioFocusChangeListener: ", "AUDIOFOCUS_GAIN");
              mAudioManager.registerMediaButtonEventReceiver(mMediaButtonEventComponenName);
         }
         else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
             Log.e("ClassOnAudioFocusChangeListener: ", "AUDIOFOCUS_LOSS");                              
         }
    }
};

Here is the same Manifest.

    <receiver 
        android:name="MainActivity$MediaButtonEventReceiver">           
        <intent-filter android:priority="1000" >
        <action android:name="android.intent.action.MEDIA_BUTTON" />               
        </intent-filter>
    </receiver>
mifthi
  • 151
  • 8
  • On Android L+ your suggestions work, but unregistering did not. I kept getting the events. Having the receiver with the full intent-filter and action declared in the manifest statically registers it, you cannot unregister it any more. Solution: define only the receiver in the manifest without the intent filter. Then you can register and unregister it dynamically in your code. – Habib Oct 30 '16 at 22:13
0

I've the same problem as you and I would like to know if you resolved it. The diference with my code is that I´ve the broadcastReceiver Class inside another Class. Something like that:

public class MyClass extends Activity 
{
    /// Code

    public class MediaButtonReceiver extends BroadcastReceiver
    {
         @Override
         public void onReceive(Context context, Intent intent)
         {
              /// Code
         }
    }
}

And the Manifest:

<receiver android:name="net.mypackage.MyClass.MediaButtonReceiver">
    <intent-filter android:priority="1000" >
        <action android:name="android.intent.action.MEDIA_BUTTON" />               
    </intent-filter>
</receiver>

Thanks for your help

Jafuentes
  • 365
  • 2
  • 6
  • 13
  • You cannot specify non-static inner class as a BroadcastReceiver in the Android manifest. See http://stackoverflow.com/questions/3608955/receiver-as-inner-class-in-android – 0xF Jun 26 '14 at 07:25