diff --git a/libraries/session/src/main/java/androidx/media3/session/ConnectionState.java b/libraries/session/src/main/java/androidx/media3/session/ConnectionState.java index 6752a386c3..afb57b623f 100644 --- a/libraries/session/src/main/java/androidx/media3/session/ConnectionState.java +++ b/libraries/session/src/main/java/androidx/media3/session/ConnectionState.java @@ -37,7 +37,9 @@ import java.lang.annotation.Target; */ /* package */ class ConnectionState implements Bundleable { - public final int version; + public final int libraryVersion; + + public final int sessionInterfaceVersion; public final IMediaSession sessionBinder; @@ -54,7 +56,8 @@ import java.lang.annotation.Target; public final PlayerInfo playerInfo; public ConnectionState( - int version, + int libraryVersion, + int sessionInterfaceVersion, IMediaSession sessionBinder, @Nullable PendingIntent sessionActivity, SessionCommands sessionCommands, @@ -62,7 +65,8 @@ import java.lang.annotation.Target; Player.Commands playerCommandsFromPlayer, Bundle tokenExtras, PlayerInfo playerInfo) { - this.version = version; + this.libraryVersion = libraryVersion; + this.sessionInterfaceVersion = sessionInterfaceVersion; this.sessionBinder = sessionBinder; this.sessionCommands = sessionCommands; this.playerCommandsFromSession = playerCommandsFromSession; @@ -78,7 +82,7 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.SOURCE) @Target(TYPE_USE) @IntDef({ - FIELD_VERSION, + FIELD_LIBRARY_VERSION, FIELD_SESSION_BINDER, FIELD_SESSION_ACTIVITY, FIELD_SESSION_COMMANDS, @@ -86,10 +90,11 @@ import java.lang.annotation.Target; FIELD_PLAYER_COMMANDS_FROM_PLAYER, FIELD_TOKEN_EXTRAS, FIELD_PLAYER_INFO, + FIELD_SESSION_INTERFACE_VERSION, }) private @interface FieldNumber {} - private static final int FIELD_VERSION = 0; + private static final int FIELD_LIBRARY_VERSION = 0; private static final int FIELD_SESSION_BINDER = 1; private static final int FIELD_SESSION_ACTIVITY = 2; private static final int FIELD_SESSION_COMMANDS = 3; @@ -97,12 +102,13 @@ import java.lang.annotation.Target; private static final int FIELD_PLAYER_COMMANDS_FROM_PLAYER = 5; private static final int FIELD_TOKEN_EXTRAS = 6; private static final int FIELD_PLAYER_INFO = 7; - // Next field key = 8 + private static final int FIELD_SESSION_INTERFACE_VERSION = 8; + // Next field key = 9 @Override public Bundle toBundle() { Bundle bundle = new Bundle(); - bundle.putInt(keyForField(FIELD_VERSION), version); + bundle.putInt(keyForField(FIELD_LIBRARY_VERSION), libraryVersion); BundleCompat.putBinder(bundle, keyForField(FIELD_SESSION_BINDER), sessionBinder.asBinder()); bundle.putParcelable(keyForField(FIELD_SESSION_ACTIVITY), sessionActivity); bundle.putBundle(keyForField(FIELD_SESSION_COMMANDS), sessionCommands.toBundle()); @@ -124,6 +130,7 @@ import java.lang.annotation.Target; /* excludeTimeline= */ false, /* excludeTracks= */ !playerCommandsFromPlayer.contains(Player.COMMAND_GET_TRACKS) || !playerCommandsFromSession.contains(Player.COMMAND_GET_TRACKS))); + bundle.putInt(keyForField(FIELD_SESSION_INTERFACE_VERSION), sessionInterfaceVersion); return bundle; } @@ -131,7 +138,9 @@ import java.lang.annotation.Target; public static final Creator CREATOR = ConnectionState::fromBundle; private static ConnectionState fromBundle(Bundle bundle) { - int version = bundle.getInt(keyForField(FIELD_VERSION), /* defaultValue= */ 0); + int libraryVersion = bundle.getInt(keyForField(FIELD_LIBRARY_VERSION), /* defaultValue= */ 0); + int sessionInterfaceVersion = + bundle.getInt(keyForField(FIELD_SESSION_INTERFACE_VERSION), /* defaultValue= */ 0); IBinder sessionBinder = checkNotNull(BundleCompat.getBinder(bundle, keyForField(FIELD_SESSION_BINDER))); @Nullable @@ -162,7 +171,8 @@ import java.lang.annotation.Target; ? PlayerInfo.DEFAULT : PlayerInfo.CREATOR.fromBundle(playerInfoBundle); return new ConnectionState( - version, + libraryVersion, + sessionInterfaceVersion, IMediaSession.Stub.asInterface(sessionBinder), sessionActivity, sessionCommands, diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java b/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java index aadc8a42d6..d217afa06e 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java @@ -2326,7 +2326,8 @@ import org.checkerframework.checker.nullness.qual.NonNull; new SessionToken( token.getUid(), TYPE_SESSION, - result.version, + result.libraryVersion, + result.sessionInterfaceVersion, token.getPackageName(), result.sessionBinder, result.tokenExtras); diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java b/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java index 196139e568..1bf05a7255 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java @@ -177,6 +177,7 @@ import org.checkerframework.checker.initialization.qual.Initialized; Process.myUid(), SessionToken.TYPE_SESSION, MediaLibraryInfo.VERSION_INT, + MediaSessionStub.VERSION_INT, context.getPackageName(), sessionStub, tokenExtras); diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaSessionStub.java b/libraries/session/src/main/java/androidx/media3/session/MediaSessionStub.java index cba32b5f44..7160d1e176 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaSessionStub.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaSessionStub.java @@ -102,6 +102,9 @@ import java.util.concurrent.ExecutionException; private static final String TAG = "MediaSessionStub"; + /** The version of the IMediaSession interface. */ + public static final int VERSION_INT = 1; + private final WeakReference sessionImpl; private final MediaSessionManager sessionManager; private final ConnectedControllersManager connectedControllersManager; @@ -446,6 +449,7 @@ import java.util.concurrent.ExecutionException; ConnectionState state = new ConnectionState( MediaLibraryInfo.VERSION_INT, + MediaSessionStub.VERSION_INT, MediaSessionStub.this, sessionImpl.getSessionActivity(), connectionResult.availableSessionCommands, diff --git a/libraries/session/src/main/java/androidx/media3/session/SessionToken.java b/libraries/session/src/main/java/androidx/media3/session/SessionToken.java index fd9d1f0280..ff8167ce1e 100644 --- a/libraries/session/src/main/java/androidx/media3/session/SessionToken.java +++ b/libraries/session/src/main/java/androidx/media3/session/SessionToken.java @@ -133,11 +133,14 @@ public final class SessionToken implements Bundleable { /* package */ SessionToken( int uid, int type, - int version, + int libraryVersion, + int interfaceVersion, String packageName, IMediaSession iSession, Bundle tokenExtras) { - impl = new SessionTokenImplBase(uid, type, version, packageName, iSession, tokenExtras); + impl = + new SessionTokenImplBase( + uid, type, libraryVersion, interfaceVersion, packageName, iSession, tokenExtras); } /* package */ SessionToken(Context context, MediaSessionCompat.Token compatToken) { @@ -230,7 +233,16 @@ public final class SessionToken implements Bundleable { * {@code 1000000} if the session is a legacy session. */ public int getSessionVersion() { - return impl.getSessionVersion(); + return impl.getLibraryVersion(); + } + + /** + * Returns the interface version of the session if the {@link #getType() type} is {@link + * #TYPE_SESSION}. Otherwise, it returns {@code 0}. + */ + @UnstableApi + public int getInterfaceVersion() { + return impl.getInterfaceVersion(); } /** @@ -412,7 +424,9 @@ public final class SessionToken implements Bundleable { @TokenType int getType(); - int getSessionVersion(); + int getLibraryVersion(); + + int getInterfaceVersion(); Bundle getExtras(); diff --git a/libraries/session/src/main/java/androidx/media3/session/SessionTokenImplBase.java b/libraries/session/src/main/java/androidx/media3/session/SessionTokenImplBase.java index aaefd1dc01..1c2e869b53 100644 --- a/libraries/session/src/main/java/androidx/media3/session/SessionTokenImplBase.java +++ b/libraries/session/src/main/java/androidx/media3/session/SessionTokenImplBase.java @@ -40,7 +40,9 @@ import java.lang.annotation.Target; @SessionToken.TokenType private final int type; - private final int version; + private final int libraryVersion; + + private final int interfaceVersion; private final String packageName; @@ -56,7 +58,8 @@ import java.lang.annotation.Target; this( uid, type, - /* version= */ 0, + /* libraryVersion= */ 0, + /* interfaceVersion= */ 0, checkNotNull(serviceComponent).getPackageName(), /* serviceName= */ serviceComponent.getClassName(), /* componentName= */ serviceComponent, @@ -67,14 +70,16 @@ import java.lang.annotation.Target; public SessionTokenImplBase( int uid, int type, - int version, + int libraryVersion, + int interfaceVersion, String packageName, IMediaSession iSession, Bundle tokenExtras) { this( uid, type, - version, + libraryVersion, + interfaceVersion, checkNotNull(packageName), /* serviceName= */ "", /* componentName= */ null, @@ -85,7 +90,8 @@ import java.lang.annotation.Target; private SessionTokenImplBase( int uid, int type, - int version, + int libraryVersion, + int interfaceVersion, String packageName, String serviceName, @Nullable ComponentName componentName, @@ -93,7 +99,8 @@ import java.lang.annotation.Target; Bundle extras) { this.uid = uid; this.type = type; - this.version = version; + this.libraryVersion = libraryVersion; + this.interfaceVersion = interfaceVersion; this.packageName = packageName; this.serviceName = serviceName; this.componentName = componentName; @@ -103,7 +110,15 @@ import java.lang.annotation.Target; @Override public int hashCode() { - return Objects.hashCode(uid, type, version, packageName, serviceName, componentName, iSession); + return Objects.hashCode( + uid, + type, + libraryVersion, + interfaceVersion, + packageName, + serviceName, + componentName, + iSession); } @Override @@ -114,7 +129,8 @@ import java.lang.annotation.Target; SessionTokenImplBase other = (SessionTokenImplBase) obj; return uid == other.uid && type == other.type - && version == other.version + && libraryVersion == other.libraryVersion + && interfaceVersion == other.interfaceVersion && TextUtils.equals(packageName, other.packageName) && TextUtils.equals(serviceName, other.serviceName) && Util.areEqual(componentName, other.componentName) @@ -127,8 +143,10 @@ import java.lang.annotation.Target; + packageName + " type=" + type - + " version=" - + version + + " libraryVersion=" + + libraryVersion + + " interfaceVersion=" + + interfaceVersion + " service=" + serviceName + " IMediaSession=" @@ -171,8 +189,13 @@ import java.lang.annotation.Target; } @Override - public int getSessionVersion() { - return version; + public int getLibraryVersion() { + return libraryVersion; + } + + @Override + public int getInterfaceVersion() { + return interfaceVersion; } @Override @@ -194,35 +217,39 @@ import java.lang.annotation.Target; @IntDef({ FIELD_UID, FIELD_TYPE, - FIELD_VERSION, + FIELD_LIBRARY_VERSION, FIELD_PACKAGE_NAME, FIELD_SERVICE_NAME, FIELD_ISESSION, FIELD_COMPONENT_NAME, - FIELD_EXTRAS + FIELD_EXTRAS, + FIELD_INTERFACE_VERSION }) private @interface FieldNumber {} private static final int FIELD_UID = 0; private static final int FIELD_TYPE = 1; - private static final int FIELD_VERSION = 2; + private static final int FIELD_LIBRARY_VERSION = 2; private static final int FIELD_PACKAGE_NAME = 3; private static final int FIELD_SERVICE_NAME = 4; private static final int FIELD_COMPONENT_NAME = 5; private static final int FIELD_ISESSION = 6; private static final int FIELD_EXTRAS = 7; + private static final int FIELD_INTERFACE_VERSION = 8; + // Next field key = 9 @Override public Bundle toBundle() { Bundle bundle = new Bundle(); bundle.putInt(keyForField(FIELD_UID), uid); bundle.putInt(keyForField(FIELD_TYPE), type); - bundle.putInt(keyForField(FIELD_VERSION), version); + bundle.putInt(keyForField(FIELD_LIBRARY_VERSION), libraryVersion); bundle.putString(keyForField(FIELD_PACKAGE_NAME), packageName); bundle.putString(keyForField(FIELD_SERVICE_NAME), serviceName); BundleCompat.putBinder(bundle, keyForField(FIELD_ISESSION), iSession); bundle.putParcelable(keyForField(FIELD_COMPONENT_NAME), componentName); bundle.putBundle(keyForField(FIELD_EXTRAS), extras); + bundle.putInt(keyForField(FIELD_INTERFACE_VERSION), interfaceVersion); return bundle; } @@ -234,7 +261,9 @@ import java.lang.annotation.Target; int uid = bundle.getInt(keyForField(FIELD_UID)); checkArgument(bundle.containsKey(keyForField(FIELD_TYPE)), "type should be set."); int type = bundle.getInt(keyForField(FIELD_TYPE)); - int version = bundle.getInt(keyForField(FIELD_VERSION), /* defaultValue= */ 0); + int libraryVersion = bundle.getInt(keyForField(FIELD_LIBRARY_VERSION), /* defaultValue= */ 0); + int interfaceVersion = + bundle.getInt(keyForField(FIELD_INTERFACE_VERSION), /* defaultValue= */ 0); String packageName = checkNotEmpty( bundle.getString(keyForField(FIELD_PACKAGE_NAME)), "package name should be set."); @@ -245,7 +274,8 @@ import java.lang.annotation.Target; return new SessionTokenImplBase( uid, type, - version, + libraryVersion, + interfaceVersion, packageName, serviceName, componentName, diff --git a/libraries/session/src/main/java/androidx/media3/session/SessionTokenImplLegacy.java b/libraries/session/src/main/java/androidx/media3/session/SessionTokenImplLegacy.java index ab5ae898f0..da43c9fbd6 100644 --- a/libraries/session/src/main/java/androidx/media3/session/SessionTokenImplLegacy.java +++ b/libraries/session/src/main/java/androidx/media3/session/SessionTokenImplLegacy.java @@ -154,7 +154,12 @@ import java.lang.annotation.Target; } @Override - public int getSessionVersion() { + public int getLibraryVersion() { + return 0; + } + + @Override + public int getInterfaceVersion() { return 0; } diff --git a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerListenerTest.java b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerListenerTest.java index c3e9f6c058..ea40566bb7 100644 --- a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerListenerTest.java +++ b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerListenerTest.java @@ -54,6 +54,7 @@ import androidx.media3.common.DeviceInfo; import androidx.media3.common.FlagSet; import androidx.media3.common.Format; import androidx.media3.common.MediaItem; +import androidx.media3.common.MediaLibraryInfo; import androidx.media3.common.MediaMetadata; import androidx.media3.common.PlaybackException; import androidx.media3.common.PlaybackParameters; @@ -229,6 +230,18 @@ public class MediaControllerListenerTest { assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue(); } + @Test + public void connection_correctVersions() throws Exception { + SessionToken token = new SessionToken(context, MOCK_MEDIA3_SESSION_SERVICE); + + MediaController controller = controllerTestRule.createController(token); + + assertThat(controller.getConnectedToken().getInterfaceVersion()) + .isEqualTo(MediaSessionStub.VERSION_INT); + assertThat(controller.getConnectedToken().getSessionVersion()) + .isEqualTo(MediaLibraryInfo.VERSION_INT); + } + @Test @LargeTest public void noInteractionAfterSessionClose_session() throws Exception { diff --git a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/SessionTokenTest.java b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/SessionTokenTest.java index 47f6068765..b2d54e2abf 100644 --- a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/SessionTokenTest.java +++ b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/SessionTokenTest.java @@ -71,6 +71,8 @@ public class SessionTokenTest { assertThat(token.getPackageName()).isEqualTo(context.getPackageName()); assertThat(token.getUid()).isEqualTo(Process.myUid()); assertThat(token.getType()).isEqualTo(SessionToken.TYPE_SESSION_SERVICE); + assertThat(token.getInterfaceVersion()).isEqualTo(0); + assertThat(token.getSessionVersion()).isEqualTo(0); } @Test @@ -84,6 +86,8 @@ public class SessionTokenTest { assertThat(token.getUid()).isEqualTo(Process.myUid()); assertThat(token.getType()).isEqualTo(SessionToken.TYPE_LIBRARY_SERVICE); assertThat(token.getServiceName()).isEqualTo(testComponentName.getClassName()); + assertThat(token.getInterfaceVersion()).isEqualTo(0); + assertThat(token.getSessionVersion()).isEqualTo(0); } @Test @@ -101,6 +105,7 @@ public class SessionTokenTest { assertThat(token.getUid()).isEqualTo(Process.myUid()); assertThat(token.getType()).isEqualTo(SessionToken.TYPE_SESSION); assertThat(token.getSessionVersion()).isEqualTo(MediaLibraryInfo.VERSION_INT); + assertThat(token.getInterfaceVersion()).isEqualTo(MediaSessionStub.VERSION_INT); assertThat(TestUtils.equals(testTokenExtras, token.getExtras())).isTrue(); assertThat(token.getServiceName()).isEmpty(); }