始终接收所有Android媒体按钮事件的回调(即使其他应用正在播放音频) [英] Receive callback on all Android media button events all the time (even when another app is playing audio)

查看:112
本文介绍了始终接收所有Android媒体按钮事件的回调(即使其他应用正在播放音频)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Background Info: I need to detect whenever a user presses the play/pause button found on most headsets (KEYCODE_MEDIA_PLAY_PAUSE).

我大多数情况下都使用MediaSessions完成它们,但是当另一个应用程序开始播放音频时,我就停止了回调.

I have it all mostly working using MediaSessions, but when another app starts playing audio, I stop getting callbacks.

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

It seems like this is because the app that's playing audio created its own MediaSession and Android sends KeyEvents only to the newest MediaSession. To prevent this I create an OnActiveSessionsChangedListener and create a new MediaSession every time it fires.

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

This does work, but every time I create a new MediaSession, the listener fires again, so I find myself stuck in an inf loop.

我的问题:有人知道我该怎么做吗?

My Question: does anyone know how I can do any of the following??:

  • 防止其他应用窃取我的媒体按钮焦点
  • 当我将媒体按钮的焦点丢失到另一个应用程序时进行检测,因此我只能在那时创建一个新的MediaSession,而不是在每次激活时创建一个新的MediaSession会话发生变化
  • 检查我当前是否已经具有媒体按钮焦点,所以我不必要地创建一个新的MediaSession

什么不起作用:

  • BroadcastReceiver已开启AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION无效因为应用必须手动触发该广播以及许多应用,像NPR One一样
  • AudioManager.OnAudioFocusChangeListener无法正常工作,因为它需要我音频焦点
  • 在android.intent.action.MEDIA_BUTTON&调用abortBroadcast(),但是当其他应用播放音频时,未触发我的接收器.此外,其他应用程序也可以设置最高优先级.

我的代码:

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

以下是触发的处理程序:

Here is the handler that gets triggered:

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

最后是处理程序触发的方法:

And finally here is the method that the Handler triggers:

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

谢谢!

推荐答案

如果您只想捕获 MediaButton ,则可以注册 BroadcastReceiver 来获取Media Button的所有操作.时间 .

if you just want to capture MediaButton you can register a BroadcastReceiver to get Media Button action all the time .

MediaButtonIntentReceiver类:

MediaButtonIntentReceiver class :

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:

add this to manifest.xml:

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

并这样注册您的 BroadcastReceiver (在主要活动中)

and register your BroadcastReceiver like this ( in main activity)

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

另请参阅:

如何使用以下命令从蓝牙耳机捕获关键事件android

如何拦截按钮按下Android中的耳机?

这篇关于始终接收所有Android媒体按钮事件的回调(即使其他应用正在播放音频)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