Enable MediaSession2Test.testSetPlayer_playbackInfo

Bug: 77241129
Test: ./gradlew media:check media:connectedCheck (API 19 and 28)
Change-Id: I27d8cc37f6ed81b2cdb8600a6eb0d8443fa9a33e
diff --git a/media/src/androidTest/java/androidx/media/MediaSession2Test.java b/media/src/androidTest/java/androidx/media/MediaSession2Test.java
index 77dbf43..af11bb7 100644
--- a/media/src/androidTest/java/androidx/media/MediaSession2Test.java
+++ b/media/src/androidTest/java/androidx/media/MediaSession2Test.java
@@ -18,6 +18,9 @@
 
 import static android.media.AudioAttributes.CONTENT_TYPE_MUSIC;
 
+import static androidx.media.VolumeProviderCompat.VOLUME_CONTROL_ABSOLUTE;
+import static androidx.media.VolumeProviderCompat.VOLUME_CONTROL_FIXED;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
@@ -282,7 +285,6 @@
         assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
     }
 
-    @Ignore
     @Test
     public void testSetPlayer_playbackInfo() throws Exception {
         prepareLooper();
@@ -294,10 +296,9 @@
 
         final int maxVolume = 100;
         final int currentVolume = 23;
-        final int volumeControlType = VolumeProviderCompat.VOLUME_CONTROL_ABSOLUTE;
-        VolumeProviderCompat volumeProvider =
-                new VolumeProviderCompat(volumeControlType, maxVolume, currentVolume) {
-                };
+        final int volumeControlType = VOLUME_CONTROL_ABSOLUTE;
+        VolumeProviderCompat volumeProvider = new VolumeProviderCompat(
+                volumeControlType, maxVolume, currentVolume) { };
 
         final CountDownLatch latch = new CountDownLatch(1);
         final ControllerCallback callback = new ControllerCallback() {
@@ -320,9 +321,11 @@
         assertEquals(PlaybackInfo.PLAYBACK_TYPE_LOCAL, info.getPlaybackType());
         assertEquals(attrs, info.getAudioAttributes());
         AudioManager manager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
-        int localVolumeControlType = manager.isVolumeFixed()
-                ? VolumeProviderCompat.VOLUME_CONTROL_FIXED
-                : VolumeProviderCompat.VOLUME_CONTROL_ABSOLUTE;
+
+        int localVolumeControlType = VOLUME_CONTROL_ABSOLUTE;
+        if (Build.VERSION.SDK_INT >= 21 && manager.isVolumeFixed()) {
+            localVolumeControlType = VOLUME_CONTROL_FIXED;
+        }
         assertEquals(localVolumeControlType, info.getControlType());
         assertEquals(manager.getStreamMaxVolume(AudioManager.STREAM_MUSIC), info.getMaxVolume());
         assertEquals(manager.getStreamVolume(AudioManager.STREAM_MUSIC), info.getCurrentVolume());
diff --git a/media/src/main/java/androidx/media/MediaConstants2.java b/media/src/main/java/androidx/media/MediaConstants2.java
index b5af0a9..f575ca0 100644
--- a/media/src/main/java/androidx/media/MediaConstants2.java
+++ b/media/src/main/java/androidx/media/MediaConstants2.java
@@ -24,6 +24,8 @@
     // Event string used by IMediaControllerCallback.onEvent()
     static final String SESSION_EVENT_ON_PLAYER_STATE_CHANGED =
             "androidx.media.session.event.ON_PLAYER_STATE_CHANGED";
+    static final String SESSION_EVENT_ON_PLAYBACK_INFO_CHANGED =
+            "androidx.media.session.event.ON_PLAYBACK_INFO_CHANGED";
     static final String SESSION_EVENT_ON_ERROR =
             "androidx.media.session.event.ON_ERROR";
     static final String SESSION_EVENT_ON_REPEAT_MODE_CHANGED =
@@ -76,6 +78,7 @@
     static final String ARGUMENT_ARGUMENTS = "androidx.media.argument.ARGUMENTS";
     static final String ARGUMENT_RESULT_RECEIVER = "androidx.media.argument.RESULT_RECEIVER";
     static final String ARGUMENT_COMMAND_BUTTONS = "androidx.media.argument.COMMAND_BUTTONS";
+    static final String ARGUMENT_PLAYBACK_INFO = "androidx.media.argument.PLAYBACK_INFO";
 
     static final String ARGUMENT_ICONTROLLER_CALLBACK =
             "androidx.media.argument.ICONTROLLER_CALLBACK";
diff --git a/media/src/main/java/androidx/media/MediaController2.java b/media/src/main/java/androidx/media/MediaController2.java
index f62616c..ac3cd02 100644
--- a/media/src/main/java/androidx/media/MediaController2.java
+++ b/media/src/main/java/androidx/media/MediaController2.java
@@ -31,6 +31,7 @@
 import static androidx.media.MediaConstants2.ARGUMENT_MEDIA_ITEM;
 import static androidx.media.MediaConstants2.ARGUMENT_PACKAGE_NAME;
 import static androidx.media.MediaConstants2.ARGUMENT_PID;
+import static androidx.media.MediaConstants2.ARGUMENT_PLAYBACK_INFO;
 import static androidx.media.MediaConstants2.ARGUMENT_PLAYBACK_STATE_COMPAT;
 import static androidx.media.MediaConstants2.ARGUMENT_PLAYER_STATE;
 import static androidx.media.MediaConstants2.ARGUMENT_PLAYLIST;
@@ -55,6 +56,7 @@
 import static androidx.media.MediaConstants2.CONTROLLER_COMMAND_DISCONNECT;
 import static androidx.media.MediaConstants2.SESSION_EVENT_ON_ALLOWED_COMMANDS_CHANGED;
 import static androidx.media.MediaConstants2.SESSION_EVENT_ON_ERROR;
+import static androidx.media.MediaConstants2.SESSION_EVENT_ON_PLAYBACK_INFO_CHANGED;
 import static androidx.media.MediaConstants2.SESSION_EVENT_ON_PLAYER_STATE_CHANGED;
 import static androidx.media.MediaConstants2.SESSION_EVENT_ON_PLAYLIST_CHANGED;
 import static androidx.media.MediaConstants2.SESSION_EVENT_ON_PLAYLIST_METADATA_CHANGED;
@@ -362,8 +364,7 @@
         PlaybackInfo(int playbackType, AudioAttributesCompat attrs, int controlType, int max,
                 int current) {
             mPlaybackType = playbackType;
-            // TODO: Use AudioAttributesCompat instead of AudioAttributes, and set the value
-            mAudioAttrsCompat = null;
+            mAudioAttrsCompat = attrs;
             mControlType = controlType;
             mMaxVolume = max;
             mCurrentVolume = current;
@@ -432,8 +433,10 @@
             bundle.putInt(KEY_CONTROL_TYPE, mControlType);
             bundle.putInt(KEY_MAX_VOLUME, mMaxVolume);
             bundle.putInt(KEY_CURRENT_VOLUME, mCurrentVolume);
-            bundle.putParcelable(KEY_AUDIO_ATTRIBUTES,
-                    MediaUtils2.toAudioAttributesBundle(mAudioAttrsCompat));
+            if (mAudioAttrsCompat != null) {
+                bundle.putParcelable(KEY_AUDIO_ATTRIBUTES,
+                        MediaUtils2.toAudioAttributesBundle(mAudioAttrsCompat));
+            }
             return bundle;
         }
 
@@ -452,7 +455,6 @@
             final int currentVolume = bundle.getInt(KEY_CURRENT_VOLUME);
             final AudioAttributesCompat attrs = MediaUtils2.fromAudioAttributesBundle(
                     bundle.getBundle(KEY_AUDIO_ATTRIBUTES));
-
             return createPlaybackInfo(volumeType, attrs, volumeControl, maxVolume,
                     currentVolume);
         }
@@ -583,6 +585,17 @@
                     mCallback.onCustomLayoutChanged(MediaController2.this, layout);
                     break;
                 }
