Reliably Pausing Media Playback System-Wide in And

2019-02-10 09:59发布

问题:

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!

回答1:

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);


回答2:

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);