Проблема с мультимедийными кнопками Android O (Oreo, 8) и более поздних версий

Код для обработки мультимедийных кнопок на гарнитурах, которые я использую в своем приложении для преобразования текста в речь, отлично работает в Android API версий 22–25 (в более старых версиях Android они обрабатываются другими, ныне устаревшими средствами). Однако в Android 8 «Oreo», как в общедоступной бета-версии, так и в финальной версии, это не работает. Вот соответствующий код:

Когда служба запускается, я создаю объект 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;
}

Ничего, совсем тупо медиа кнопочки нажимать события. Что не так с "О" или моим кодом??? Я совершенно сбит с толку.

Обновление от 32 августа 2017 г.

Я также создал тривиальный, но работающий проект приложения, демонстрирующий проблему, см.: https://github.com/gregko/PlayerServiceSample. Этот проект отображает выходные данные LogCat при нажатии кнопки мультимедиа на гарнитуре под Android 5.x–7.x, но полностью не работает под Android 8 «Oreo».

Обновление от 01 сентября 2017 г. Теперь в системе отслеживания проблем Android есть открытая проблема, которую я отправил по адресу https://issuetracker.google.com/issues/65175978. Тем не менее, кнопки мультимедиа работают в нескольких приложениях музыкальных проигрывателей, которые я тестировал на Oreo, я просто не могу понять, что они делают по-другому, чтобы заставить их работать... Контекст моего приложения не воспроизводит музыку, а читает вслух текст с текстом к службе речи, поэтому большая часть кода из примеров музыкального проигрывателя не применима.


person gregko    schedule 30.08.2017    source источник
comment
Поскольку я решил проблему самостоятельно вскоре после публикации награды, теперь награда должна быть эффективно закрыта. Я не вижу способа сделать это здесь, так что давайте посмотрим, что произойдет...   -  person gregko    schedule 02.09.2017


Ответы (1)


Решено. На странице Android 8.0 Behavior Changes мы находим этот текст. :

В Android 8.0 (уровень API 26) обработка событий медиа-кнопки отличается:

  1. Обработка медиа-кнопок в действиях пользовательского интерфейса не изменилась: активные действия по-прежнему имеют приоритет при обработке событий медиа-кнопок.
  2. Если действие переднего плана не обрабатывает событие кнопки мультимедиа, система направляет событие в приложение, которое последним локально воспроизводило звук. Активный статус, флаги и состояние воспроизведения мультимедийного сеанса не учитываются при определении того, какое приложение получает события мультимедийной кнопки.
  3. Если мультимедийный сеанс приложения был освобожден, система отправляет событие мультимедийной кнопки в MediaButtonReceiver приложения, если он есть.
  4. Во всех остальных случаях система отбрасывает событие кнопки мультимедиа.

Все, что мне нужно было сделать, чтобы мой тривиальный образец заработал, это воспроизвести какой-нибудь звук с помощью MediaPlayer. По-видимому, воспроизведение звука с помощью Text-to-Speech API не подходит, что, на мой взгляд, является ошибкой.

Вот код, который я добавил к своему тривиальному образцу, чтобы заставить его работать, проигрывая очень короткий и тихий файл WAV из каталога Raw resources:

    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

Обновление 2, 10 октября 2017 г.

Теперь Google говорит, что поведение Oreo в этом отношении является преднамеренным и не исправит его. Прочтите ответ в конце сообщения об отслеживании проблем выше. Должен сказать, я разочарован.

person gregko    schedule 01.09.2017
comment
Удивительно, что это сработало. Много высоких пятерок для вас. Я надеюсь, что они исправят это. - person cottonBallPaws; 10.10.2017
comment
Ничего себе, вы только что решили проблему, которую я пытался в течение 4 дней! спасибо! - person the1900; 21.08.2019