Improve idle and stale media session handling

* MediaManager: Use the inactive session if we're on an android version that allows it
* MediaManager: Clear the cache if no session is found
* Send the media key event to the inactive session, if any
* Otherwise, broadcast the media key event generically
This commit is contained in:
José Rebelo
2025-03-23 23:29:30 +00:00
committed by José Rebelo
parent b95f868bff
commit 57273d35bb
2 changed files with 57 additions and 15 deletions
@@ -23,8 +23,10 @@ import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
import android.media.session.MediaController;
import android.media.session.MediaSession;
import android.media.session.MediaSessionManager;
import android.media.session.PlaybackState;
import android.os.Build;
import android.os.SystemClock;
import android.view.KeyEvent;
@@ -89,11 +91,11 @@ public class GBMusicControlReceiver extends BroadcastReceiver {
final GBPrefs prefs = GBApplication.getPrefs();
final long eventTime = SystemClock.uptimeMillis();
if (prefs.getBoolean("pref_deprecated_media_control", false)) {
// Deprecated path - mb_intents works for some players and not others, and vice-versa
final long eventTime = SystemClock.uptimeMillis();
if (prefs.getBoolean("mb_intents", false)) {
String audioPlayer = getAudioPlayer(context);
@@ -116,11 +118,7 @@ public class GBMusicControlReceiver extends BroadcastReceiver {
context.sendOrderedBroadcast(upIntent, null);
} else {
LOG.debug("Sending key press {} generally", musicCmd);
final KeyEvent downEvent = new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, keyCode, 0);
audioManager.dispatchMediaKeyEvent(downEvent);
final KeyEvent upEvent = new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, keyCode, 0);
audioManager.dispatchMediaKeyEvent(upEvent);
broadcastMediaKeyEvent(eventTime, keyCode, audioManager);
}
} else {
try {
@@ -129,12 +127,28 @@ public class GBMusicControlReceiver extends BroadcastReceiver {
new ComponentName(context, NotificationListener.class)
);
if (controllers.isEmpty()) {
LOG.warn("No media controller found to handle {}", musicCmd);
return;
}
final MediaController controller;
final MediaController controller = controllers.get(0);
if (controllers.isEmpty()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
// Fallback to the one that would handle the media key event, if any
final MediaSession.Token mediaKeyEventSession = mediaSessionManager.getMediaKeyEventSession();
if (mediaKeyEventSession != null) {
LOG.debug("Got media key event session controller");
controller = new MediaController(context, mediaKeyEventSession);
} else {
LOG.warn("No fallback media controller found to handle {}, dispatching media key event", musicCmd);
broadcastMediaKeyEvent(eventTime, keyCode, audioManager);
return;
}
} else {
LOG.warn("No media controller found to handle {}, dispatching media key event", musicCmd);
broadcastMediaKeyEvent(eventTime, keyCode, audioManager);
return;
}
} else {
controller = controllers.get(0);
}
switch (musicCmd) {
case NEXT:
@@ -185,6 +199,14 @@ public class GBMusicControlReceiver extends BroadcastReceiver {
}
}
private static void broadcastMediaKeyEvent(final long eventTime, final int keyCode, final AudioManager audioManager) {
final KeyEvent downEvent = new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, keyCode, 0);
audioManager.dispatchMediaKeyEvent(downEvent);
final KeyEvent upEvent = new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, keyCode, 0);
audioManager.dispatchMediaKeyEvent(upEvent);
}
private static void sendPhoneVolume(final AudioManager audioManager) {
final int volumeLevel = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
final int volumeMax = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
@@ -21,8 +21,10 @@ import android.content.Context;
import android.media.AudioManager;
import android.media.MediaMetadata;
import android.media.session.MediaController;
import android.media.session.MediaSession;
import android.media.session.MediaSessionManager;
import android.media.session.PlaybackState;
import android.os.Build;
import androidx.annotation.Nullable;
@@ -92,11 +94,29 @@ public class MediaManager {
final List<MediaController> controllers = mediaSessionManager.getActiveSessions(
new ComponentName(context, NotificationListener.class)
);
final MediaController controller;
if (controllers.isEmpty()) {
LOG.debug("No media controller available");
return;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
// Fallback to the one that would handle the media key event, if any
final MediaSession.Token mediaKeyEventSession = mediaSessionManager.getMediaKeyEventSession();
if (mediaKeyEventSession != null) {
LOG.debug("Got media key event session controller");
controller = new MediaController(context, mediaKeyEventSession);
} else {
LOG.debug("No fallback media controller available");
bufferMusicSpec = null;
bufferMusicStateSpec = null;
return;
}
} else {
LOG.debug("No active media controller available");
bufferMusicSpec = null;
bufferMusicStateSpec = null;
return;
}
} else {
controller = controllers.get(0);
}
final MediaController controller = controllers.get(0);
bufferMusicSpec = extractMusicSpec(controller.getMetadata());
bufferMusicStateSpec = extractMusicStateSpec(controller.getPlaybackState());