Ensure Media3 play calls get FGS exemption
When a Media3 controller calls play on a Media3 session, the call is currently not routed through the platform session at all. This means the usual exemption to start a FGS for media controller interactions is not triggered. We can manually ensure this exemption is given by sending a custom platform command to the session. The Media3 session will never receive this command as it's not a known Media3 custom command. Sessions will see a single onConnect call with a platform controller from the sender app though. We can prevent this on newer versions of the code by dropping the onCommand call early. PiperOrigin-RevId: 679115247
This commit is contained in:
parent
50c879ee21
commit
f4eef88089
@ -94,6 +94,8 @@
|
|||||||
items are available for both, `MediaBrowser` and `MediaController`. See
|
items are available for both, `MediaBrowser` and `MediaController`. See
|
||||||
<a href="https://developer.android.com/training/cars/media#custom_browse_actions">Custom
|
<a href="https://developer.android.com/training/cars/media#custom_browse_actions">Custom
|
||||||
Browse actions of AAOS</a>.
|
Browse actions of AAOS</a>.
|
||||||
|
* Fix bug where a Media3 controller was sometimes unable to let a session
|
||||||
|
app start a foreground service after requesting `play()`.
|
||||||
* UI:
|
* UI:
|
||||||
* Make the stretched/cropped video in
|
* Make the stretched/cropped video in
|
||||||
`PlayerView`-in-Compose-`AndroidView` workaround opt-in, due to issues
|
`PlayerView`-in-Compose-`AndroidView` workaround opt-in, due to issues
|
||||||
|
@ -497,6 +497,8 @@ public final class MediaConstants {
|
|||||||
"androidx.media3.session.SESSION_COMMAND_ON_CAPTIONING_ENABLED_CHANGED";
|
"androidx.media3.session.SESSION_COMMAND_ON_CAPTIONING_ENABLED_CHANGED";
|
||||||
/* package */ static final String SESSION_COMMAND_REQUEST_SESSION3_TOKEN =
|
/* package */ static final String SESSION_COMMAND_REQUEST_SESSION3_TOKEN =
|
||||||
"androidx.media3.session.SESSION_COMMAND_REQUEST_SESSION3_TOKEN";
|
"androidx.media3.session.SESSION_COMMAND_REQUEST_SESSION3_TOKEN";
|
||||||
|
/* package */ static final String SESSION_COMMAND_MEDIA3_PLAY_REQUEST =
|
||||||
|
"androidx.media3.session.SESSION_COMMAND_MEDIA3_PLAY_REQUEST";
|
||||||
|
|
||||||
/* package */ static final String ARGUMENT_CAPTIONING_ENABLED =
|
/* package */ static final String ARGUMENT_CAPTIONING_ENABLED =
|
||||||
"androidx.media3.session.ARGUMENT_CAPTIONING_ENABLED";
|
"androidx.media3.session.ARGUMENT_CAPTIONING_ENABLED";
|
||||||
|
@ -137,6 +137,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
@Nullable private TextureView videoTextureView;
|
@Nullable private TextureView videoTextureView;
|
||||||
private Size surfaceSize;
|
private Size surfaceSize;
|
||||||
@Nullable private IMediaSession iSession;
|
@Nullable private IMediaSession iSession;
|
||||||
|
@Nullable private android.media.session.MediaController platformController;
|
||||||
private long currentPositionMs;
|
private long currentPositionMs;
|
||||||
private long lastSetPlayWhenReadyCalledTimeMs;
|
private long lastSetPlayWhenReadyCalledTimeMs;
|
||||||
@Nullable private PlayerInfo pendingPlayerInfo;
|
@Nullable private PlayerInfo pendingPlayerInfo;
|
||||||
@ -405,6 +406,13 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Util.SDK_INT >= 31 && platformController != null) {
|
||||||
|
// Ensure the platform session gets allow-listed to start a foreground service after receiving
|
||||||
|
// the play command.
|
||||||
|
platformController.sendCommand(
|
||||||
|
MediaConstants.SESSION_COMMAND_MEDIA3_PLAY_REQUEST, /* args= */ null, /* cb= */ null);
|
||||||
|
}
|
||||||
|
|
||||||
dispatchRemoteSessionTaskWithPlayerCommand(
|
dispatchRemoteSessionTaskWithPlayerCommand(
|
||||||
(iSession, seq) -> iSession.play(controllerStub, seq));
|
(iSession, seq) -> iSession.play(controllerStub, seq));
|
||||||
|
|
||||||
@ -2644,6 +2652,9 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
playerInfo = result.playerInfo;
|
playerInfo = result.playerInfo;
|
||||||
MediaSession.Token platformToken =
|
MediaSession.Token platformToken =
|
||||||
result.platformToken == null ? token.getPlatformToken() : result.platformToken;
|
result.platformToken == null ? token.getPlatformToken() : result.platformToken;
|
||||||
|
if (platformToken != null) {
|
||||||
|
platformController = new android.media.session.MediaController(context, platformToken);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
// Implementation for the local binder is no-op,
|
// Implementation for the local binder is no-op,
|
||||||
// so can be used without worrying about deadlock.
|
// so can be used without worrying about deadlock.
|
||||||
|
@ -280,8 +280,11 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
@Override
|
@Override
|
||||||
public void onCommand(String commandName, @Nullable Bundle args, @Nullable ResultReceiver cb) {
|
public void onCommand(String commandName, @Nullable Bundle args, @Nullable ResultReceiver cb) {
|
||||||
checkStateNotNull(commandName);
|
checkStateNotNull(commandName);
|
||||||
if (TextUtils.equals(MediaConstants.SESSION_COMMAND_REQUEST_SESSION3_TOKEN, commandName)
|
if (commandName.equals(MediaConstants.SESSION_COMMAND_MEDIA3_PLAY_REQUEST)) {
|
||||||
&& cb != null) {
|
// Ignore, no need to handle this command here.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (commandName.equals(MediaConstants.SESSION_COMMAND_REQUEST_SESSION3_TOKEN) && cb != null) {
|
||||||
cb.send(RESULT_SUCCESS, sessionImpl.getToken().toBundle());
|
cb.send(RESULT_SUCCESS, sessionImpl.getToken().toBundle());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user