Is Google Play Music chasing all ACTION_MEDIA_BUTTON actions?

When you send sendOrderedBroadcast with the intent ACTION_MEDIA_BUTTON (I simulate that the user clicks the play button on the bluetooth headset), Google Play Music opens and plays the last album, which is played instead of the foreground application.

If I change it to sendBroadcast, both Google Play Music and the current music playback application (Pandora in my case), you can enter the play button.

This only happens in Android 4.0 and higher . Is Play Music a pursuit of this intention (mistake)? You suspect that Pandora is not registering as the current media player after this tip: http://android-developers.blogspot.com/2010/06/allowing-applications-to-play-nicer.html

Is there a way that I can direct this intention only to the current music playback application?

Here is my code:

public void broadcastMediaIntent(MediaIntent intentType){ long eventtime = SystemClock.uptimeMillis(); Intent downIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); Intent upIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); KeyEvent downEvent = null; KeyEvent upEvent = null; switch(intentType){ case NEXT: downEvent = new KeyEvent(eventtime, eventtime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_NEXT, 0); upEvent = new KeyEvent(eventtime, eventtime, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_NEXT, 0); break; case PLAY_PAUSE: downEvent = new KeyEvent(eventtime, eventtime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, 0); upEvent = new KeyEvent(eventtime, eventtime, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, 0); break; case PREVIOUS: downEvent = new KeyEvent(eventtime, eventtime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PREVIOUS, 0); upEvent = new KeyEvent(eventtime, eventtime, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_PREVIOUS, 0); break; case FAST_FORWARD: downEvent = new KeyEvent(eventtime, eventtime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_FAST_FORWARD, 0); upEvent = new KeyEvent(eventtime, eventtime, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_FAST_FORWARD, 0); break; case REWIND: downEvent = new KeyEvent(eventtime, eventtime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_REWIND, 0); upEvent = new KeyEvent(eventtime, eventtime, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_REWIND, 0); break; default: break; } downIntent.putExtra(Intent.EXTRA_KEY_EVENT, downEvent); sendOrderedBroadcast(downIntent, null); upIntent.putExtra(Intent.EXTRA_KEY_EVENT, upEvent); sendOrderedBroadcast(upIntent, null); } 
+7
source share
2 answers

There is an API that you should use to be the preferred receiver of these intentions, but this, of course, can be handled by the sender of the system keys. Check out this post and docs . But it depends on the pandora and the music of Google in this case, which is probably not up to you. Of course, you can also send your broadcasts to a specific package (by specifying the name of the component in the intent), but then you decide which application will receive it. I quickly looked through the hidden API in AudioManager, but that doesn't look promising.

Have you tried with the accessory? If this works, I will see how this intention is sent. If this is not the case, I would look at which applications are installed and either make an β€œintelligent” assumption or ask the user for which application to send the intent. Maybe the last one is the best way to go anyway, as it uses public APIs and will not annoy the user, guessing wrong :)

Edit: This can work, but can also be protected by permissions and certificates. In lockscreen, media keys are handled like this:

 void handleMediaKeyEvent(KeyEvent keyEvent) { IAudioService audioService = IAudioService.Stub.asInterface( ServiceManager.checkService(Context.AUDIO_SERVICE)); if (audioService != null) { try { audioService.dispatchMediaKeyEvent(keyEvent); } catch (RemoteException e) { Log.e("KeyguardViewBase", "dispatchMediaKeyEvent threw exception " + e); } } else { Slog.w("KeyguardViewBase", "Unable to find IAudioService for media key event"); } } 

However, the API is hidden, so you have to get around this. This is probably the best I can help you. An alternative is the introduction of events. One way to do this is to become an input method, but that is unlikely to be the direction. There are several ways to input events into your own activities, but I do not know any that introduce the system. Perhaps you can see how control tests do it.

+2
source

The following should do the trick. BTW, where did you find the source code of the lock screen?

  public void handleMediaKeyEvent(KeyEvent keyEvent) { /* * Attempt to execute the following with reflection. * * [Code] * IAudioService audioService = IAudioService.Stub.asInterface(b); * audioService.dispatchMediaKeyEvent(keyEvent); */ try { // Get binder from ServiceManager.checkService(String) IBinder iBinder = (IBinder) Class.forName("android.os.ServiceManager") .getDeclaredMethod("checkService",String.class) .invoke(null, Context.AUDIO_SERVICE); // get audioService from IAudioService.Stub.asInterface(IBinder) Object audioService = Class.forName("android.media.IAudioService$Stub") .getDeclaredMethod("asInterface",IBinder.class) .invoke(null,iBinder); // Dispatch keyEvent using IAudioService.dispatchMediaKeyEvent(KeyEvent) Class.forName("android.media.IAudioService") .getDeclaredMethod("dispatchMediaKeyEvent",KeyEvent.class) .invoke(audioService, keyEvent); } catch (Exception e1) { e1.printStackTrace(); } } 
+5
source

All Articles