+                case SESSION_EVENT_ON_PLAYBACK_INFO_CHANGED: {
+                    PlaybackInfo info = PlaybackInfo.fromBundle(
+                            extras.getBundle(ARGUMENT_PLAYBACK_INFO));
+                    if (info == null) {
+                        return;
+                    }
+                    synchronized (mLock) {
+                        mPlaybackInfo = info;
+                    }
+                    mCallback.onPlaybackInfoChanged(MediaController2.this, info);
+                }
             }
         }
     }
@@ -1450,6 +1463,8 @@
         // TODO: Set mMediaMetadataCompat from the data.
         final List<MediaItem2> playlist = MediaUtils2.fromMediaItem2ParcelableArray(
                 data.getParcelableArray(ARGUMENT_PLAYLIST));
+        final PlaybackInfo playbackInfo =
+                PlaybackInfo.fromBundle(data.getBundle(ARGUMENT_PLAYBACK_INFO));
         if (DEBUG) {
             Log.d(TAG, "onConnectedNotLocked sessionCompatToken=" + mToken.getSessionCompatToken()
                     + ", allowedCommands=" + allowedCommands);
@@ -1473,6 +1488,7 @@
                 mShuffleMode = shuffleMode;
                 mPlaylist = playlist;
                 mConnected = true;
+                mPlaybackInfo = playbackInfo;
             }
             // TODO(jaewan): Keep commands to prevents illegal API calls.
             mCallbackExecutor.execute(new Runnable() {
diff --git a/media/src/main/java/androidx/media/MediaSession2.java b/media/src/main/java/androidx/media/MediaSession2.java
index e11af45..4c4f7c0 100644
--- a/media/src/main/java/androidx/media/MediaSession2.java
+++ b/media/src/main/java/androidx/media/MediaSession2.java
@@ -35,6 +35,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
+import androidx.media.MediaController2.PlaybackInfo;
 import androidx.media.MediaPlayerBase.BuffState;
 import androidx.media.MediaPlayerBase.PlayerState;
 import androidx.media.MediaPlaylistAgent.PlaylistEventCallback;
@@ -1053,6 +1054,7 @@
         abstract SessionCallback getCallback();
         abstract boolean isClosed();
         abstract PlaybackStateCompat getPlaybackStateCompat();
+        abstract PlaybackInfo getPlaybackInfo();
     }
 
     static final String TAG = "MediaSession2";
diff --git a/media/src/main/java/androidx/media/MediaSession2ImplBase.java b/media/src/main/java/androidx/media/MediaSession2ImplBase.java
index b5a3350..0e0eeb4 100644
--- a/media/src/main/java/androidx/media/MediaSession2ImplBase.java
+++ b/media/src/main/java/androidx/media/MediaSession2ImplBase.java
@@ -47,6 +47,7 @@
 import androidx.annotation.GuardedBy;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.media.MediaController2.PlaybackInfo;
 import androidx.media.MediaPlayerBase.PlayerEventCallback;
 import androidx.media.MediaPlaylistAgent.PlaylistEventCallback;
 
@@ -90,6 +91,8 @@
     private OnDataSourceMissingHelper mDsmHelper;
     @GuardedBy("mLock")
     private PlaybackStateCompat mPlaybackStateCompat;
+    @GuardedBy("mLock")
+    private PlaybackInfo mPlaybackInfo;
 
     MediaSession2ImplBase(Context context, MediaSessionCompat sessionCompat, String id,
             MediaPlayerBase player, MediaPlaylistAgent playlistAgent,
@@ -142,6 +145,7 @@
         }
         final MediaPlayerBase oldPlayer;
         final MediaPlaylistAgent oldAgent;
+        final PlaybackInfo info = createPlaybackInfo(volumeProvider, player.getAudioAttributes());
         synchronized (mLock) {
             oldPlayer = mPlayer;
             oldAgent = mPlaylistAgent;
@@ -155,6 +159,7 @@
             }
             mPlaylistAgent = playlistAgent;
             mVolumeProvider = volumeProvider;
+            mPlaybackInfo = info;
         }
         if (player != oldPlayer) {
             player.registerPlayerEventCallback(mCallbackExecutor, mPlayerEventCallback);
@@ -172,13 +177,50 @@
         }
 
         if (oldPlayer != null) {
-            // TODO: implement
-            //mSession2Stub.notifyVolumeControlInfoChanged();
+            mSession2Stub.notifyPlaybackInfoChanged(info);
             notifyPlayerUpdatedNotLocked(oldPlayer);
         }
         // TODO(jaewan): Repeat the same thing for the playlist agent.
     }
 
