首页 文章

始终接收所有Android媒体按钮事件的回调(即使其他应用正在播放音频)

提问于
浏览
5

Background Info: 我需要检测用户何时按下大多数耳机上的播放/暂停按钮(KEYCODE_MEDIA_PLAY_PAUSE) .

我拥有它主要使用MediaSessions,但当另一个应用程序开始播放音频时,我停止回调 .

这似乎是因为正在播放音频的应用创建了自己的MediaSession,而Android仅将KeyEvents发送到最新的MediaSession . 为了防止这种情况,我创建一个OnActiveSessionsChangedListener并在每次触发时创建一个新的MediaSession .

这确实有效,但每次我创建一个新的MediaSession时,监听器再次触发,所以我发现自己陷入了一个inf循环 .

My Question: 有谁知道我怎么做以下任何一个??:

  • 防止其他应用窃取我的媒体按钮焦点

  • 当我将媒体按钮焦点丢失到另一个应用程序时检测到,所以我只能创建一个新的MediaSession,而不是每当活动会话改变时

  • 检查我当前是否已经有媒体按钮焦点,所以我不必要地创建一个新的MediaSession

What didn't work:

音频效果_ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION上的_119_ BroadcastReceiver无法正常工作,因为应用必须手动触发广播,而许多应用,如NPR One不

  • AudioManager.OnAudioFocusChangeListener无效,因为它需要我有音频焦点

  • BroadcastReceiver在android.intent.action.MEDIA_BUTTON上具有最高优先级并调用abortBroadcast(),但当其他应用程序播放音频时,我的接收器未被触发 . 此外,其他应用程序也可以设置最高优先级 .

My Code:

mMediaSessionManager.addOnActiveSessionsChangedListener(controllers -> {
    boolean updateButtonReceiver = false;

    // recreate MediaSession if another app handles media buttons
    for (MediaController mediaController : controllers) {
        if (!TextUtils.equals(getPackageName(), mediaController.getPackageName())) {
            if ((mediaController.getFlags() & (MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS)) != 0L) {
                updateButtonReceiver = true;
            }
        }

    }

    if (updateButtonReceiver) {
        // using a handler with a delay of about 2 seconds because this listener fires very often.
        mAudioFocusHandler.removeCallbacksAndMessages(null);
        mAudioFocusHandler.sendEmptyMessageDelayed(0, AUDIO_FOCUS_DELAY_MS);
    }
}, ClickAppNotificationListener.getComponentName(this));

这是被触发的处理程序:

private final Handler mAudioFocusHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        if (mShouldBeEnabled) {
            updateButtonReceiverEnabled(true);
        }
    }
};

最后,这是Handler触发的方法:

private void updateButtonReceiverEnabled(boolean shouldBeEnabled) {
    // clear old session (not sure if this is necessary)
    if (mMediaSession != null) {
        mMediaSession.setActive(false);
        mMediaSession.setFlags(0);
        mMediaSession.setCallback(null);
        mMediaSession.release();
        mMediaSession = null;
    }

    mMediaSession = new MediaSessionCompat(this, MEDIA_SESSION_TAG);
    mMediaSession.setCallback(mMediaButtonCallback);
    mMediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
    mMediaSession.setPlaybackToLocal(AudioManager.STREAM_MUSIC);
    mMediaSession.setActive(true);
    mMediaSession.setPlaybackState(new PlaybackStateCompat.Builder()
            .setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE)
            .setState(PlaybackStateCompat.STATE_CONNECTING, 0, 0f)
            .build());

    if (shouldBeEnabled != mShouldBeEnabled) {            
        getPackageManager().setComponentEnabledSetting(mMediaButtonComponent,
                shouldBeEnabled
                        ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
                        : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                PackageManager.DONT_KILL_APP);
    }

    mShouldBeEnabled = shouldBeEnabled;
}

谢谢!

2 回答

  • 2

    如果您只想捕获 MediaButton ,您可以注册 BroadcastReceiver 以始终获取媒体按钮操作 .

    MediaButtonIntentReceiver类:

    public class MediaButtonIntentReceiver extends BroadcastReceiver {
    
      public MediaButtonIntentReceiver() {
        super();
        }
    
     @Override
     public void onReceive(Context context, Intent intent) {
         String intentAction = intent.getAction();
         if (!Intent.ACTION_MEDIA_BUTTON.equals(intentAction)) {
            return;
           }
         KeyEvent event =   (KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
         if (event == null) {
            return;
           }
         int action = event.getAction();
         if (action == KeyEvent.ACTION_DOWN) {
              // do something
           Toast.makeText(context, "BUTTON PRESSED!", Toast.LENGTH_SHORT).show(); 
            }
        abortBroadcast();
      }
    }
    

    将其添加到manifest.xml:

    <receiver android:name=".MediaButtonIntentReceiver">
        <intent-filter>
            <action android:name="android.intent.action.MEDIA_BUTTON" />
        </intent-filter>
    </receiver>
    

    并注册你的 BroadcastReceiver (在主要活动中)

    IntentFilter filter = new IntentFilter(Intent.ACTION_MEDIA_BUTTON);
    MediaButtonIntentReceiver r = new MediaButtonIntentReceiver();
    filter.setPriority(1000); 
    registerReceiver(r, filter);
    

    还看看:

    How to capture key events from bluetooth headset with android

    How do I intercept button presses on the headset in Android?

  • 1

    您在 OnActiveSessionsChangedListener 中获得的 controllers 按优先顺序排序 . 如果您发现 MediaSession 不是列表中的第一个,则只需创建一个新的 MediaSession .

    请注意,如果有另一个应用程序使用相同的方法争用媒体键事件,您可能仍会遇到无限循环 .

相关问题