【问题标题】:Is Google Play Music hogging all ACTION_MEDIA_BUTTON intents?Google Play 音乐是否占用了所有 ACTION_MEDIA_BUTTON 意图?
【发布时间】:2012-09-24 21:51:46
【问题描述】:

当发送带有 ACTION_MEDIA_BUTTON 意图的 sendOrderedBroadcast 时(我在模拟用户正在单击蓝牙耳机上的播放按钮),Google Play 音乐会打开并播放最后播放的专辑,而不是前台音乐播放应用程序。

如果我将其更改为 sendBroadcast,Google Play 音乐和当前的音乐播放应用(在我的例子中是 Pandora)都会启动播放按钮。

这只发生在 Android 4.0 及更高版本中。 Play Music 是否有这种意图(一个错误)?您是否怀疑 Pandora 没有按照以下建议将自己注册为当前的媒体按钮处理程序: http://android-developers.blogspot.com/2010/06/allowing-applications-to-play-nicer.html

有没有办法可以将这个意图只指向当前的音乐播放应用程序?

这是我的代码:

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

}

【问题讨论】:

标签: android android-intent


【解决方案1】:

以下应该可以解决问题。 BTW,你在哪里找到锁屏的源代码?

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

【讨论】:

【解决方案2】:

您必须使用一个 API 作为这些意图的首选接收者,但它当然可以由系统密钥的发送者处理。查看this postthe docs。但在这种情况下,这取决于潘多拉和谷歌音乐,所以这可能不取决于你。你当然也可以将你的广播发送到一个特定的包(通过在意图中指定组件名称),然后你决定哪个应用程序得到它。我在 AudioManager 中快速搜索了一个隐藏的 API,但这看起来并不乐观。

您是否尝试过使用配件?如果可行,那么我将研究如何发送该意图。如果没有,我会查看安装了哪些应用程序,然后进行“智能”猜测或询问用户要将意图发送到哪个应用程序。也许最后一个是两种情况下最好的方法,因为它使用公共 API,不会因为猜错而惹恼用户:)

编辑: 这可以工作,但它也可能受到权限和证书的保护。在锁屏中,媒体键的处理方式如下:

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

但是,API 是隐藏的,因此您必须解决这个问题。这可能是我能帮助你的最好的了。另一种方法是注入事件。做到这一点的一种方法是成为一种输入法,但这不太可能是一种前进的方式。有几种方法可以将事件注入到您自己的活动中,但我不知道任何注入系统的方法。也许你可以看看仪器测试是如何做到的。

【讨论】:

  • 我没有尝试过配件,因为我没有。希望我做到了。有没有办法找出当前音乐播放应用程序的组件名称?我不知道是否可以做出明智的猜测,因为发送有序广播取决于应用程序的优先级。我假设最终其他应用程序(如 Pandora)将更新到新的 API...
  • 您始终可以使用ActivityManager.getRunningTasks(int) 查看正在运行的应用程序,但作为用户,我更喜欢设置(可能会备份一些“AI”以提供建议和/或默认值。还有替代查看日志,但我不建议这样做,因为它非常不可靠。对于没有附件的测试,您可以查看 here 虽然我自己没有测试过这些。
  • 所以我可以尝试使用真正的配件。它使用三星蓝牙耳机正常工作。当前前台应用程序 Pandora 响应耳机上的播放暂停和下一步按钮。耳机是否有某种特殊的访问权限?我如何构建我的意图,让它仿佛来自耳机?
  • 使用您指向我的媒体按钮应用程序显示与我的应用程序相同的行为。 Google Play 只是弹出并使用意图,而不是 Pandora 或 Spotify。
  • 好的,发生的情况是潘多拉在音频服务(私有api)中注册自己,PhoneWindowManager(隐藏)调用音频服务来调用在注册期间创建的待处理意图。这一切都是隐藏的。但是如果你能以某种方式注入事件,看看会发生什么会很有趣。将它注入一个活动可能没有任何好处,这就是我迄今为止发现的 Activity.dispatchKeyEvent()。我会继续寻找。
猜你喜欢
  • 2013-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-29
  • 1970-01-01
相关资源
最近更新 更多