+    private PlaybackInfo createPlaybackInfo(VolumeProviderCompat volumeProvider,
+            AudioAttributesCompat attrs) {
+        PlaybackInfo info;
+        if (volumeProvider == null) {
+            int stream;
+            if (attrs == null) {
+                stream = AudioManager.STREAM_MUSIC;
+            } else {
+                stream = attrs.getVolumeControlStream();
+                if (stream == AudioManager.USE_DEFAULT_STREAM_TYPE) {
+                    // It may happen if the AudioAttributes doesn't have usage.
+                    // Change it to the STREAM_MUSIC because it's not supported by audio manager
+                    // for querying volume level.
+                    stream = AudioManager.STREAM_MUSIC;
+                }
+            }
+
+            int controlType = VolumeProviderCompat.VOLUME_CONTROL_ABSOLUTE;
+            if (Build.VERSION.SDK_INT >= 21 && mAudioManager.isVolumeFixed()) {
+                controlType = VolumeProviderCompat.VOLUME_CONTROL_FIXED;
+            }
+            info = PlaybackInfo.createPlaybackInfo(
+                    PlaybackInfo.PLAYBACK_TYPE_LOCAL,
+                    attrs,
+                    controlType,
+                    mAudioManager.getStreamMaxVolume(stream),
+                    mAudioManager.getStreamVolume(stream));
+        } else {
+            info = PlaybackInfo.createPlaybackInfo(
+                    PlaybackInfo.PLAYBACK_TYPE_REMOTE,
+                    attrs,
+                    volumeProvider.getVolumeControl(),
+                    volumeProvider.getMaxVolume(),
+                    volumeProvider.getCurrentVolume());
+        }
+        return info;
+    }
+
     @Override
     public void close() {
         synchronized (mLock) {
@@ -754,6 +796,13 @@
         }
     }
 
