6

The title makes this sound much simpler than it is.. I'm trying to broadcast an intent that will pause most music players.

I know I can use create a KeyEvent for that will broadcast KEYCODE_MEDIA_PLAY_PAUSE with this:

    long eventTime = SystemClock.uptimeMillis(); 
    Intent downIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
    KeyEvent downEvent = new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, 0);
    downIntent.putExtra(Intent.EXTRA_KEY_EVENT, downEvent); 
    ctx.sendOrderedBroadcast(downIntent, null);

And that works. It will pause the stock media player how I want it to, along with most other music players that support headphone play/pause buttons. But for some reason, it only works once with the stock music player. I can press the button to call this, and it'll pause music. If I start playing it again, and hit my pause button again, it doesn't work. Once I reboot the device, it'll work once again. But then, with Pandora, it works consistently as it should.

I thought I might be able to work around that and just pause without using a KeyEvent. I tried this with AudioManager and another intent:

    AudioManager mAudioManager = (AudioManager) ctx.getSystemService(Context.AUDIO_SERVICE);    
    if (mAudioManager.isMusicActive()) {
        Intent mediaIntent = new Intent("com.android.music.musicservicecommand");
        mediaIntent.putExtra("command", "pause");
        ctx.sendBroadcast(mediaIntent);
    }

And this also works, and it works consistently. But it's inherently fragile, because by sending the intent directly to the Android music player, that's the only player it'll work with. No control of Pandora, Last.FM, etc. and I need it to work with most music players.

I'm just not sure where to go next. I'm not picky about what kind of solution I'm given as long as it works. If you can help me make the KeyEvent work, fantastic, if you have some totally different solution, fantastic. I just want it to work! Thanks!

Geniusdog254
  • 65
  • 1
  • 4
  • Anything you do here be "inherently fragile". Moreover, there will be plenty of media players that will completely ignore this event. And it is entirely possible that someday the OS will start blocking faked `ACTION_MEDIA_BUTTON` events the way they block other similar faked events. If you are writing your own media player, use the audio focus features in `AudioManager` to acquire the audio focus. – CommonsWare Jun 30 '12 at 15:53
  • I'm not actually writing my own media player. I know there are plenty of fully functional apps on the Play Store that will stop music after a set amount of time, but I'm not particularly happy with any of them. I'm just trying to write my own take on one, and I need to be able to pause most music apps. – Geniusdog254 Jun 30 '12 at 15:57

3 Answers3

5

I ran across this as well. Thanks to your description of it, I think i understand what's going on. You send the keydown event, but never the keyup so to the system thinks the play/pause button is being continuously pressed. I used this piece of code successfully.

Intent mediaEvent = new Intent(Intent.ACTION_MEDIA_BUTTON);
KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PLAY); 
mediaEvent.putExtra(Intent.EXTRA_KEY_EVENT, event);
context.sendBroadcast(mediaEvent);

new Timer().schedule(new TimerTask() {
    @Override
    public void run() {
        Intent mediaEvent = new Intent(Intent.ACTION_MEDIA_BUTTON);
        KeyEvent event = new KeyEvent(KeyEvent.ACTION_UP,KeyEvent.KEYCODE_MEDIA_PLAY); 
        mediaEvent.putExtra(Intent.EXTRA_KEY_EVENT, event);
        context.sendBroadcast(mediaEvent);
    }
}, 100);
user997416
  • 51
  • 1
  • 3
  • Note the starting Android O, you'll need to send the intent explicitly (https://commonsware.com/blog/2017/04/11/android-o-implicit-broadcast-ban.html) – Sean Jan 01 '20 at 12:06
3

To pause system wide audio, you don't start an intent but rather request audio focus from the system.

So when you wish to pause everything do the following (suggested in onCreate):

//The Variables we'll need to create
AudioManager am;
OnAudioFocusChangeListener af;

//I do nothing with this listener, but it's required for the next step.
af = new OnAudioFocusChangeListener() {

      public void onAudioFocusChange(int focusChange) {
          if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
              // Lower the volume
          } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
              // Raise it back to normal
          }    
      }

}; 

//Do the actual pause
am = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
int request = am.requestAudioFocus(af,
    AudioManager.STREAM_MUSIC,
    AudioManager.AUDIOFOCUS_GAIN);

But don't forget to let go of focus using:

am.abandonAudioFocus(af);
Marcel Binder
  • 166
  • 10
Peter Brooks
  • 1,170
  • 9
  • 23
0

While Peter Brooks' answer does work, I found this works better since the pausing / playing is immediate. With Android 12, getting audio focus is slow as the audio fades out first.

AudioManager audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
audioManager.dispatchMediaKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PAUSE));
audioManager.dispatchMediaKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_PAUSE));

Solution initially found here: Get details of app playing audio

Flyview
  • 1,899
  • 1
  • 28
  • 46