Вывод мультимедийных кнопок 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, intent):
// 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" или моим кодом? Я полностью сбит с толку.
Обновление 8/32/2017
Я также создал тривиальный, но рабочий проект приложения, демонстрирующий проблему, см. Https://github.com/gregko/PlayerServiceSample. Этот проект отображает вывод LogCat, когда кнопка мультимедиа нажата на гарнитуру под Android 5.x до 7.x, но полностью не работает под Android 8 "Oreo".
Обновление 9/1/2017 В настоящее время открыта проблема в Android Issue Tracker, которую я отправил, на странице https://issuetracker.google.com/issues/65175978. Тем не менее, кнопки мультимедиа работают в нескольких приложениях для музыкальных плееров, которые я тестировал на Oreo, я просто не могу понять, что они делают по-другому, чтобы заставить их работать... Контекст моего приложения не играет музыку, но чтение вслух текста с текстом к речевому сервису, поэтому много кода из примеров музыкального проигрывателя не применяется.
Ответы
Ответ 1
Решаемые. На странице " Изменения поведения Android 8.0 " на странице Google мы находим этот текст:
В Android 8.0 (уровень API 26) обработка событий медиа-кнопок различна:
- Обработка кнопок мультимедиа в пользовательском интерфейсе не изменилась: приоритетные действия по-прежнему имеют приоритет при обработке событий с медиа-кнопками.
- Если активность переднего плана не обрабатывает событие кнопки мультимедиа, система направляет событие в приложение, которое недавно воспроизводило аудио локально. Активное состояние, флаги и состояние воспроизведения сеанса мультимедиа не учитываются при определении того, какое приложение принимает события кнопки мультимедиа.
- Если сеанс мультимедиа приложения был выпущен, система отправляет событие кнопки мультимедиа в приложение MediaButtonReceiver, если оно есть.
- Для каждого другого случая система отбрасывает событие кнопки мультимедиа.
Все, что мне нужно было сделать, чтобы сделать мою тривиальную пробную работу, было воспроизвести звук с помощью MediaPlayer. Очевидно, что воспроизведение звука с использованием 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 в этом отношении "по дизайну" и не будет исправлять его. Прочтите ответ в конце сообщения о проблеме, вышедшем выше. Должен сказать, я разочарован.