+    @Override
+    PlaybackInfo getPlaybackInfo() {
+        synchronized (mLock) {
+            return mPlaybackInfo;
+        }
+    }
+
     MediaSession2StubImplBase getSession2Stub() {
         return mSession2Stub;
     }
diff --git a/media/src/main/java/androidx/media/MediaSession2StubImplBase.java b/media/src/main/java/androidx/media/MediaSession2StubImplBase.java
index 6e0d375..b13f70b 100644
--- a/media/src/main/java/androidx/media/MediaSession2StubImplBase.java
+++ b/media/src/main/java/androidx/media/MediaSession2StubImplBase.java
@@ -28,6 +28,7 @@
 import static androidx.media.MediaConstants2.ARGUMENT_MEDIA_ITEM;
 import static androidx.media.MediaConstants2.ARGUMENT_PACKAGE_NAME;
 import static androidx.media.MediaConstants2.ARGUMENT_PID;
+import static androidx.media.MediaConstants2.ARGUMENT_PLAYBACK_INFO;
 import static androidx.media.MediaConstants2.ARGUMENT_PLAYBACK_STATE_COMPAT;
 import static androidx.media.MediaConstants2.ARGUMENT_PLAYER_STATE;
 import static androidx.media.MediaConstants2.ARGUMENT_PLAYLIST;
@@ -52,6 +53,7 @@
 import static androidx.media.MediaConstants2.CONTROLLER_COMMAND_DISCONNECT;
 import static androidx.media.MediaConstants2.SESSION_EVENT_ON_ALLOWED_COMMANDS_CHANGED;
 import static androidx.media.MediaConstants2.SESSION_EVENT_ON_ERROR;
+import static androidx.media.MediaConstants2.SESSION_EVENT_ON_PLAYBACK_INFO_CHANGED;
 import static androidx.media.MediaConstants2.SESSION_EVENT_ON_PLAYER_STATE_CHANGED;
 import static androidx.media.MediaConstants2.SESSION_EVENT_ON_PLAYLIST_CHANGED;
 import static androidx.media.MediaConstants2.SESSION_EVENT_ON_PLAYLIST_METADATA_CHANGED;
@@ -103,6 +105,7 @@
 
 import androidx.annotation.GuardedBy;
 import androidx.annotation.NonNull;
