20

I have this broadcast receiver for ACTION_MEDIA_BUTTON which actually works for both Android 2.x and Android 4.1, but for some strange reason, on Android 2.x (only), I get each even twice (for a single click on the pause button, of course):

public class RemoteControlReceiver extends BroadcastReceiver {
  private static long prevEventTime = 0;

  @Override
  public void onReceive(Context ctx, Intent intent) {
    if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())) {
      KeyEvent event = (KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
      long curEventTime = event.getEventTime();
      if (event != null && (event.getAction() == KeyEvent.ACTION_UP) /*&& (curEventTime != prevEventTime)*/) {
        int keycode = event.getKeyCode();
        switch (keycode)
        {
          case KeyEvent.KEYCODE_MEDIA_NEXT:
            Log.i(TAG, "KEYCODE_MEDIA_NEXT"); 
            break;
          case KeyEvent.KEYCODE_HEADSETHOOK:
            Log.i(TAG, "KEYCODE_HEADSETHOOK" + " " +  curEventTime + " <> " + prevEventTime + " (" + event.getAction() + ")");
            prevEventTime = curEventTime;
            break;
          case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
            Log.i(TAG, "KEYCODE_MEDIA_PREVIOUS"); 
            break;
          default:
        }
      }     
    }
  }

}

Attempting to understand the mystery, I log the event time for each such occurrence:

03-01 18:27:05.264: I/RemoteControlReceiver.onReceive(22377): KEYCODE_HEADSETHOOK 142304436 <> 0 (1)
03-01 18:27:05.434: I/RemoteControlReceiver.onReceive(22377): KEYCODE_HEADSETHOOK 142304436 <> 142304436 (1)

03-01 18:27:14.054: I/RemoteControlReceiver.onReceive(22377): KEYCODE_HEADSETHOOK 142313265 <> 142304436 (1)
03-01 18:27:14.074: I/RemoteControlReceiver.onReceive(22377): KEYCODE_HEADSETHOOK 142313265 <> 142313265 (1)

03-01 18:27:24.254: I/RemoteControlReceiver.onReceive(22377): KEYCODE_HEADSETHOOK 142323464 <> 142313265 (1)
03-01 18:27:24.264: I/RemoteControlReceiver.onReceive(22377): KEYCODE_HEADSETHOOK 142323464 <> 142323464 (1)

03-01 18:27:37.574: I/RemoteControlReceiver.onReceive(22377): KEYCODE_HEADSETHOOK 142336795 <> 142323464 (1)
03-01 18:27:37.614: I/RemoteControlReceiver.onReceive(22377): KEYCODE_HEADSETHOOK 142336795 <> 142336795 (1)

03-01 18:27:45.214: I/RemoteControlReceiver.onReceive(22377): KEYCODE_HEADSETHOOK 142344433 <> 142336795 (1)
03-01 18:27:45.284: I/RemoteControlReceiver.onReceive(22377): KEYCODE_HEADSETHOOK 142344433 <> 142344433 (1)

03-01 18:27:52.474: I/RemoteControlReceiver.onReceive(22377): KEYCODE_HEADSETHOOK 142351687 <> 142344433 (1)
03-01 18:27:52.504: I/RemoteControlReceiver.onReceive(22377): KEYCODE_HEADSETHOOK 142351687 <> 142351687 (1)

Again, this double-occurrence doesn't happen in Android 4.1. It only happens in Android 2.x.

Any idea why?

(while I can use the same event time logging technique to filter-out the second occurrence, I prefer to understand first what's happening (possible programming mistake on my side?) and to see whether there is a better solution for that)


Answering the question below: ("how exactly you register your receiver")

First in the app's manifest:

<receiver android:name="com.example.mylib.RemoteControlReceiver" android:enabled="true">
    <intent-filter android:priority="2147483647" >
        <action android:name="android.intent.action.MEDIA_BUTTON" />
    </intent-filter>
</receiver>

Then, in my library's activity (per this tip), in OnCreate():

mRemoteControlReceiver = new ComponentName(this, RemoteControlReceiver.class);
mAudioManager.registerMediaButtonEventReceiver(mRemoteControlReceiver);

I hope this provides a more complete picture that can help solve this mystery.

Community
  • 1
  • 1
an00b
  • 11,338
  • 13
  • 64
  • 101
  • How exactly you register your receiver? – clover Mar 29 '13 at 23:48
  • Now I can't edit my bounty text (pathetic). By "I'm not using any library" I meant I'm not having more than an application registering the same listener. – matteo Nov 20 '14 at 22:08

3 Answers3

8

I noticed that you are using this receiver in a library (the "mylib" part in your manifest).

If this is indeed the case and you have that receiver registered by two applications sharing the same registration code, you will see those events twice.

If three applications register that receiver, you will receive those events tripled...

Make sure that each application uses a different (unique) <receiver android:name.

scatmoi
  • 1,958
  • 4
  • 18
  • 32
  • Not my case, and I do observe the issue. I only have the filter defined in the manifest. This only occurs in Android 2.x. This is obviously a bug, as I have verified my own receiver is instantiated and fired twice (twice for UP and twice for DOWN) and it is registered only one (checked via PackageManager.queryBroadcastReceivers. Is the workaround of checking the event time reliable and is it the only one? – matteo Nov 20 '14 at 21:58
6

I ran across this issue and spent a while banging my head against the wall before I realized that each press of the button generates two events: a KeyEvent.ACTION_DOWN, and a KeyEvent.ACTION_UP. So two tests are needed to use a media button:

if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())) {}

and

if (event.getAction() == KeyEvent.ACTION_DOWN) {}

So if anyone else finds themselves here as a result of the same mistake, perhaps this reply will help.

Tad
  • 4,668
  • 34
  • 35
0

For ensuring that it's the first time always you can use a flag to tell that it's the first action.

boolean firstAction= false;
if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())) {
    firstAction= !firstAction;
    if(!firstAction)
    {
        return true;
    }

    KeyEvent event = (KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
    long curEventTime = event.getEventTime();
    if (event != null && (event.getAction() == KeyEvent.ACTION_UP) /*&& (curEventTime != prevEventTime)*/) {
        int keycode = event.getKeyCode();
        switch (keycode)
        {
          case KeyEvent.KEYCODE_MEDIA_NEXT:
            Log.i(TAG, "KEYCODE_MEDIA_NEXT"); 
            break;
          case KeyEvent.KEYCODE_HEADSETHOOK:
            Log.i(TAG, "KEYCODE_HEADSETHOOK" + " " +  curEventTime + " <> " + prevEventTime + " (" + event.getAction() + ")");
            prevEventTime = curEventTime;
            break;
          case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
            Log.i(TAG, "KEYCODE_MEDIA_PREVIOUS"); 
            break;
          default:
        }
    }     
}
Mohamed
  • 761
  • 9
  • 19
  • Note the commented out `/*&& (curEventTime != prevEventTime)*/` in my original code: This already works around the problem described above. What I was asking is **why** this is happening, not how to workaround the problem. Thanks for trying to help. :) – an00b Apr 05 '13 at 00:36