2012-09-24 11 views
7

Quando si invia un SendOrderedBroadcast con un intento ACTION_MEDIA_BUTTON (sto imitando che l'utente fa clic sul pulsante di riproduzione su un auricolare bluetooth), Google Play Music si apre e riproduce l'ultimo album riprodotto anziché l'app di riproduzione musicale in primo piano.Google Play Music esegue il hogging di tutti gli intenti ACTION_MEDIA_BUTTON?

Se lo cambio in sendBroadcast, sia Google Play Music che l'app di riproduzione musicale corrente (Pandora nel mio caso), eseguirà il pulsante di riproduzione.

Questo si verifica solo in Android 4.0 e oltre. Play Music sta intasando questo intento (un bug)? Sospetti che Pandora non si stia registrando come gestore di pulsante multimediale corrente seguendo questo consiglio: http://android-developers.blogspot.com/2010/06/allowing-applications-to-play-nicer.html

C'è un modo per indirizzare questo intento solo all'attuale app di riproduzione musicale?

Ecco il mio codice:

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

risposta

2

V'è un'API che si deve utilizzare per essere il ricevitore preferito di questi intenti, ma che può ovviamente essere gestita dal mittente dei tasti di sistema. Guarda this post e the docs. Ma in questo caso è la musica di Pandora e Google, quindi probabilmente non dipende da te. Ovviamente potresti anche inviare le tue trasmissioni ad un particolare pacchetto (specificando il nome del componente nell'intento), ma poi decidi quale app lo ottiene. Ho fatto una rapida ricerca di un'API nascosta nell'audioManager ma non sembra promettente.

Hai provato con un accessorio? Se funziona, vorrei esaminare come viene inviata quell'intenzione. In caso contrario, darei un'occhiata a quali applicazioni sono installate e fare un'ipotesi "intelligente" o chiedere all'utente a quale app inviare l'intento. Forse l'ultimo è il modo migliore per andare in entrambi i casi in quanto utilizza le API pubbliche e non infastidire l'utente indovinando sbagliato :)

Edit: Questo potrebbe funzionare, ma può anche essere protetto da autorizzazioni e certificati. Nel lockscreen questo è come i tasti multimediali sono gestite:

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

Tuttavia, l'API è nascosto in modo che avrebbe dovuto lavorare intorno a quello. Questo è probabilmente il meglio che posso aiutarti. L'alternativa è iniettare gli eventi. Un modo per farlo è quello di diventare un metodo di input, ma non è probabile che sia una soluzione. Esistono diversi modi per iniettare eventi per la propria attività, ma non conosco alcuno che inietti al sistema. Forse puoi dare un'occhiata a come lo fanno i test di strumentazione.

+0

Non ho provato con un accessorio, perché non ho uno. Vorrei averlo fatto. C'è un modo per scoprire il nome del componente dell'attuale app di riproduzione musicale? Non so se è possibile fare un'ipotesi intelligente poiché l'invio di una trasmissione ordinata dipende dalla priorità dell'app. Presumo che alla fine le altre app come Pandora si aggiorneranno alla nuova API ... – joepetrakovich

+0

Puoi sempre vedere quali applicazioni sono in esecuzione usando [ActivityManager.getRunningTasks (int)] (http://developer.android.com/reference/android/ app/ActivityManager.html # getRunningTasks (int)) ma come utente preferisco le impostazioni (forse il backup con alcuni "AI" per fornire suggerimenti e/o valori predefiniti. C'è anche l'alternativa per cercare nei registri, ma non lo proporrei poiché è molto inaffidabile. Per il test senza un accessorio è possibile guardare [qui] (http://code.google.com/p/media-button-router/wiki/TestingWithoutBluetooth) Non ho ancora testato me stesso. –

+0

Quindi sono stato in grado di provare con un accessorio reale. Funziona correttamente utilizzando un auricolare bluetooth Samsung. L'attuale app in primo piano, Pandora, risponde alla pausa di riproduzione e ai pulsanti successivi sull'auricolare. Le cuffie hanno qualche tipo di accesso speciale? Come posso costruire il mio intento di agire come se provenisse da una cuffia? – joepetrakovich

5

Il seguente dovrebbe fare il trucco. BTW, dove hai trovato il codice sorgente per la schermata di blocco?

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

C'è una risposta relativa a questa che non riflette. semplicemente utilizza AudioManager. http://stackoverflow.com/a/40493319/1713704 – MojAmiri

Problemi correlati