+import androidx.media.MediaController2.PlaybackInfo;
 import androidx.media.MediaSession2.CommandButton;
 import androidx.media.MediaSession2.ControllerInfo;
 
@@ -492,6 +495,18 @@
         });
     }
 
+    void notifyPlaybackInfoChanged(final PlaybackInfo info) {
+        notifyAll(new Session2Runnable() {
+            @Override
+            public void run(ControllerInfo controller) throws RemoteException {
+                Bundle bundle = new Bundle();
+                bundle.putBundle(ARGUMENT_PLAYBACK_INFO, info.toBundle());
+                controller.getControllerBinder().onEvent(
+                        SESSION_EVENT_ON_PLAYBACK_INFO_CHANGED, bundle);
+            }
+        });
+    }
+
     void notifyPlayerStateChanged(final int state) {
         notifyAll(new Session2Runnable() {
             @Override
@@ -775,6 +790,8 @@
                         resultData.putParcelableArray(ARGUMENT_PLAYLIST,
                                 MediaUtils2.toMediaItem2ParcelableArray(playlist));
                     }
+                    resultData.putBundle(ARGUMENT_PLAYBACK_INFO,
+                            mSession.getPlaybackInfo().toBundle());
 
                     // Double check if session is still there, because close() can be
                     // called in another thread.
diff --git a/media/src/main/java/androidx/media/MediaUtils2.java b/media/src/main/java/androidx/media/MediaUtils2.java
index b784599..d581819 100644
--- a/media/src/main/java/androidx/media/MediaUtils2.java
+++ b/media/src/main/java/androidx/media/MediaUtils2.java
@@ -16,6 +16,8 @@
 
 package androidx.media;
 
+import static androidx.media.AudioAttributesCompat.CONTENT_TYPE_UNKNOWN;
+import static androidx.media.AudioAttributesCompat.USAGE_UNKNOWN;
 import static androidx.media.MediaMetadata2.METADATA_KEY_DISPLAY_DESCRIPTION;
 import static androidx.media.MediaMetadata2.METADATA_KEY_DISPLAY_ICON;
 import static androidx.media.MediaMetadata2.METADATA_KEY_DISPLAY_ICON_URI;
@@ -286,12 +288,6 @@
         }
     }
 
-    static MediaController2.PlaybackInfo createPlaybackInfo(int playbackType,
-            AudioAttributesCompat attrs, VolumeProviderCompat vp) {
-        return new MediaController2.PlaybackInfo(playbackType, attrs, vp.getVolumeControl(),
-                vp.getMaxVolume(), vp.getCurrentVolume());
-    }
-
     static Parcelable[] toMediaItem2ParcelableArray(List<MediaItem2> playlist) {
         if (playlist == null) {
             return null;
@@ -356,6 +352,9 @@
     }
 
     static Bundle toAudioAttributesBundle(AudioAttributesCompat attrs) {
+        if (attrs == null) {
+            return null;
+        }
         Bundle bundle = new Bundle();
         bundle.putInt(AUDIO_ATTRIBUTES_USAGE, attrs.getUsage());
         bundle.putInt(AUDIO_ATTRIBUTES_CONTENT_TYPE, attrs.getContentType());
@@ -364,10 +363,13 @@
     }
 
     static AudioAttributesCompat fromAudioAttributesBundle(Bundle bundle) {
+        if (bundle == null) {
+            return null;
+        }
         return new AudioAttributesCompat.Builder()
-                .setUsage(bundle.getInt(AUDIO_ATTRIBUTES_USAGE))
-                .setContentType(bundle.getInt(AUDIO_ATTRIBUTES_CONTENT_TYPE))
-                .setFlags(bundle.getInt(AUDIO_ATTRIBUTES_FLAGS))
+                .setUsage(bundle.getInt(AUDIO_ATTRIBUTES_USAGE, USAGE_UNKNOWN))
+                .setContentType(bundle.getInt(AUDIO_ATTRIBUTES_CONTENT_TYPE, CONTENT_TYPE_UNKNOWN))
+                .setFlags(bundle.getInt(AUDIO_ATTRIBUTES_FLAGS, 0))
                 .build();
     }