2012-09-24 7 views
7

Al enviar un sendOrderedBroadcast con un ACTION_MEDIA_BUTTON intento (imito que el usuario está haciendo clic en el botón Reproducir en un auricular bluetooth), Google Play Music abre y reproduce el último álbum reproducido en lugar de la aplicación de reproducción de música en primer plano.¿Google Play Music está acaparando todos los intentos de ACTION_MEDIA_BUTTON?

Si lo cambio a sendBroadcast, tanto Google Play Music como la aplicación de reproducción de música actual (Pandora en mi caso), representarán el botón de reproducción.

Esto solo ocurre en Android 4.0 y superior. ¿Play Music está acaparando este intento (un error)? ¿Sospecha que Pandora no se está registrando como el gestor de botones de medios actual siguiendo este consejo: http://android-developers.blogspot.com/2010/06/allowing-applications-to-play-nicer.html

¿Hay alguna manera de dirigir esta intención a la aplicación de reproducción de música actual solamente?

Aquí está mi código:

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

} 
+0

http://code.google.com/p/android/issues/detail?id=23272 – joepetrakovich

Respuesta

2

Existe una API que usted tiene que utilizar para ser el receptor preferido de esos intentos, pero que por supuesto puede ser manejado por el remitente de las teclas del sistema. Mire this post, y the docs. Pero eso depende de pandora y google music en este caso, por lo que probablemente no sea tu decisión. Por supuesto, también puede enviar sus transmisiones a un paquete en particular (especificando el nombre del componente en la intención), pero luego decide qué aplicación lo obtiene. Hice una búsqueda rápida de una API oculta en AudioManager, pero eso no parece prometedor.

¿Has probado con un accesorio? Si eso funciona, entonces analizaría cómo se envía esa intención. De lo contrario, verificaría qué aplicaciones están instaladas y haré una suposición "inteligente" o le preguntaré a qué aplicación enviar el intento. Tal vez la última es la mejor manera de entrar en cualquiera de los casos, ya que utiliza las API públicas y no molestar al usuario adivinando mal :)

Editar: Esto podría funcionar, pero puede también tener vigilancia por los permisos y certificados. En la pantalla de bloqueo se trata de cómo se manejan los medios de comunicación claves:

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

Sin embargo, la API está oculto por lo que tendría que trabajar alrededor de eso. Eso es probablemente lo mejor que puedo ayudarte. La alternativa es inyectar los eventos. Una forma de hacerlo es convertirse en un método de entrada, pero no es probable que sea un camino a seguir. Hay varias maneras de inyectar eventos a su propia actividad, pero no conozco ninguna que se inyecte en el sistema. Tal vez puedas echar un vistazo a cómo lo están haciendo las pruebas de instrumentación.

+0

No he probado con un accesorio porque yo no tengo uno. Ojalá lo hubiera hecho ¿Hay alguna manera de descubrir el nombre del componente de la aplicación de reproducción de música actual? No sé si es posible hacer una suposición inteligente ya que enviar una transmisión ordenada depende de la prioridad de la aplicación. Asumo que eventualmente las otras aplicaciones como Pandora se actualizarán a la nueva API ... – joepetrakovich

+0

Puedes ver siempre qué aplicaciones se están ejecutando usando [ActivityManager.getRunningTasks (int)] (http://developer.android.com/reference/android/ app/ActivityManager.html # getRunningTasks (int)) pero como usuario prefiero la configuración (quizás una copia de seguridad con algunos "AI" para proporcionar sugerencias y/o valores predeterminados). También existe la alternativa de buscar en los registros, pero no lo propongo ya que es muy poco confiable. Para probar sin un accesorio puede mirar [aquí] (http://code.google.com/p/media-button-router/wiki/TestingWithoutBluetooth) Aunque no he probado esto. –

+0

Así que pude probar con un accesorio real. Funciona correctamente con un auricular bluetooth de Samsung. La aplicación actual de primer plano, Pandora, responde a la pausa de reproducción y a los próximos botones de los auriculares. ¿Los auriculares tienen algún tipo de acceso especial? ¿Cómo puedo construir mi intención de actuar como si viniera de un auricular? – joepetrakovich

5

El siguiente debería hacer el truco. BTW, ¿dónde encontraste el código fuente de la pantalla de bloqueo?

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(); 
    } 
} 
+0

Hay una respuesta relacionada con esta que no refleja. simplemente usa AudioManager. http://stackoverflow.com/a/40493319/1713704 – MojAmiri

Cuestiones relacionadas