Android "O"(奥利奥,8)和更高版本的媒体按钮问题

Android "O" (Oreo, 8) and higher media buttons issue

我在 Text-to-Speech 应用程序中使用的用于处理耳机媒体按钮的代码在 Android API 22 到 25(在旧版本 Android它们由其他现在已贬值的方式处理)。但是在 Android 8 "Oreo" 下,public beta 和最终版本都不起作用。这是相关代码:

服务启动时,我创建 MediaSessionCompact 对象:

        mSession = new MediaSessionCompat(getApplicationContext(), "my.package.name._player_session");
        mSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
        mSession.setActive(true);
        mSession.setCallback(myMediaSessionCallback);
        PlaybackStateCompat state = new PlaybackStateCompat.Builder()
                .setActions(ACTION_PLAY_PAUSE | ACTION_PLAY | ACTION_PAUSE |
                        ACTION_SKIP_TO_NEXT | ACTION_SKIP_TO_PREVIOUS |
                        ACTION_FAST_FORWARD | ACTION_REWIND
                )
                .setState(PlaybackStateCompat.STATE_PAUSED, 0 /*PlaybackStateCompat.PLAYBACK_POSITION_UNKNOWN*/, 1f)
                .build();
        mSession.setPlaybackState(state);

当然有会话媒体回调定义:

private MediaSessionCompat.Callback myMediaSessionCallback = new MediaSessionCompat.Callback() {
    @Override
    public boolean onMediaButtonEvent(Intent mediaButtonIntent) {
        // The log output below never appears on "Oreo", nothing comes here.
        Log.d(TAG, "callback onMediaButtonEvent() Compat");
        MediaButtonIntentReceiver.handleIntent(mediaButtonIntent.getAction(), (KeyEvent) mediaButtonIntent.getParcelableExtra(Intent.EXTRA_KEY_EVENT));
        return true;
    }

    @Override
    public void onSkipToNext() {
        //...
    }
    // etc. other overrides
};

我还尝试了 PendingIntent,使用 MediaButtonReceiver.buildMediaButtonPendingIntent() 并为我感兴趣的所有操作设置 mSession.setMediaButtonReceiver(pendingIntent),然后在我的服务 onStartCommand() 中调用 MediaButtonReceiver.handleIntent(mSession, 意图):

// still in the same service:            
mSession.setMediaButtonReceiver(
            MediaButtonReceiver.buildMediaButtonPendingIntent(
                this,
                mMediaButtonReceiverComponentName,
                ACTION_PLAY));


mSession.setMediaButtonReceiver(
            MediaButtonReceiver.buildMediaButtonPendingIntent(
                this,
                mMediaButtonReceiverComponentName,
                ACTION_PAUSE));


mSession.setMediaButtonReceiver(
            MediaButtonReceiver.buildMediaButtonPendingIntent(
                this,
                mMediaButtonReceiverComponentName,
                ACTION_PLAY_PAUSE));

并在服务 onStartCommand() 中:

@Override 
public int onStartCommand(Intent intent, int flags, int startId) {
    // ...
    if (intent != null) {
        MediaButtonReceiver.handleIntent(mSession, intent);
        // ...
    }
    return START_NOT_STICKY;
}

没什么,媒体按钮按下事件完全愚蠢。 "O" 或我的代码有什么问题???我完全莫名其妙。

2017 年 8 月 32 日更新

我还创建了一个简单但有效的应用程序项目来演示该问题,请参阅:https://github.com/gregko/PlayerServiceSample。当在 Android 5.x 到 7.x 下按下耳机上的媒体按钮时,此项目显示 LogCat 输出,但在 Android 8 [=40= 下完全失败].

2017 年 9 月 1 日更新 Android Issue Tracker 上现在有一个关于此的未解决问题,我在 https://issuetracker.google.com/issues/65175978 提交了该问题。媒体按钮在我在 Oreo 上测试过的几个音乐播放器应用程序中仍然有效,我只是无法弄清楚它们做了什么不同才能使它们工作......我的应用程序的上下文不是播放音乐,而是使用 Text 大声朗读文本到语音服务,因此音乐播放器示例中的很多代码不适用。

已解决。在“Android 8.0 Behavior Changes”Google 页面上,我们找到以下文本:

In Android 8.0 (API level 26) the handling of media button events is different:

  1. The handling of media buttons in a UI activity has not changed: foreground activities still get priority in handling media button events.
  2. If the foreground activity does not handle the media button event, the system routes the event to the app that most recently played audio locally. The active status, flags, and playback state of a media session are not considered when determining which app receives media button events.
  3. If the app's media session has been released, the system sends the media button event to the app's MediaButtonReceiver if it has one.
  4. For every other case, the system discards the media button event.

要使我的简单示例工作,我所要做的就是使用 MediaPlayer 播放一些声音。显然用文本转语音 API 播放声音不合格,在我看来这是一个错误。

这是我添加到我的简单示例中以使其工作的代码,从原始资源目录播放一个非常简短且无声的 WAV 文件:

    final MediaPlayer mMediaPlayer;
    mMediaPlayer = MediaPlayer.create(this, R.raw.silent_sound);
    mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
        @Override
        public void onCompletion(MediaPlayer mediaPlayer) {
            mMediaPlayer.release();
        }
    });
    mMediaPlayer.start();

更新

已将错误报告提交给 Android 问题跟踪器 https://issuetracker.google.com/issues/65344811

2017 年 10 月 10 日更新 2

Google 现在说奥利奥在这方面的行为是“设计使然”的,不会修复它。阅读上面问题跟踪器 post 末尾附近的回复。我必须说我很失望。