MediaSession2: Unhide MediaSession2 and MediaController2

MediaSession2 and MediaController2 are the new version of the
MediaSessionCompat and MediaControllerCompat.

Bug: 76182126
Test: ./gradlew :media:check :media:connectedCheck updateApi
Change-Id: I1e0bceaaf111c1f92656133bbbc546c7cf1025a4
diff --git a/media/api/current.txt b/media/api/current.txt
index d7df744..a9e2161 100644
--- a/media/api/current.txt
+++ b/media/api/current.txt
@@ -565,6 +565,41 @@
     method public androidx.media.AudioAttributesCompat.Builder setUsage(int);
   }
 
+  public final class DataSourceDesc {
+    method public long getEndPosition();
+    method public java.io.FileDescriptor getFileDescriptor();
+    method public long getFileDescriptorLength();
+    method public long getFileDescriptorOffset();
+    method public androidx.media.Media2DataSource getMedia2DataSource();
+    method public java.lang.String getMediaId();
+    method public long getStartPosition();
+    method public int getType();
+    method public android.net.Uri getUri();
+    method public android.content.Context getUriContext();
+    method public java.util.List<java.net.HttpCookie> getUriCookies();
+    method public java.util.Map<java.lang.String, java.lang.String> getUriHeaders();
+    field public static final long FD_LENGTH_UNKNOWN = 576460752303423487L; // 0x7ffffffffffffffL
+    field public static final long POSITION_UNKNOWN = 576460752303423487L; // 0x7ffffffffffffffL
+    field public static final int TYPE_CALLBACK = 1; // 0x1
+    field public static final int TYPE_FD = 2; // 0x2
+    field public static final int TYPE_NONE = 0; // 0x0
+    field public static final int TYPE_URI = 3; // 0x3
+  }
+
+  public static class DataSourceDesc.Builder {
+    ctor public DataSourceDesc.Builder();
+    ctor public DataSourceDesc.Builder(androidx.media.DataSourceDesc);
+    method public androidx.media.DataSourceDesc build();
+    method public androidx.media.DataSourceDesc.Builder setDataSource(androidx.media.Media2DataSource);
+    method public androidx.media.DataSourceDesc.Builder setDataSource(java.io.FileDescriptor);
+    method public androidx.media.DataSourceDesc.Builder setDataSource(java.io.FileDescriptor, long, long);
+    method public androidx.media.DataSourceDesc.Builder setDataSource(android.content.Context, android.net.Uri);
+    method public androidx.media.DataSourceDesc.Builder setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>, java.util.List<java.net.HttpCookie>);
+    method public androidx.media.DataSourceDesc.Builder setEndPosition(long);
+    method public androidx.media.DataSourceDesc.Builder setMediaId(java.lang.String);
+    method public androidx.media.DataSourceDesc.Builder setStartPosition(long);
+  }
+
   public abstract class MediaBrowserServiceCompat extends android.app.Service {
     ctor public MediaBrowserServiceCompat();
     method public void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
@@ -600,6 +635,487 @@
     method public void sendResult(T);
   }
 
+  public class MediaController2 implements java.lang.AutoCloseable {
+    ctor public MediaController2(android.content.Context, androidx.media.SessionToken2, java.util.concurrent.Executor, androidx.media.MediaController2.ControllerCallback);
+    method public void addPlaylistItem(int, androidx.media.MediaItem2);
+    method public void adjustVolume(int, int);
+    method public void close();
+    method public void fastForward();
+    method public long getBufferedPosition();
+    method public int getBufferingState();
+    method public androidx.media.MediaItem2 getCurrentMediaItem();
+    method public long getCurrentPosition();
+    method public long getDuration();
+    method public androidx.media.MediaController2.PlaybackInfo getPlaybackInfo();
+    method public float getPlaybackSpeed();
+    method public int getPlayerState();
+    method public java.util.List<androidx.media.MediaItem2> getPlaylist();
+    method public androidx.media.MediaMetadata2 getPlaylistMetadata();
+    method public int getRepeatMode();
+    method public android.app.PendingIntent getSessionActivity();
+    method public androidx.media.SessionToken2 getSessionToken();
+    method public int getShuffleMode();
+    method public boolean isConnected();
+    method public void pause();
+    method public void play();
+    method public void playFromMediaId(java.lang.String, android.os.Bundle);
+    method public void playFromSearch(java.lang.String, android.os.Bundle);
+    method public void playFromUri(android.net.Uri, android.os.Bundle);
+    method public void prepare();
+    method public void prepareFromMediaId(java.lang.String, android.os.Bundle);
+    method public void prepareFromSearch(java.lang.String, android.os.Bundle);
+    method public void prepareFromUri(android.net.Uri, android.os.Bundle);
+    method public void removePlaylistItem(androidx.media.MediaItem2);
+    method public void replacePlaylistItem(int, androidx.media.MediaItem2);
+    method public void reset();
+    method public void rewind();
+    method public void seekTo(long);
+    method public void selectRoute(android.os.Bundle);
+    method public void sendCustomCommand(androidx.media.SessionCommand2, android.os.Bundle, android.os.ResultReceiver);
+    method public void setPlaybackSpeed(float);
+    method public void setPlaylist(java.util.List<androidx.media.MediaItem2>, androidx.media.MediaMetadata2);
+    method public void setRating(java.lang.String, androidx.media.Rating2);
+    method public void setRepeatMode(int);
+    method public void setShuffleMode(int);
+    method public void setVolumeTo(int, int);
+    method public void skipToNextItem();
+    method public void skipToPlaylistItem(androidx.media.MediaItem2);
+    method public void skipToPreviousItem();
+    method public void subscribeRoutesInfo();
+    method public void unsubscribeRoutesInfo();
+    method public void updatePlaylistMetadata(androidx.media.MediaMetadata2);
+  }
+
+  public static abstract class MediaController2.ControllerCallback {
+    ctor public MediaController2.ControllerCallback();
+    method public void onAllowedCommandsChanged(androidx.media.MediaController2, androidx.media.SessionCommandGroup2);
+    method public void onBufferingStateChanged(androidx.media.MediaController2, androidx.media.MediaItem2, int);
+    method public void onConnected(androidx.media.MediaController2, androidx.media.SessionCommandGroup2);
+    method public void onCurrentMediaItemChanged(androidx.media.MediaController2, androidx.media.MediaItem2);
+    method public void onCustomCommand(androidx.media.MediaController2, androidx.media.SessionCommand2, android.os.Bundle, android.os.ResultReceiver);
+    method public void onCustomLayoutChanged(androidx.media.MediaController2, java.util.List<androidx.media.MediaSession2.CommandButton>);
+    method public void onDisconnected(androidx.media.MediaController2);
+    method public void onError(androidx.media.MediaController2, int, android.os.Bundle);
+    method public void onPlaybackInfoChanged(androidx.media.MediaController2, androidx.media.MediaController2.PlaybackInfo);
+    method public void onPlaybackSpeedChanged(androidx.media.MediaController2, float);
+    method public void onPlayerStateChanged(androidx.media.MediaController2, int);
+    method public void onPlaylistChanged(androidx.media.MediaController2, java.util.List<androidx.media.MediaItem2>, androidx.media.MediaMetadata2);
+    method public void onPlaylistMetadataChanged(androidx.media.MediaController2, androidx.media.MediaMetadata2);
+    method public void onRepeatModeChanged(androidx.media.MediaController2, int);
+    method public void onRoutesInfoChanged(androidx.media.MediaController2, java.util.List<android.os.Bundle>);
+    method public void onSeekCompleted(androidx.media.MediaController2, long);
+    method public void onShuffleModeChanged(androidx.media.MediaController2, int);
+  }
+
+  public static final class MediaController2.PlaybackInfo {
+    method public androidx.media.AudioAttributesCompat getAudioAttributes();
+    method public int getControlType();
+    method public int getCurrentVolume();
+    method public int getMaxVolume();
+    method public int getPlaybackType();
+    field public static final int PLAYBACK_TYPE_LOCAL = 1; // 0x1
+    field public static final int PLAYBACK_TYPE_REMOTE = 2; // 0x2
+  }
+
+  public class MediaItem2 {
+    method public static androidx.media.MediaItem2 fromBundle(android.os.Bundle);
+    method public androidx.media.DataSourceDesc getDataSourceDesc();
+    method public int getFlags();
+    method public java.lang.String getMediaId();
+    method public androidx.media.MediaMetadata2 getMetadata();
+    method public boolean isBrowsable();
+    method public boolean isPlayable();
+    method public void setMetadata(androidx.media.MediaMetadata2);
+    method public android.os.Bundle toBundle();
+    field public static final int FLAG_BROWSABLE = 1; // 0x1
+    field public static final int FLAG_PLAYABLE = 2; // 0x2
+  }
+
+  public static final class MediaItem2.Builder {
+    ctor public MediaItem2.Builder(int);
+    method public androidx.media.MediaItem2 build();
+    method public androidx.media.MediaItem2.Builder setDataSourceDesc(androidx.media.DataSourceDesc);
+    method public androidx.media.MediaItem2.Builder setMediaId(java.lang.String);
+    method public androidx.media.MediaItem2.Builder setMetadata(androidx.media.MediaMetadata2);
+  }
+
+  public final class MediaMetadata2 {
+    method public boolean containsKey(java.lang.String);
+    method public static androidx.media.MediaMetadata2 fromBundle(android.os.Bundle);
+    method public android.graphics.Bitmap getBitmap(java.lang.String);
+    method public android.os.Bundle getExtras();
+    method public float getFloat(java.lang.String);
+    method public long getLong(java.lang.String);
+    method public java.lang.String getMediaId();
+    method public androidx.media.Rating2 getRating(java.lang.String);
+    method public java.lang.String getString(java.lang.String);
+    method public java.lang.CharSequence getText(java.lang.String);
+    method public java.util.Set<java.lang.String> keySet();
+    method public int size();
+    method public android.os.Bundle toBundle();
+    field public static final long BT_FOLDER_TYPE_ALBUMS = 2L; // 0x2L
+    field public static final long BT_FOLDER_TYPE_ARTISTS = 3L; // 0x3L
+    field public static final long BT_FOLDER_TYPE_GENRES = 4L; // 0x4L
+    field public static final long BT_FOLDER_TYPE_MIXED = 0L; // 0x0L
+    field public static final long BT_FOLDER_TYPE_PLAYLISTS = 5L; // 0x5L
+    field public static final long BT_FOLDER_TYPE_TITLES = 1L; // 0x1L
+    field public static final long BT_FOLDER_TYPE_YEARS = 6L; // 0x6L
+    field public static final java.lang.String METADATA_KEY_ADVERTISEMENT = "android.media.metadata.ADVERTISEMENT";
+    field public static final java.lang.String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM";
+    field public static final java.lang.String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART";
+    field public static final java.lang.String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST";
+    field public static final java.lang.String METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI";
+    field public static final java.lang.String METADATA_KEY_ART = "android.media.metadata.ART";
+    field public static final java.lang.String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";
+    field public static final java.lang.String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI";
+    field public static final java.lang.String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR";
+    field public static final java.lang.String METADATA_KEY_BT_FOLDER_TYPE = "android.media.metadata.BT_FOLDER_TYPE";
+    field public static final java.lang.String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
+    field public static final java.lang.String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";
+    field public static final java.lang.String METADATA_KEY_DATE = "android.media.metadata.DATE";
+    field public static final java.lang.String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
+    field public static final java.lang.String METADATA_KEY_DISPLAY_DESCRIPTION = "android.media.metadata.DISPLAY_DESCRIPTION";
+    field public static final java.lang.String METADATA_KEY_DISPLAY_ICON = "android.media.metadata.DISPLAY_ICON";
+    field public static final java.lang.String METADATA_KEY_DISPLAY_ICON_URI = "android.media.metadata.DISPLAY_ICON_URI";
+    field public static final java.lang.String METADATA_KEY_DISPLAY_SUBTITLE = "android.media.metadata.DISPLAY_SUBTITLE";
+    field public static final java.lang.String METADATA_KEY_DISPLAY_TITLE = "android.media.metadata.DISPLAY_TITLE";
+    field public static final java.lang.String METADATA_KEY_DOWNLOAD_STATUS = "android.media.metadata.DOWNLOAD_STATUS";
+    field public static final java.lang.String METADATA_KEY_DURATION = "android.media.metadata.DURATION";
+    field public static final java.lang.String METADATA_KEY_EXTRAS = "android.media.metadata.EXTRAS";
+    field public static final java.lang.String METADATA_KEY_GENRE = "android.media.metadata.GENRE";
+    field public static final java.lang.String METADATA_KEY_MEDIA_ID = "android.media.metadata.MEDIA_ID";
+    field public static final java.lang.String METADATA_KEY_MEDIA_URI = "android.media.metadata.MEDIA_URI";
+    field public static final java.lang.String METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS";
+    field public static final java.lang.String METADATA_KEY_RATING = "android.media.metadata.RATING";
+    field public static final java.lang.String METADATA_KEY_TITLE = "android.media.metadata.TITLE";
+    field public static final java.lang.String METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER";
+    field public static final java.lang.String METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING";
+    field public static final java.lang.String METADATA_KEY_WRITER = "android.media.metadata.WRITER";
+    field public static final java.lang.String METADATA_KEY_YEAR = "android.media.metadata.YEAR";
+    field public static final long STATUS_DOWNLOADED = 2L; // 0x2L
+    field public static final long STATUS_DOWNLOADING = 1L; // 0x1L
+    field public static final long STATUS_NOT_DOWNLOADED = 0L; // 0x0L
+  }
+
+  public static final class MediaMetadata2.Builder {
+    ctor public MediaMetadata2.Builder();
+    ctor public MediaMetadata2.Builder(androidx.media.MediaMetadata2);
+    method public androidx.media.MediaMetadata2 build();
+    method public androidx.media.MediaMetadata2.Builder putBitmap(java.lang.String, android.graphics.Bitmap);
+    method public androidx.media.MediaMetadata2.Builder putFloat(java.lang.String, float);
+    method public androidx.media.MediaMetadata2.Builder putLong(java.lang.String, long);
+    method public androidx.media.MediaMetadata2.Builder putRating(java.lang.String, androidx.media.Rating2);
+    method public androidx.media.MediaMetadata2.Builder putString(java.lang.String, java.lang.String);
+    method public androidx.media.MediaMetadata2.Builder putText(java.lang.String, java.lang.CharSequence);
+    method public androidx.media.MediaMetadata2.Builder setExtras(android.os.Bundle);
+  }
+
+  public abstract class MediaPlayerBase implements java.lang.AutoCloseable {
+    ctor public MediaPlayerBase();
+    method public abstract androidx.media.AudioAttributesCompat getAudioAttributes();
+    method public long getBufferedPosition();
+    method public abstract int getBufferingState();
+    method public abstract androidx.media.DataSourceDesc getCurrentDataSource();
+    method public long getCurrentPosition();
+    method public long getDuration();
+    method public float getMaxPlayerVolume();
+    method public float getPlaybackSpeed();
+    method public abstract int getPlayerState();
+    method public abstract float getPlayerVolume();
+    method public boolean isReversePlaybackSupported();
+    method public abstract void loopCurrent(boolean);
+    method public abstract void pause();
+    method public abstract void play();
+    method public abstract void prepare();
+    method public abstract void registerPlayerEventCallback(java.util.concurrent.Executor, androidx.media.MediaPlayerBase.PlayerEventCallback);
+    method public abstract void reset();
+    method public abstract void seekTo(long);
+    method public abstract void setAudioAttributes(androidx.media.AudioAttributesCompat);
+    method public abstract void setDataSource(androidx.media.DataSourceDesc);
+    method public abstract void setNextDataSource(androidx.media.DataSourceDesc);
+    method public abstract void setNextDataSources(java.util.List<androidx.media.DataSourceDesc>);
+    method public abstract void setPlaybackSpeed(float);
+    method public abstract void setPlayerVolume(float);
+    method public abstract void skipToNext();
+    method public abstract void unregisterPlayerEventCallback(androidx.media.MediaPlayerBase.PlayerEventCallback);
+    field public static final int BUFFERING_STATE_BUFFERING_AND_PLAYABLE = 1; // 0x1
+    field public static final int BUFFERING_STATE_BUFFERING_AND_STARVED = 2; // 0x2
+    field public static final int BUFFERING_STATE_BUFFERING_COMPLETE = 3; // 0x3
+    field public static final int BUFFERING_STATE_UNKNOWN = 0; // 0x0
+    field public static final int PLAYER_STATE_ERROR = 3; // 0x3
+    field public static final int PLAYER_STATE_IDLE = 0; // 0x0
+    field public static final int PLAYER_STATE_PAUSED = 1; // 0x1
+    field public static final int PLAYER_STATE_PLAYING = 2; // 0x2
+    field public static final long UNKNOWN_TIME = -1L; // 0xffffffffffffffffL
+  }
+
+  public static abstract class MediaPlayerBase.PlayerEventCallback {
+    ctor public MediaPlayerBase.PlayerEventCallback();
+    method public void onBufferingStateChanged(androidx.media.MediaPlayerBase, androidx.media.DataSourceDesc, int);
+    method public void onCurrentDataSourceChanged(androidx.media.MediaPlayerBase, androidx.media.DataSourceDesc);
+    method public void onMediaPrepared(androidx.media.MediaPlayerBase, androidx.media.DataSourceDesc);
+    method public void onPlaybackSpeedChanged(androidx.media.MediaPlayerBase, float);
+    method public void onPlayerStateChanged(androidx.media.MediaPlayerBase, int);
+    method public void onSeekCompleted(androidx.media.MediaPlayerBase, long);
+  }
+
+  public abstract class MediaPlaylistAgent {
+    ctor public MediaPlaylistAgent();
+    method public abstract void addPlaylistItem(int, androidx.media.MediaItem2);
+    method public abstract androidx.media.MediaItem2 getCurrentMediaItem();
+    method public androidx.media.MediaItem2 getMediaItem(androidx.media.DataSourceDesc);
+    method public abstract java.util.List<androidx.media.MediaItem2> getPlaylist();
+    method public abstract androidx.media.MediaMetadata2 getPlaylistMetadata();
+    method public abstract int getRepeatMode();
+    method public abstract int getShuffleMode();
+    method public final void notifyPlaylistChanged();
+    method public final void notifyPlaylistMetadataChanged();
+    method public final void notifyRepeatModeChanged();
+    method public final void notifyShuffleModeChanged();
+    method public final void registerPlaylistEventCallback(java.util.concurrent.Executor, androidx.media.MediaPlaylistAgent.PlaylistEventCallback);
+    method public abstract void removePlaylistItem(androidx.media.MediaItem2);
+    method public abstract void replacePlaylistItem(int, androidx.media.MediaItem2);
+    method public abstract void setPlaylist(java.util.List<androidx.media.MediaItem2>, androidx.media.MediaMetadata2);
+    method public abstract void setRepeatMode(int);
+    method public abstract void setShuffleMode(int);
+    method public abstract void skipToNextItem();
+    method public abstract void skipToPlaylistItem(androidx.media.MediaItem2);
+    method public abstract void skipToPreviousItem();
+    method public final void unregisterPlaylistEventCallback(androidx.media.MediaPlaylistAgent.PlaylistEventCallback);
+    method public abstract void updatePlaylistMetadata(androidx.media.MediaMetadata2);
+    field public static final int REPEAT_MODE_ALL = 2; // 0x2
+    field public static final int REPEAT_MODE_GROUP = 3; // 0x3
+    field public static final int REPEAT_MODE_NONE = 0; // 0x0
+    field public static final int REPEAT_MODE_ONE = 1; // 0x1
+    field public static final int SHUFFLE_MODE_ALL = 1; // 0x1
+    field public static final int SHUFFLE_MODE_GROUP = 2; // 0x2
+    field public static final int SHUFFLE_MODE_NONE = 0; // 0x0
+  }
+
+  public static abstract class MediaPlaylistAgent.PlaylistEventCallback {
+    ctor public MediaPlaylistAgent.PlaylistEventCallback();
+    method public void onPlaylistChanged(androidx.media.MediaPlaylistAgent, java.util.List<androidx.media.MediaItem2>, androidx.media.MediaMetadata2);
+    method public void onPlaylistMetadataChanged(androidx.media.MediaPlaylistAgent, androidx.media.MediaMetadata2);
+    method public void onRepeatModeChanged(androidx.media.MediaPlaylistAgent, int);
+    method public void onShuffleModeChanged(androidx.media.MediaPlaylistAgent, int);
+  }
+
+  public class MediaSession2 implements java.lang.AutoCloseable {
+    method public void addPlaylistItem(int, androidx.media.MediaItem2);
+    method public void clearOnDataSourceMissingHelper();
+    method public void close();
+    method public long getBufferedPosition();
+    method public int getBufferingState();
+    method public java.util.List<androidx.media.MediaSession2.ControllerInfo> getConnectedControllers();
+    method public androidx.media.MediaItem2 getCurrentMediaItem();
+    method public long getCurrentPosition();
+    method public long getDuration();
+    method public float getPlaybackSpeed();
+    method public androidx.media.MediaPlayerBase getPlayer();
+    method public int getPlayerState();
+    method public java.util.List<androidx.media.MediaItem2> getPlaylist();
+    method public androidx.media.MediaPlaylistAgent getPlaylistAgent();
+    method public androidx.media.MediaMetadata2 getPlaylistMetadata();
+    method public int getRepeatMode();
+    method public int getShuffleMode();
+    method public androidx.media.SessionToken2 getToken();
+    method public androidx.media.VolumeProviderCompat getVolumeProvider();
+    method public void notifyError(int, android.os.Bundle);
+    method public void notifyRoutesInfoChanged(androidx.media.MediaSession2.ControllerInfo, java.util.List<android.os.Bundle>);
+    method public void pause();
+    method public void play();
+    method public void prepare();
+    method public void removePlaylistItem(androidx.media.MediaItem2);
+    method public void replacePlaylistItem(int, androidx.media.MediaItem2);
+    method public void reset();
+    method public void seekTo(long);
+    method public void sendCustomCommand(androidx.media.SessionCommand2, android.os.Bundle);
+    method public void sendCustomCommand(androidx.media.MediaSession2.ControllerInfo, androidx.media.SessionCommand2, android.os.Bundle, android.os.ResultReceiver);
+    method public void setAllowedCommands(androidx.media.MediaSession2.ControllerInfo, androidx.media.SessionCommandGroup2);
+    method public void setAudioFocusRequest(android.media.AudioFocusRequest);
+    method public void setCustomLayout(androidx.media.MediaSession2.ControllerInfo, java.util.List<androidx.media.MediaSession2.CommandButton>);
+    method public void setOnDataSourceMissingHelper(androidx.media.MediaSession2.OnDataSourceMissingHelper);
+    method public void setPlaybackSpeed(float);
+    method public void setPlaylist(java.util.List<androidx.media.MediaItem2>, androidx.media.MediaMetadata2);
+    method public void setRepeatMode(int);
+    method public void setShuffleMode(int);
+    method public void skipToNextItem();
+    method public void skipToPlaylistItem(androidx.media.MediaItem2);
+    method public void skipToPreviousItem();
+    method public void updatePlayer(androidx.media.MediaPlayerBase, androidx.media.MediaPlaylistAgent, androidx.media.VolumeProviderCompat);
+    method public void updatePlaylistMetadata(androidx.media.MediaMetadata2);
+    field public static final int ERROR_CODE_ACTION_ABORTED = 10; // 0xa
+    field public static final int ERROR_CODE_APP_ERROR = 1; // 0x1
+    field public static final int ERROR_CODE_AUTHENTICATION_EXPIRED = 3; // 0x3
+    field public static final int ERROR_CODE_CONCURRENT_STREAM_LIMIT = 5; // 0x5
+    field public static final int ERROR_CODE_CONTENT_ALREADY_PLAYING = 8; // 0x8
+    field public static final int ERROR_CODE_END_OF_QUEUE = 11; // 0xb
+    field public static final int ERROR_CODE_NOT_AVAILABLE_IN_REGION = 7; // 0x7
+    field public static final int ERROR_CODE_NOT_SUPPORTED = 2; // 0x2
+    field public static final int ERROR_CODE_PARENTAL_CONTROL_RESTRICTED = 6; // 0x6
+    field public static final int ERROR_CODE_PREMIUM_ACCOUNT_REQUIRED = 4; // 0x4
+    field public static final int ERROR_CODE_SETUP_REQUIRED = 12; // 0xc
+    field public static final int ERROR_CODE_SKIP_LIMIT_REACHED = 9; // 0x9
+    field public static final int ERROR_CODE_UNKNOWN_ERROR = 0; // 0x0
+  }
+
+  public static final class MediaSession2.Builder {
+    ctor public MediaSession2.Builder(android.content.Context);
+    method public androidx.media.MediaSession2 build();
+    method public androidx.media.MediaSession2.Builder setId(java.lang.String);
+    method public androidx.media.MediaSession2.Builder setPlayer(androidx.media.MediaPlayerBase);
+    method public androidx.media.MediaSession2.Builder setPlaylistAgent(androidx.media.MediaPlaylistAgent);
+    method public androidx.media.MediaSession2.Builder setSessionActivity(android.app.PendingIntent);
+    method public androidx.media.MediaSession2.Builder setSessionCallback(java.util.concurrent.Executor, androidx.media.MediaSession2.SessionCallback);
+    method public androidx.media.MediaSession2.Builder setVolumeProvider(androidx.media.VolumeProviderCompat);
+  }
+
+  public static final class MediaSession2.CommandButton {
+    method public androidx.media.SessionCommand2 getCommand();
+    method public java.lang.String getDisplayName();
+    method public android.os.Bundle getExtras();
+    method public int getIconResId();
+    method public boolean isEnabled();
+  }
+
+  public static final class MediaSession2.CommandButton.Builder {
+    ctor public MediaSession2.CommandButton.Builder();
+    method public androidx.media.MediaSession2.CommandButton build();
+    method public androidx.media.MediaSession2.CommandButton.Builder setCommand(androidx.media.SessionCommand2);
+    method public androidx.media.MediaSession2.CommandButton.Builder setDisplayName(java.lang.String);
+    method public androidx.media.MediaSession2.CommandButton.Builder setEnabled(boolean);
+    method public androidx.media.MediaSession2.CommandButton.Builder setExtras(android.os.Bundle);
+    method public androidx.media.MediaSession2.CommandButton.Builder setIconResId(int);
+  }
+
+  public static final class MediaSession2.ControllerInfo {
+    method public java.lang.String getPackageName();
+    method public int getUid();
+  }
+
+  public static abstract interface MediaSession2.OnDataSourceMissingHelper {
+    method public abstract androidx.media.DataSourceDesc onDataSourceMissing(androidx.media.MediaSession2, androidx.media.MediaItem2);
+  }
+
+  public static abstract class MediaSession2.SessionCallback {
+    ctor public MediaSession2.SessionCallback();
+    method public void onBufferingStateChanged(androidx.media.MediaSession2, androidx.media.MediaPlayerBase, androidx.media.MediaItem2, int);
+    method public boolean onCommandRequest(androidx.media.MediaSession2, androidx.media.MediaSession2.ControllerInfo, androidx.media.SessionCommand2);
+    method public androidx.media.SessionCommandGroup2 onConnect(androidx.media.MediaSession2, androidx.media.MediaSession2.ControllerInfo);
+    method public void onCurrentMediaItemChanged(androidx.media.MediaSession2, androidx.media.MediaPlayerBase, androidx.media.MediaItem2);
+    method public void onCustomCommand(androidx.media.MediaSession2, androidx.media.MediaSession2.ControllerInfo, androidx.media.SessionCommand2, android.os.Bundle, android.os.ResultReceiver);
+    method public void onDisconnected(androidx.media.MediaSession2, androidx.media.MediaSession2.ControllerInfo);
+    method public void onFastForward(androidx.media.MediaSession2, androidx.media.MediaSession2.ControllerInfo);
+    method public void onMediaPrepared(androidx.media.MediaSession2, androidx.media.MediaPlayerBase, androidx.media.MediaItem2);
+    method public void onPlayFromMediaId(androidx.media.MediaSession2, androidx.media.MediaSession2.ControllerInfo, java.lang.String, android.os.Bundle);
+    method public void onPlayFromSearch(androidx.media.MediaSession2, androidx.media.MediaSession2.ControllerInfo, java.lang.String, android.os.Bundle);
+    method public void onPlayFromUri(androidx.media.MediaSession2, androidx.media.MediaSession2.ControllerInfo, android.net.Uri, android.os.Bundle);
+    method public void onPlaybackSpeedChanged(androidx.media.MediaSession2, androidx.media.MediaPlayerBase, float);
+    method public void onPlayerStateChanged(androidx.media.MediaSession2, androidx.media.MediaPlayerBase, int);
+    method public void onPlaylistChanged(androidx.media.MediaSession2, androidx.media.MediaPlaylistAgent, java.util.List<androidx.media.MediaItem2>, androidx.media.MediaMetadata2);
+    method public void onPlaylistMetadataChanged(androidx.media.MediaSession2, androidx.media.MediaPlaylistAgent, androidx.media.MediaMetadata2);
+    method public void onPrepareFromMediaId(androidx.media.MediaSession2, androidx.media.MediaSession2.ControllerInfo, java.lang.String, android.os.Bundle);
+    method public void onPrepareFromSearch(androidx.media.MediaSession2, androidx.media.MediaSession2.ControllerInfo, java.lang.String, android.os.Bundle);
+    method public void onPrepareFromUri(androidx.media.MediaSession2, androidx.media.MediaSession2.ControllerInfo, android.net.Uri, android.os.Bundle);
+    method public void onRepeatModeChanged(androidx.media.MediaSession2, androidx.media.MediaPlaylistAgent, int);
+    method public void onRewind(androidx.media.MediaSession2, androidx.media.MediaSession2.ControllerInfo);
+    method public void onSeekCompleted(androidx.media.MediaSession2, androidx.media.MediaPlayerBase, long);
+    method public void onSelectRoute(androidx.media.MediaSession2, androidx.media.MediaSession2.ControllerInfo, android.os.Bundle);
+    method public void onSetRating(androidx.media.MediaSession2, androidx.media.MediaSession2.ControllerInfo, java.lang.String, androidx.media.Rating2);
+    method public void onShuffleModeChanged(androidx.media.MediaSession2, androidx.media.MediaPlaylistAgent, int);
+    method public void onSubscribeRoutesInfo(androidx.media.MediaSession2, androidx.media.MediaSession2.ControllerInfo);
+    method public void onUnsubscribeRoutesInfo(androidx.media.MediaSession2, androidx.media.MediaSession2.ControllerInfo);
+  }
+
+  public final class Rating2 {
+    method public static androidx.media.Rating2 fromBundle(android.os.Bundle);
+    method public float getPercentRating();
+    method public int getRatingStyle();
+    method public float getStarRating();
+    method public boolean hasHeart();
+    method public boolean isRated();
+    method public boolean isThumbUp();
+    method public static androidx.media.Rating2 newHeartRating(boolean);
+    method public static androidx.media.Rating2 newPercentageRating(float);
+    method public static androidx.media.Rating2 newStarRating(int, float);
+    method public static androidx.media.Rating2 newThumbRating(boolean);
+    method public static androidx.media.Rating2 newUnratedRating(int);
+    method public android.os.Bundle toBundle();
+    field public static final int RATING_3_STARS = 3; // 0x3
+    field public static final int RATING_4_STARS = 4; // 0x4
+    field public static final int RATING_5_STARS = 5; // 0x5
+    field public static final int RATING_HEART = 1; // 0x1
+    field public static final int RATING_NONE = 0; // 0x0
+    field public static final int RATING_PERCENTAGE = 6; // 0x6
+    field public static final int RATING_THUMB_UP_DOWN = 2; // 0x2
+  }
+
+  public final class SessionCommand2 {
+    ctor public SessionCommand2(int);
+    ctor public SessionCommand2(java.lang.String, android.os.Bundle);
+    method public int getCommandCode();
+    method public java.lang.String getCustomCommand();
+    method public android.os.Bundle getExtras();
+    field public static final int COMMAND_CODE_CUSTOM = 0; // 0x0
+    field public static final int COMMAND_CODE_PLAYBACK_PAUSE = 2; // 0x2
+    field public static final int COMMAND_CODE_PLAYBACK_PLAY = 1; // 0x1
+    field public static final int COMMAND_CODE_PLAYBACK_PREPARE = 6; // 0x6
+    field public static final int COMMAND_CODE_PLAYBACK_RESET = 3; // 0x3
+    field public static final int COMMAND_CODE_PLAYBACK_SEEK_TO = 9; // 0x9
+    field public static final int COMMAND_CODE_PLAYBACK_SET_SPEED = 39; // 0x27
+    field public static final int COMMAND_CODE_PLAYLIST_ADD_ITEM = 15; // 0xf
+    field public static final int COMMAND_CODE_PLAYLIST_GET_CURRENT_MEDIA_ITEM = 20; // 0x14
+    field public static final int COMMAND_CODE_PLAYLIST_GET_LIST = 18; // 0x12
+    field public static final int COMMAND_CODE_PLAYLIST_GET_LIST_METADATA = 20; // 0x14
+    field public static final int COMMAND_CODE_PLAYLIST_REMOVE_ITEM = 16; // 0x10
+    field public static final int COMMAND_CODE_PLAYLIST_REPLACE_ITEM = 17; // 0x11
+    field public static final int COMMAND_CODE_PLAYLIST_SET_LIST = 19; // 0x13
+    field public static final int COMMAND_CODE_PLAYLIST_SET_LIST_METADATA = 21; // 0x15
+    field public static final int COMMAND_CODE_PLAYLIST_SET_REPEAT_MODE = 14; // 0xe
+    field public static final int COMMAND_CODE_PLAYLIST_SET_SHUFFLE_MODE = 13; // 0xd
+    field public static final int COMMAND_CODE_PLAYLIST_SKIP_TO_NEXT_ITEM = 4; // 0x4
+    field public static final int COMMAND_CODE_PLAYLIST_SKIP_TO_PLAYLIST_ITEM = 12; // 0xc
+    field public static final int COMMAND_CODE_PLAYLIST_SKIP_TO_PREV_ITEM = 5; // 0x5
+    field public static final int COMMAND_CODE_SESSION_FAST_FORWARD = 7; // 0x7
+    field public static final int COMMAND_CODE_SESSION_PLAY_FROM_MEDIA_ID = 22; // 0x16
+    field public static final int COMMAND_CODE_SESSION_PLAY_FROM_SEARCH = 24; // 0x18
+    field public static final int COMMAND_CODE_SESSION_PLAY_FROM_URI = 23; // 0x17
+    field public static final int COMMAND_CODE_SESSION_PREPARE_FROM_MEDIA_ID = 25; // 0x19
+    field public static final int COMMAND_CODE_SESSION_PREPARE_FROM_SEARCH = 27; // 0x1b
+    field public static final int COMMAND_CODE_SESSION_PREPARE_FROM_URI = 26; // 0x1a
+    field public static final int COMMAND_CODE_SESSION_REWIND = 8; // 0x8
+    field public static final int COMMAND_CODE_SESSION_SELECT_ROUTE = 38; // 0x26
+    field public static final int COMMAND_CODE_SESSION_SET_RATING = 28; // 0x1c
+    field public static final int COMMAND_CODE_SESSION_SUBSCRIBE_ROUTES_INFO = 36; // 0x24
+    field public static final int COMMAND_CODE_SESSION_UNSUBSCRIBE_ROUTES_INFO = 37; // 0x25
+    field public static final int COMMAND_CODE_VOLUME_ADJUST_VOLUME = 11; // 0xb
+    field public static final int COMMAND_CODE_VOLUME_SET_VOLUME = 10; // 0xa
+  }
+
+  public final class SessionCommandGroup2 {
+    ctor public SessionCommandGroup2();
+    ctor public SessionCommandGroup2(androidx.media.SessionCommandGroup2);
+    method public void addAllPredefinedCommands();
+    method public void addCommand(androidx.media.SessionCommand2);
+    method public void addCommand(int);
+    method public java.util.Set<androidx.media.SessionCommand2> getCommands();
+    method public boolean hasCommand(androidx.media.SessionCommand2);
+    method public boolean hasCommand(int);
+    method public void removeCommand(androidx.media.SessionCommand2);
+    method public void removeCommand(int);
+  }
+
+  public final class SessionToken2 {
+    method public static androidx.media.SessionToken2 fromBundle(android.os.Bundle);
+    method public java.lang.String getId();
+    method public java.lang.String getPackageName();
+    method public java.lang.String getServiceName();
+    method public int getType();
+    method public int getUid();
+    method public android.os.Bundle toBundle();
+    field public static final int TYPE_SESSION = 0; // 0x0
+  }
+
   public abstract class VolumeProviderCompat {
     ctor public VolumeProviderCompat(int, int, int);
     method public final int getCurrentVolume();
diff --git a/media/src/main/java/androidx/media/DataSourceDesc.java b/media/src/main/java/androidx/media/DataSourceDesc.java
index 7a4fe5c..ee047be 100644
--- a/media/src/main/java/androidx/media/DataSourceDesc.java
+++ b/media/src/main/java/androidx/media/DataSourceDesc.java
@@ -16,14 +16,11 @@
 
 package androidx.media;
 
-import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
 import android.content.Context;
 import android.net.Uri;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.annotation.RestrictTo;
 import androidx.core.util.Preconditions;
 
 import java.io.FileDescriptor;
@@ -36,16 +33,13 @@
 import java.util.Map;
 
 /**
- * @hide
  * Structure for data source descriptor.
  *
  * Used by {@link MediaPlayer2#setDataSource(DataSourceDesc)}
  * to set data source for playback.
  *
  * <p>Users should use {@link Builder} to change {@link DataSourceDesc}.
- *
  */
-@RestrictTo(LIBRARY_GROUP)
 public final class DataSourceDesc {
     /* No data source has been set yet */
     public static final int TYPE_NONE     = 0;
@@ -56,8 +50,23 @@
     /* data source is type of Uri */
     public static final int TYPE_URI      = 3;
 
-    // intentionally less than long.MAX_VALUE
-    public static final long LONG_MAX = 0x7ffffffffffffffL;
+    // intentionally less than long.MAX_VALUE.
+    // Declare this first to avoid 'illegal forward reference'.
+    private static final long LONG_MAX = 0x7ffffffffffffffL;
+
+    /**
+     * Used when a position is unknown.
+     *
+     * @see #getEndPosition()
+     */
+    public static final long POSITION_UNKNOWN = LONG_MAX;
+
+    /**
+     * Used when the length of file descriptor is unknown.
+     *
+     * @see #getFileDescriptorLength()
+     */
+    public static final long FD_LENGTH_UNKNOWN = LONG_MAX;
 
     private int mType = TYPE_NONE;
 
@@ -65,7 +74,7 @@
 
     private FileDescriptor mFD;
     private long mFDOffset = 0;
-    private long mFDLength = LONG_MAX;
+    private long mFDLength = FD_LENGTH_UNKNOWN;
 
     private Uri mUri;
     private Map<String, String> mUriHeader;
@@ -74,7 +83,7 @@
 
     private String mMediaId;
     private long mStartPositionMs = 0;
-    private long mEndPositionMs = LONG_MAX;
+    private long mEndPositionMs = POSITION_UNKNOWN;
 
     private DataSourceDesc() {
     }
@@ -83,7 +92,7 @@
      * Return the media Id of data source.
      * @return the media Id of data source
      */
-    public String getMediaId() {
+    public @Nullable String getMediaId() {
         return mMediaId;
     }
 
@@ -97,7 +106,7 @@
 
     /**
      * Return the position in milliseconds at which the playback will end.
-     * -1 means ending at the end of source content.
+     * {@link #POSITION_UNKNOWN} means ending at the end of source content.
      * @return the position in milliseconds at which the playback will end
      */
     public long getEndPosition() {
@@ -117,7 +126,7 @@
      * It's meaningful only when {@code getType} returns {@link #TYPE_CALLBACK}.
      * @return the Media2DataSource of this data source
      */
-    public Media2DataSource getMedia2DataSource() {
+    public @Nullable Media2DataSource getMedia2DataSource() {
         return mMedia2DataSource;
     }
 
@@ -126,7 +135,7 @@
      * It's meaningful only when {@code getType} returns {@link #TYPE_FD}.
      * @return the FileDescriptor of this data source
      */
-    public FileDescriptor getFileDescriptor() {
+    public @Nullable FileDescriptor getFileDescriptor() {
         return mFD;
     }
 
@@ -143,7 +152,7 @@
     /**
      * Return the content length associated with the FileDescriptor of this data source.
      * It's meaningful only when {@code getType} returns {@link #TYPE_FD}.
-     * -1 means same as the length of source content.
+     * {@link #FD_LENGTH_UNKNOWN} means same as the length of source content.
      * @return the content length associated with the FileDescriptor of this data source
      */
     public long getFileDescriptorLength() {
@@ -155,7 +164,7 @@
      * It's meaningful only when {@code getType} returns {@link #TYPE_URI}.
      * @return the Uri of this data source
      */
-    public Uri getUri() {
+    public @Nullable Uri getUri() {
         return mUri;
     }
 
@@ -164,7 +173,7 @@
      * It's meaningful only when {@code getType} returns {@link #TYPE_URI}.
      * @return the Uri headers of this data source
      */
-    public Map<String, String> getUriHeaders() {
+    public @Nullable Map<String, String> getUriHeaders() {
         if (mUriHeader == null) {
             return null;
         }
@@ -176,7 +185,7 @@
      * It's meaningful only when {@code getType} returns {@link #TYPE_URI}.
      * @return the Uri cookies of this data source
      */
-    public List<HttpCookie> getUriCookies() {
+    public @Nullable List<HttpCookie> getUriCookies() {
         if (mUriCookies == null) {
             return null;
         }
@@ -188,7 +197,7 @@
      * It's meaningful only when {@code getType} returns {@link #TYPE_URI}.
      * @return the Context used for resolving the Uri of this data source
      */
-    public Context getUriContext() {
+    public @Nullable Context getUriContext() {
         return mUriContext;
     }
 
@@ -213,7 +222,7 @@
 
         private FileDescriptor mFD;
         private long mFDOffset = 0;
-        private long mFDLength = LONG_MAX;
+        private long mFDLength = FD_LENGTH_UNKNOWN;
 
         private Uri mUri;
         private Map<String, String> mUriHeader;
@@ -222,7 +231,7 @@
 
         private String mMediaId;
         private long mStartPositionMs = 0;
-        private long mEndPositionMs = LONG_MAX;
+        private long mEndPositionMs = POSITION_UNKNOWN;
 
         /**
          * Constructs a new Builder with the defaults.
@@ -235,7 +244,7 @@
          * @param dsd the {@link DataSourceDesc} object whose data will be reused
          * in the new Builder.
          */
-        public Builder(DataSourceDesc dsd) {
+        public Builder(@NonNull DataSourceDesc dsd) {
             mType = dsd.mType;
             mMedia2DataSource = dsd.mMedia2DataSource;
             mFD = dsd.mFD;
@@ -258,7 +267,7 @@
          *
          * @return a new {@link DataSourceDesc} object
          */
-        public DataSourceDesc build() {
+        public @NonNull DataSourceDesc build() {
             if (mType != TYPE_CALLBACK
                     && mType != TYPE_FD
                     && mType != TYPE_URI) {
@@ -293,7 +302,7 @@
          * @param mediaId the media Id of this data source
          * @return the same Builder instance.
          */
-        public Builder setMediaId(String mediaId) {
+        public @NonNull Builder setMediaId(String mediaId) {
             mMediaId = mediaId;
             return this;
         }
@@ -306,7 +315,7 @@
          * @return the same Builder instance.
          *
          */
-        public Builder setStartPosition(long position) {
+        public @NonNull Builder setStartPosition(long position) {
             if (position < 0) {
                 position = 0;
             }
@@ -321,9 +330,9 @@
          * @param position the end position in milliseconds at which the playback will end
          * @return the same Builder instance.
          */
-        public Builder setEndPosition(long position) {
+        public @NonNull Builder setEndPosition(long position) {
             if (position < 0) {
-                position = LONG_MAX;
+                position = POSITION_UNKNOWN;
             }
             mEndPositionMs = position;
             return this;
@@ -336,7 +345,7 @@
          * @return the same Builder instance.
          * @throws NullPointerException if m2ds is null.
          */
-        public Builder setDataSource(@NonNull Media2DataSource m2ds) {
+        public @NonNull Builder setDataSource(@NonNull Media2DataSource m2ds) {
             Preconditions.checkNotNull(m2ds);
             resetDataSource();
             mType = TYPE_CALLBACK;
@@ -353,7 +362,7 @@
          * @return the same Builder instance.
          * @throws NullPointerException if fd is null.
          */
-        public Builder setDataSource(FileDescriptor fd) {
+        public @NonNull Builder setDataSource(@NonNull FileDescriptor fd) {
             Preconditions.checkNotNull(fd);
             resetDataSource();
             mType = TYPE_FD;
@@ -375,13 +384,14 @@
          * @return the same Builder instance.
          * @throws NullPointerException if fd is null.
          */
-        public Builder setDataSource(FileDescriptor fd, long offset, long length) {
+        public @NonNull Builder setDataSource(@NonNull FileDescriptor fd, long offset,
+                long length) {
             Preconditions.checkNotNull(fd);
             if (offset < 0) {
                 offset = 0;
             }
             if (length < 0) {
-                length = LONG_MAX;
+                length = FD_LENGTH_UNKNOWN;
             }
             resetDataSource();
             mType = TYPE_FD;
@@ -399,7 +409,7 @@
          * @return the same Builder instance.
          * @throws NullPointerException if context or uri is null.
          */
-        public Builder setDataSource(@NonNull Context context, @NonNull Uri uri) {
+        public @NonNull Builder setDataSource(@NonNull Context context, @NonNull Uri uri) {
             Preconditions.checkNotNull(context, "context cannot be null");
             Preconditions.checkNotNull(uri, "uri cannot be null");
             resetDataSource();
@@ -436,7 +446,7 @@
          * @throws IllegalArgumentException if the cookie handler is not of CookieManager type
          *                                  when cookies are provided.
          */
-        public Builder setDataSource(@NonNull Context context, @NonNull Uri uri,
+        public @NonNull Builder setDataSource(@NonNull Context context, @NonNull Uri uri,
                 @Nullable Map<String, String> headers, @Nullable List<HttpCookie> cookies) {
             Preconditions.checkNotNull(context, "context cannot be null");
             Preconditions.checkNotNull(uri);
@@ -467,7 +477,7 @@
             mMedia2DataSource = null;
             mFD = null;
             mFDOffset = 0;
-            mFDLength = LONG_MAX;
+            mFDLength = FD_LENGTH_UNKNOWN;
             mUri = null;
             mUriHeader = null;
             mUriCookies = null;
diff --git a/media/src/main/java/androidx/media/MediaController2.java b/media/src/main/java/androidx/media/MediaController2.java
index 05d61ef..7883654 100644
--- a/media/src/main/java/androidx/media/MediaController2.java
+++ b/media/src/main/java/androidx/media/MediaController2.java
@@ -127,6 +127,7 @@
 import android.util.Log;
 
 import androidx.annotation.GuardedBy;
+import androidx.annotation.IntDef;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
@@ -136,11 +137,12 @@
 import androidx.media.MediaSession2.ControllerInfo;
 import androidx.media.MediaSession2.ErrorCode;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.List;
 import java.util.concurrent.Executor;
 
 /**
- * @hide
  * Allows an app to interact with an active {@link MediaSession2} or a
  * {@link MediaSessionService2} in any status. Media buttons and other commands can be sent to
  * the session.
@@ -168,9 +170,27 @@
  * @see MediaSessionService2
  */
 @TargetApi(Build.VERSION_CODES.KITKAT)
-@RestrictTo(LIBRARY_GROUP)
 public class MediaController2 implements AutoCloseable {
     /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    @IntDef({AudioManager.ADJUST_LOWER, AudioManager.ADJUST_RAISE, AudioManager.ADJUST_SAME,
+            AudioManager.ADJUST_MUTE, AudioManager.ADJUST_UNMUTE, AudioManager.ADJUST_TOGGLE_MUTE})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface VolumeDirection {}
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    @IntDef(value = {AudioManager.FLAG_SHOW_UI, AudioManager.FLAG_ALLOW_RINGER_MODES,
+            AudioManager.FLAG_PLAY_SOUND, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE,
+            AudioManager.FLAG_VIBRATE}, flag = true)
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface VolumeFlags {}
+
+    /**
      * Interface for listening to change in activeness of the {@link MediaSession2}.  It's
      * active if and only if it has set a player.
      */
@@ -297,7 +317,6 @@
          * @param item new item
          * @see #onBufferingStateChanged(MediaController2, MediaItem2, int)
          */
-        // TODO(jaewan): Use this (b/74316764)
         public void onCurrentMediaItemChanged(@NonNull MediaController2 controller,
                 @NonNull MediaItem2 item) { }
 
@@ -525,7 +544,6 @@
 
         @Override
         public void onSessionEvent(String event, Bundle extras) {
-            // TODO: Call callbacks on the executor
             switch (event) {
                 case SESSION_EVENT_ON_ALLOWED_COMMANDS_CHANGED: {
                     SessionCommandGroup2 allowedCommands = SessionCommandGroup2.fromBundle(
@@ -666,7 +684,7 @@
     }
 
     private static final String TAG = "MediaController2";
-    private static final boolean DEBUG = true; // TODO(jaewan): Change
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     // Note: Using {@code null} doesn't helpful here because MediaBrowserServiceCompat always wraps
     //       the rootHints so it becomes non-null.
@@ -1090,7 +1108,7 @@
      * @param flags flags from {@link AudioManager} to include with the volume request for local
      *              playback
      */
-    public void setVolumeTo(int value, int flags) {
+    public void setVolumeTo(int value, @VolumeFlags int flags) {
         synchronized (mLock) {
             if (!mConnected) {
                 Log.w(TAG, "Session isn't active", new IllegalStateException());
@@ -1107,6 +1125,7 @@
      * Adjust the volume of the output this session is playing on. The direction
      * must be one of {@link AudioManager#ADJUST_LOWER},
      * {@link AudioManager#ADJUST_RAISE}, or {@link AudioManager#ADJUST_SAME}.
+     * <p>
      * The command will be ignored if the session does not support
      * {@link VolumeProviderCompat#VOLUME_CONTROL_RELATIVE} or
      * {@link VolumeProviderCompat#VOLUME_CONTROL_ABSOLUTE}.
@@ -1122,7 +1141,7 @@
      * @param flags flags from {@link AudioManager} to include with the volume request for local
      *              playback
      */
-    public void adjustVolume(int direction, int flags) {
+    public void adjustVolume(@VolumeDirection int direction, @VolumeFlags int flags) {
         synchronized (mLock) {
             if (!mConnected) {
                 Log.w(TAG, "Session isn't active", new IllegalStateException());
@@ -1274,7 +1293,6 @@
      */
     public @Nullable PlaybackInfo getPlaybackInfo() {
         synchronized (mLock) {
-            // TODO: update mPlaybackInfo via MediaControllerCompat.Callback.onAudioInfoChanged().
             return mPlaybackInfo;
         }
     }
@@ -1333,7 +1351,9 @@
      * implementation. Use media items returned here for other playlist agent APIs such as
      * {@link MediaPlaylistAgent#skipToPlaylistItem(MediaItem2)}.
      *
-     * @return playlist. Can be {@code null} if the controller doesn't have enough permission.
+     * @return playlist. Can be {@code null} if the playlist hasn't set nor controller doesn't have
+     *      enough permission.
+     * @see SessionCommand2#COMMAND_CODE_PLAYLIST_GET_LIST
      */
     public @Nullable List<MediaItem2> getPlaylist() {
         synchronized (mLock) {
@@ -1389,7 +1409,8 @@
 
     /**
      * Adds the media item to the playlist at position index. Index equals or greater than
-     * the current playlist size will add the item at the end of the playlist.
+     * the current playlist size (e.g. {@link Integer#MAX_VALUE}) will add the item at the end of
+     * the playlist.
      * <p>
      * This will not change the currently playing media item.
      * If index is less than or equal to the current index of the playlist,
@@ -1501,7 +1522,6 @@
      * @see MediaPlaylistAgent#REPEAT_MODE_GROUP
      */
     public void setRepeatMode(@RepeatMode int repeatMode) {
-        // TODO: check permission
         Bundle args = new Bundle();
         args.putInt(ARGUMENT_REPEAT_MODE, repeatMode);
         sendCommand(COMMAND_CODE_PLAYLIST_SET_REPEAT_MODE, args);
@@ -1530,7 +1550,6 @@
      * @see MediaPlaylistAgent#SHUFFLE_MODE_GROUP
      */
     public void setShuffleMode(@ShuffleMode int shuffleMode) {
-        // TODO: check permission
         Bundle args = new Bundle();
         args.putInt(ARGUMENT_SHUFFLE_MODE, shuffleMode);
         sendCommand(COMMAND_CODE_PLAYLIST_SET_SHUFFLE_MODE, args);
@@ -1570,7 +1589,6 @@
 
     // Should be used without a lock to prevent potential deadlock.
     void onConnectedNotLocked(Bundle data) {
-        // TODO: Getting mPlaybackInfo via MediaControllerCompat.Callback.onAudioInfoChanged()
         // is enough or should we pass it while connecting?
         final SessionCommandGroup2 allowedCommands = SessionCommandGroup2.fromBundle(
                 data.getBundle(ARGUMENT_ALLOWED_COMMANDS));
@@ -1580,13 +1598,14 @@
                 ARGUMENT_PLAYBACK_STATE_COMPAT);
         final int repeatMode = data.getInt(ARGUMENT_REPEAT_MODE);
         final int shuffleMode = data.getInt(ARGUMENT_SHUFFLE_MODE);
-        // TODO: Set mMediaMetadataCompat from the data.
         final List<MediaItem2> playlist = MediaUtils2.fromMediaItem2ParcelableArray(
                 data.getParcelableArray(ARGUMENT_PLAYLIST));
         final MediaItem2 currentMediaItem = MediaItem2.fromBundle(
                 data.getBundle(ARGUMENT_MEDIA_ITEM));
         final PlaybackInfo playbackInfo =
                 PlaybackInfo.fromBundle(data.getBundle(ARGUMENT_PLAYBACK_INFO));
+        final MediaMetadata2 metadata = MediaMetadata2.fromBundle(
+                data.getBundle(ARGUMENT_PLAYLIST_METADATA));
         if (DEBUG) {
             Log.d(TAG, "onConnectedNotLocked sessionCompatToken=" + mToken.getSessionCompatToken()
                     + ", allowedCommands=" + allowedCommands);
@@ -1611,10 +1630,10 @@
                 mShuffleMode = shuffleMode;
                 mPlaylist = playlist;
                 mCurrentMediaItem = currentMediaItem;
+                mPlaylistMetadata = metadata;
                 mConnected = true;
                 mPlaybackInfo = playbackInfo;
             }
-            // TODO(jaewan): Keep commands to prevents illegal API calls.
             mCallbackExecutor.execute(new Runnable() {
                 @Override
                 public void run() {
@@ -1634,8 +1653,6 @@
     }
 
     private void initialize() {
-        // TODO(jaewan): More sanity checks.
-        // TODO: Check the connection between 1.0 and 2.0 APIs
         if (mToken.getType() == SessionToken2.TYPE_SESSION) {
             synchronized (mLock) {
                 mBrowserCompat = null;
diff --git a/media/src/main/java/androidx/media/MediaItem2.java b/media/src/main/java/androidx/media/MediaItem2.java
index 20fbf06..b8c44c1 100644
--- a/media/src/main/java/androidx/media/MediaItem2.java
+++ b/media/src/main/java/androidx/media/MediaItem2.java
@@ -31,7 +31,6 @@
 import java.util.UUID;
 
 /**
- * @hide
  * A class with information on a single media item with the metadata information.
  * Media item are application dependent so we cannot guarantee that they contain the right values.
  * <p>
@@ -39,7 +38,6 @@
  * <p>
  * This object isn't a thread safe.
  */
-@RestrictTo(LIBRARY_GROUP)
 public class MediaItem2 {
     /** @hide */
     @RestrictTo(LIBRARY_GROUP)
@@ -298,7 +296,6 @@
             String id = (mMetadata != null)
                     ? mMetadata.getString(MediaMetadata2.METADATA_KEY_MEDIA_ID) : null;
             if (id == null) {
-                //  TODO(jaewan): Double check if its sufficient (e.g. Use UUID instead?)
                 id = (mMediaId != null) ? mMediaId : toString();
             }
             return new MediaItem2(id, mDataSourceDesc, mMetadata, mFlags);
diff --git a/media/src/main/java/androidx/media/MediaMetadata2.java b/media/src/main/java/androidx/media/MediaMetadata2.java
index f622bfc..0cfd237 100644
--- a/media/src/main/java/androidx/media/MediaMetadata2.java
+++ b/media/src/main/java/androidx/media/MediaMetadata2.java
@@ -34,14 +34,12 @@
 import java.util.Set;
 
 /**
- * @hide
  * Contains metadata about an item, such as the title, artist, etc.
  */
 // New version of MediaMetadata with following changes
 //   - Don't implement Parcelable for updatable support.
 //   - Also support MediaDescription features. MediaDescription is deprecated instead because
 //     it was insufficient for controller to display media contents.
-@RestrictTo(LIBRARY_GROUP)
 public final class MediaMetadata2 {
     private static final String TAG = "MediaMetadata2";
 
@@ -339,8 +337,7 @@
      * service providing the content. If used, this should be a persistent
      * unique key for the underlying content.  It may be used with
      * {@link MediaController2#playFromMediaId(String, Bundle)}
-     * to initiate playback when provided by a {@link MediaBrowser2} connected to
-     * the same app.
+     * to initiate playback.
      *
      * @see Builder#putText(String, CharSequence)
      * @see Builder#putString(String, String)
@@ -353,7 +350,7 @@
      * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
      * information about the Uri of the content. This value is specific to the service providing the
      * content. It may be used with {@link MediaController2#playFromUri(Uri, Bundle)}
-     * to initiate playback when provided by a {@link MediaBrowser2} connected to the same app.
+     * to initiate playback.
      *
      * @see Builder#putText(String, CharSequence)
      * @see Builder#putString(String, String)
@@ -714,7 +711,6 @@
         if (key == null) {
             throw new IllegalArgumentException("key shouldn't be null");
         }
-        // TODO(jaewan): Add backward compatibility
         Rating2 rating = null;
         try {
             rating = Rating2.fromBundle(mBundle.getBundle(key));
@@ -887,7 +883,6 @@
          * <li>{@link #METADATA_KEY_DISPLAY_ICON_URI}</li>
          * <li>{@link #METADATA_KEY_MEDIA_ID}</li>
          * <li>{@link #METADATA_KEY_MEDIA_URI}</li>
-         * <li>{@link #METADATA_KEY_RADIO_PROGRAM_NAME}</li>
          * </ul>
          *
          * @param key The key for referencing this value
@@ -932,7 +927,6 @@
          * <li>{@link #METADATA_KEY_DISPLAY_ICON_URI}</li>
          * <li>{@link #METADATA_KEY_MEDIA_ID}</li>
          * <li>{@link #METADATA_KEY_MEDIA_URI}</li>
-         * <li>{@link #METADATA_KEY_RADIO_PROGRAM_NAME}</li>
          * </ul>
          *
          * @param key The key for referencing this value
diff --git a/media/src/main/java/androidx/media/MediaPlayerBase.java b/media/src/main/java/androidx/media/MediaPlayerBase.java
index 6854ae0..de0e128 100644
--- a/media/src/main/java/androidx/media/MediaPlayerBase.java
+++ b/media/src/main/java/androidx/media/MediaPlayerBase.java
@@ -32,11 +32,9 @@
 import java.util.concurrent.Executor;
 
 /**
- * @hide
  * Base class for all media players that want media session.
  */
 @TargetApi(Build.VERSION_CODES.KITKAT)
-@RestrictTo(LIBRARY_GROUP)
 public abstract class MediaPlayerBase implements AutoCloseable {
     /**
      * @hide
diff --git a/media/src/main/java/androidx/media/MediaPlaylistAgent.java b/media/src/main/java/androidx/media/MediaPlaylistAgent.java
index 802512d..07838e8 100644
--- a/media/src/main/java/androidx/media/MediaPlaylistAgent.java
+++ b/media/src/main/java/androidx/media/MediaPlaylistAgent.java
@@ -33,7 +33,6 @@
 import java.util.concurrent.Executor;
 
 /**
- * @hide
  * MediaPlaylistAgent is the abstract class an application needs to derive from to pass an object
  * to a MediaSession2 that will override default playlist handling behaviors. It contains a set of
  * notify methods to signal MediaSession2 that playlist-related state has changed.
@@ -43,7 +42,6 @@
  * Used by {@link MediaSession2} and {@link MediaController2}.
  */
 // This class only includes methods that contain {@link MediaItem2}.
-@RestrictTo(LIBRARY_GROUP)
 public abstract class MediaPlaylistAgent {
     private static final String TAG = "MediaPlaylistAgent";
 
@@ -151,7 +149,11 @@
     }
 
     /**
-     * TODO: add javadoc
+     * Notifies the current playlist and playlist metadata. Call this API when the playlist is
+     * changed.
+     * <p>
+     * Registered {@link PlaylistEventCallback} would receive this event through the
+     * {@link PlaylistEventCallback#onPlaylistChanged(MediaPlaylistAgent, List, MediaMetadata2)}.
      */
     public final void notifyPlaylistChanged() {
         SimpleArrayMap<PlaylistEventCallback, Executor> callbacks = getCallbacks();
@@ -171,7 +173,10 @@
     }
 
     /**
-     * TODO: add javadoc
+     * Notifies the current playlist metadata. Call this API when the playlist metadata is changed.
+     * <p>
+     * Registered {@link PlaylistEventCallback} would receive this event through the
+     * {@link PlaylistEventCallback#onPlaylistMetadataChanged(MediaPlaylistAgent, MediaMetadata2)}.
      */
     public final void notifyPlaylistMetadataChanged() {
         SimpleArrayMap<PlaylistEventCallback, Executor> callbacks = getCallbacks();
@@ -189,7 +194,10 @@
     }
 
     /**
-     * TODO: add javadoc
+     * Notifies the current shuffle mode. Call this API when the shuffle mode is changed.
+     * <p>
+     * Registered {@link PlaylistEventCallback} would receive this event through the
+     * {@link PlaylistEventCallback#onShuffleModeChanged(MediaPlaylistAgent, int)}.
      */
     public final void notifyShuffleModeChanged() {
         SimpleArrayMap<PlaylistEventCallback, Executor> callbacks = getCallbacks();
@@ -207,7 +215,10 @@
     }
 
     /**
-     * TODO: add javadoc
+     * Notifies the current repeat mode. Call this API when the repeat mode is changed.
+     * <p>
+     * Registered {@link PlaylistEventCallback} would receive this event through the
+     * {@link PlaylistEventCallback#onRepeatModeChanged(MediaPlaylistAgent, int)}.
      */
     public final void notifyRepeatModeChanged() {
         SimpleArrayMap<PlaylistEventCallback, Executor> callbacks = getCallbacks();
@@ -232,10 +243,14 @@
     public abstract @Nullable List<MediaItem2> getPlaylist();
 
     /**
-     * Sets the playlist.
+     * Sets the playlist with the metadata.
+     * <p>
+     * When the playlist is changed, call {@link #notifyPlaylistChanged()} to notify changes to the
+     * registered callbacks.
      *
      * @param list playlist
      * @param metadata metadata of the playlist
+     * @see #notifyPlaylistChanged()
      */
     public abstract void setPlaylist(@NonNull List<MediaItem2> list,
             @Nullable MediaMetadata2 metadata);
@@ -248,9 +263,13 @@
     public abstract @Nullable MediaMetadata2 getPlaylistMetadata();
 
     /**
-     * Updates the playlist metadata
+     * Updates the playlist metadata.
+     * <p>
+     * When the playlist metadata is changed, call {@link #notifyPlaylistMetadataChanged()} to
+     * notify changes to the registered callbacks.
      *
      * @param metadata metadata of the playlist
+     * @see #notifyPlaylistMetadataChanged()
      */
     public abstract void updatePlaylistMetadata(@Nullable MediaMetadata2 metadata);
 
@@ -261,7 +280,8 @@
 
     /**
      * Adds the media item to the playlist at position index. Index equals or greater than
-     * the current playlist size will add the item at the end of the playlist.
+     * the current playlist size (e.g. {@link Integer#MAX_VALUE}) will add the item at the end of
+     * the playlist.
      * <p>
      * This will not change the currently playing media item.
      * If index is less than or equal to the current index of the playlist,
@@ -317,13 +337,17 @@
     public abstract @RepeatMode int getRepeatMode();
 
     /**
-     * Sets the repeat mode
+     * Sets the repeat mode.
+     * <p>
+     * When the repeat mode is changed, call {@link #notifyRepeatModeChanged()} to notify changes
+     * to the registered callbacks.
      *
      * @param repeatMode repeat mode
      * @see #REPEAT_MODE_NONE
      * @see #REPEAT_MODE_ONE
      * @see #REPEAT_MODE_ALL
      * @see #REPEAT_MODE_GROUP
+     * @see #notifyRepeatModeChanged()
      */
     public abstract void setRepeatMode(@RepeatMode int repeatMode);
 
@@ -338,12 +362,16 @@
     public abstract @ShuffleMode int getShuffleMode();
 
     /**
-     * Sets the shuffle mode
+     * Sets the shuffle mode.
+     * <p>
+     * When the shuffle mode is changed, call {@link #notifyShuffleModeChanged()} to notify changes
+     * to the registered callbacks.
      *
      * @param shuffleMode The shuffle mode
      * @see #SHUFFLE_MODE_NONE
      * @see #SHUFFLE_MODE_ALL
      * @see #SHUFFLE_MODE_GROUP
+     * @see #notifyShuffleModeChanged()
      */
     public abstract void setShuffleMode(@ShuffleMode int shuffleMode);
 
diff --git a/media/src/main/java/androidx/media/MediaSession2.java b/media/src/main/java/androidx/media/MediaSession2.java
index 2ecb7ce..9f0d0a9 100644
--- a/media/src/main/java/androidx/media/MediaSession2.java
+++ b/media/src/main/java/androidx/media/MediaSession2.java
@@ -48,7 +48,6 @@
 import java.util.concurrent.Executor;
 
 /**
- * @hide
  * Allows a media app to expose its transport controls and playback information in a process to
  * other processes including the Android framework and other apps. Common use cases are as follows.
  * <ul>
@@ -81,7 +80,6 @@
  * @see MediaSessionService2
  */
 @TargetApi(Build.VERSION_CODES.KITKAT)
-@RestrictTo(LIBRARY_GROUP)
 public class MediaSession2 extends MediaInterface2.SessionPlayer implements AutoCloseable {
     /**
      * @hide
@@ -163,21 +161,18 @@
     public static final int ERROR_CODE_SETUP_REQUIRED = 12;
 
     /**
-     * TODO: Fix {link DataSourceDesc}
      * Interface definition of a callback to be invoked when a {@link MediaItem2} in the playlist
-     * didn't have a {link DataSourceDesc} but it's needed now for preparing or playing it.
+     * didn't have a {@link DataSourceDesc} but it's needed now for preparing or playing it.
      *
      * #see #setOnDataSourceMissingHelper
      */
     public interface OnDataSourceMissingHelper {
         /**
-         * TODO: Fix {link DataSourceDesc}
-         * Called when a {@link MediaItem2} in the playlist didn't have a {link DataSourceDesc}
+         * Called when a {@link MediaItem2} in the playlist didn't have a {@link DataSourceDesc}
          * but it's needed now for preparing or playing it. Returned data source descriptor will be
          * sent to the player directly to prepare or play the contents.
          * <p>
-         * TODO: Fix {link DataSourceDesc}
-         * An exception may be thrown if the returned {link DataSourceDesc} is duplicated in the
+         * An exception may be thrown if the returned {@link DataSourceDesc} is duplicated in the
          * playlist, so items cannot be differentiated.
          *
          * @param session the session for this event
@@ -195,7 +190,6 @@
      * If it's not set, the session will accept all controllers and all incoming commands by
      * default.
      */
-    // TODO(jaewan): Move this to updatable for default implementation (b/74091963)
     public abstract static class SessionCallback {
         /**
          * Called when a controller is created for this session. Return allowed commands for
@@ -472,7 +466,6 @@
          * @param player the player for this event
          * @param item new item
          */
-        // TODO(jaewan): Use this (b/74316764)
         public void onCurrentMediaItemChanged(@NonNull MediaSession2 session,
                 @NonNull MediaPlayerBase player, @NonNull MediaItem2 item) { }
 
@@ -788,7 +781,7 @@
     public static final class ControllerInfo {
         private final int mUid;
         private final String mPackageName;
-        // TODO: IMediaControllerCallback should be used only for MediaSession2ImplBase
+        // Note: IMediaControllerCallback should be used only for MediaSession2ImplBase
         private final IMediaControllerCallback mIControllerCallback;
         private final boolean mIsTrusted;
 
@@ -801,7 +794,7 @@
             mUid = uid;
             mPackageName = packageName;
             mIControllerCallback = callback;
-            mIsTrusted = isTrusted();
+            mIsTrusted = false;
         }
 
         /**
@@ -824,11 +817,11 @@
          * command request.
          *
          * @return {@code true} if the controller is trusted.
+         * @hide
          */
-        // TODO: Remove this API
+        @RestrictTo(LIBRARY_GROUP)
         public boolean isTrusted() {
-            //return mProvider.isTrusted_impl();
-            return false;
+            return mIsTrusted;
         }
 
         IBinder getId() {
@@ -860,7 +853,6 @@
          */
         @RestrictTo(LIBRARY_GROUP)
         public @NonNull Bundle toBundle() {
-            // TODO: Fill here.
             return new Bundle();
         }
 
@@ -870,7 +862,6 @@
          */
         @RestrictTo(LIBRARY_GROUP)
         public static @NonNull ControllerInfo fromBundle(@NonNull Context context, Bundle bundle) {
-            // TODO: Fill here.
             return new ControllerInfo(context, -1, -1, "TODO", null);
         }
 
@@ -951,7 +942,7 @@
         }
 
         /**
-         * Return whether it's enabled
+         * Return whether it's enabled.
          *
          * @return {@code true} if enabled. {@code false} otherwise.
          */
@@ -1008,7 +999,10 @@
             private boolean mEnabled;
 
             /**
-             * TODO: javadoc
+             * Sets the {@link SessionCommand2} that would be sent to the session when the button
+             * is clicked.
+             *
+             * @param command session command
              */
             public @NonNull Builder setCommand(@Nullable SessionCommand2 command) {
                 mCommand = command;
@@ -1016,7 +1010,13 @@
             }
 
             /**
-             * TODO: javadoc
+             * Sets the bitmap-type (e.g. PNG) icon resource id of the button.
+             * <p>
+             * None bitmap type (e.g. VectorDrawabale) may cause unexpected behavior when it's sent
+             * to {@link MediaController2} app, so please avoid using it especially for the older
+             * platform (API < 21).
+             *
+             * @param resId resource id of the button
              */
             public @NonNull Builder setIconResId(int resId) {
                 mIconResId = resId;
@@ -1024,7 +1024,9 @@
             }
 
             /**
-             * TODO: javadoc
+             * Sets the display name of the button.
+             *
+             * @param displayName display name of the button
              */
             public @NonNull Builder setDisplayName(@Nullable String displayName) {
                 mDisplayName = displayName;
@@ -1032,7 +1034,11 @@
             }
 
             /**
-             * TODO: javadoc
+             * Sets whether the button is enabled. Can be {@code false} to indicate that the button
+             * should be shown but isn't clickable.
+             *
+             * @param enabled {@code true} if the button is enabled and ready.
+             *          {@code false} otherwise.
              */
             public @NonNull Builder setEnabled(boolean enabled) {
                 mEnabled = enabled;
@@ -1040,7 +1046,9 @@
             }
 
             /**
-             * TODO: javadoc
+             * Sets the extras of the button.
+             *
+             * @param extras extras information of the button
              */
             public @NonNull Builder setExtras(@Nullable Bundle extras) {
                 mExtras = extras;
@@ -1048,7 +1056,9 @@
             }
 
             /**
-             * TODO: javadoc
+             * Builds the {@link CommandButton}.
+             *
+             * @return a new {@link CommandButton}
              */
             public @NonNull CommandButton build() {
                 return new CommandButton(mCommand, mIconResId, mDisplayName, mExtras, mEnabled);
@@ -1170,7 +1180,9 @@
     }
 
     /**
-     * TODO: add javadoc
+     * Returns the list of connected controller.
+     *
+     * @return list of {@link ControllerInfo}
      */
     public @NonNull List<ControllerInfo> getConnectedControllers() {
         return mImpl.getConnectedControllers();
@@ -1409,14 +1421,12 @@
      * Sets the data source missing helper. Helper will be used to provide default implementation of
      * {@link MediaPlaylistAgent} when it isn't set by developer.
      * <p>
-     * TODO: Fix {link DataSourceDesc}
      * Default implementation of the {@link MediaPlaylistAgent} will call helper when a
-     * {@link MediaItem2} in the playlist doesn't have a {link DataSourceDesc}. This may happen
+     * {@link MediaItem2} in the playlist doesn't have a {@link DataSourceDesc}. This may happen
      * when
      * <ul>
-     * TODO: Fix {link DataSourceDesc}
      *      <li>{@link MediaItem2} specified by {@link #setPlaylist(List, MediaMetadata2)} doesn't
-     *          have {link DataSourceDesc}</li>
+     *          have {@link DataSourceDesc}</li>
      *      <li>{@link MediaController2#addPlaylistItem(int, MediaItem2)} is called and accepted
      *          by {@link SessionCallback#onCommandRequest(
      *          MediaSession2, ControllerInfo, SessionCommand2)}.
@@ -1477,8 +1487,7 @@
      * list. Wait for {@link SessionCallback#onPlaylistChanged(MediaSession2, MediaPlaylistAgent,
      * List, MediaMetadata2)} to know the operation finishes.
      * <p>
-     * TODO: Fix {link DataSourceDesc}
-     * You may specify a {@link MediaItem2} without {link DataSourceDesc}. In that case,
+     * You may specify a {@link MediaItem2} without {@link DataSourceDesc}. In that case,
      * {@link MediaPlaylistAgent} has responsibility to dynamically query {link DataSourceDesc}
      * when such media item is ready for preparation or play. Default implementation needs
      * {@link OnDataSourceMissingHelper} for such case.
@@ -1551,7 +1560,8 @@
 
     /**
      * Adds the media item to the playlist at position index. Index equals or greater than
-     * the current playlist size will add the item at the end of the playlist.
+     * the current playlist size (e.g. {@link Integer#MAX_VALUE}) will add the item at the end of
+     * the playlist.
      * <p>
      * This will not change the currently playing media item.
      * If index is less than or equal to the current index of the play list,
diff --git a/media/src/main/java/androidx/media/MediaSession2ImplBase.java b/media/src/main/java/androidx/media/MediaSession2ImplBase.java
index 989475a..e474b45 100644
--- a/media/src/main/java/androidx/media/MediaSession2ImplBase.java
+++ b/media/src/main/java/androidx/media/MediaSession2ImplBase.java
@@ -60,7 +60,7 @@
 @TargetApi(Build.VERSION_CODES.KITKAT)
 class MediaSession2ImplBase extends MediaSession2.SupportLibraryImpl {
     static final String TAG = "MS2ImplBase";
-    static final boolean DEBUG = true; // TODO: Log.isLoggable(TAG, Log.DEBUG);
+    static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     private final Object mLock = new Object();
 
diff --git a/media/src/main/java/androidx/media/MediaSession2StubImplBase.java b/media/src/main/java/androidx/media/MediaSession2StubImplBase.java
index 5fb31b7..48e641e 100644
--- a/media/src/main/java/androidx/media/MediaSession2StubImplBase.java
+++ b/media/src/main/java/androidx/media/MediaSession2StubImplBase.java
@@ -75,6 +75,7 @@
 import static androidx.media.SessionCommand2.COMMAND_CODE_PLAYBACK_SEEK_TO;
 import static androidx.media.SessionCommand2.COMMAND_CODE_PLAYBACK_SET_SPEED;
 import static androidx.media.SessionCommand2.COMMAND_CODE_PLAYLIST_ADD_ITEM;
+import static androidx.media.SessionCommand2.COMMAND_CODE_PLAYLIST_GET_CURRENT_MEDIA_ITEM;
 import static androidx.media.SessionCommand2.COMMAND_CODE_PLAYLIST_GET_LIST;
 import static androidx.media.SessionCommand2.COMMAND_CODE_PLAYLIST_REMOVE_ITEM;
 import static androidx.media.SessionCommand2.COMMAND_CODE_PLAYLIST_REPLACE_ITEM;
@@ -131,7 +132,7 @@
 class MediaSession2StubImplBase extends MediaSessionCompat.Callback {
 
     private static final String TAG = "MS2StubImplBase";
-    private static final boolean DEBUG = true; // TODO: Log.isLoggable(TAG, Log.DEBUG);
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     private static final SparseArray<SessionCommand2> sCommandsForOnCommandRequest =
             new SparseArray<>();
@@ -531,7 +532,7 @@
     }
 
     void notifyCurrentMediaItemChanged(final MediaItem2 item) {
-        notifyAll(COMMAND_CODE_PLAYLIST_GET_LIST, new Session2Runnable() {
+        notifyAll(COMMAND_CODE_PLAYLIST_GET_CURRENT_MEDIA_ITEM, new Session2Runnable() {
             @Override
             public void run(ControllerInfo controller) throws RemoteException {
                 Bundle bundle = new Bundle();
@@ -622,7 +623,7 @@
 
     void notifyPlaylistChanged(final List<MediaItem2> playlist,
             final MediaMetadata2 metadata) {
-        notifyAll(SessionCommand2.COMMAND_CODE_PLAYLIST_GET_LIST, new Session2Runnable() {
+        notifyAll(COMMAND_CODE_PLAYLIST_GET_LIST, new Session2Runnable() {
             @Override
             public void run(ControllerInfo controller) throws RemoteException {
                 Bundle bundle = new Bundle();
@@ -866,29 +867,29 @@
                             allowedCommands.toBundle());
                     resultData.putInt(ARGUMENT_PLAYER_STATE, mSession.getPlayerState());
                     resultData.putInt(ARGUMENT_BUFFERING_STATE, mSession.getBufferingState());
-                    synchronized (mLock) {
-                        resultData.putParcelable(ARGUMENT_PLAYBACK_STATE_COMPAT,
-                                mSession.getPlaybackStateCompat());
-                        // TODO: Insert MediaMetadataCompat
-                    }
+                    resultData.putParcelable(ARGUMENT_PLAYBACK_STATE_COMPAT,
+                            mSession.getPlaybackStateCompat());
                     resultData.putInt(ARGUMENT_REPEAT_MODE, mSession.getRepeatMode());
                     resultData.putInt(ARGUMENT_SHUFFLE_MODE, mSession.getShuffleMode());
                     final List<MediaItem2> playlist = allowedCommands.hasCommand(
-                            SessionCommand2.COMMAND_CODE_PLAYLIST_GET_LIST)
-                            ? mSession.getPlaylist() : null;
+                            COMMAND_CODE_PLAYLIST_GET_LIST) ? mSession.getPlaylist() : null;
                     if (playlist != null) {
                         resultData.putParcelableArray(ARGUMENT_PLAYLIST,
                                 MediaUtils2.toMediaItem2ParcelableArray(playlist));
                     }
                     final MediaItem2 currentMediaItem =
-                            allowedCommands.hasCommand(COMMAND_CODE_PLAYLIST_GET_LIST)
+                            allowedCommands.hasCommand(COMMAND_CODE_PLAYLIST_GET_CURRENT_MEDIA_ITEM)
                                     ? mSession.getCurrentMediaItem() : null;
                     if (currentMediaItem != null) {
                         resultData.putBundle(ARGUMENT_MEDIA_ITEM, currentMediaItem.toBundle());
                     }
                     resultData.putBundle(ARGUMENT_PLAYBACK_INFO,
                             mSession.getPlaybackInfo().toBundle());
-
+                    final MediaMetadata2 playlistMetadata = mSession.getPlaylistMetadata();
+                    if (playlistMetadata != null) {
+                        resultData.putBundle(ARGUMENT_PLAYLIST_METADATA,
+                                playlistMetadata.toBundle());
+                    }
                     // Double check if session is still there, because close() can be
                     // called in another thread.
                     if (mSession.isClosed()) {
diff --git a/media/src/main/java/androidx/media/Rating2.java b/media/src/main/java/androidx/media/Rating2.java
index 28f7c70..8c81331 100644
--- a/media/src/main/java/androidx/media/Rating2.java
+++ b/media/src/main/java/androidx/media/Rating2.java
@@ -30,7 +30,6 @@
 import java.lang.annotation.RetentionPolicy;
 
 /**
- * @hide
  * A class to encapsulate rating information used as content metadata.
  * A rating is defined by its rating style (see {@link #RATING_HEART},
  * {@link #RATING_THUMB_UP_DOWN}, {@link #RATING_3_STARS}, {@link #RATING_4_STARS},
@@ -40,7 +39,6 @@
  */
 // New version of Rating with following change
 //   - Don't implement Parcelable for updatable support.
-@RestrictTo(LIBRARY_GROUP)
 public final class Rating2 {
     /**
      * @hide
diff --git a/media/src/main/java/androidx/media/SessionCommand2.java b/media/src/main/java/androidx/media/SessionCommand2.java
index aca8234..f017941 100644
--- a/media/src/main/java/androidx/media/SessionCommand2.java
+++ b/media/src/main/java/androidx/media/SessionCommand2.java
@@ -31,14 +31,12 @@
 import java.util.List;
 
 /**
- * @hide
  * Define a command that a {@link MediaController2} can send to a {@link MediaSession2}.
  * <p>
  * If {@link #getCommandCode()} isn't {@link #COMMAND_CODE_CUSTOM}), it's predefined command.
  * If {@link #getCommandCode()} is {@link #COMMAND_CODE_CUSTOM}), it's custom command and
  * {@link #getCustomCommand()} shouldn't be {@code null}.
  */
-@RestrictTo(LIBRARY_GROUP)
 public final class SessionCommand2 {
     /**
      * Command code for the custom command which can be defined by string action in the
@@ -194,10 +192,6 @@
     /**
      * Command code for {@link MediaController2#getPlaylist()}. This will expose metadata
      * information to the controller.
-     * <p>
-     * Command would be sent directly to the playlist agent if the session doesn't reject the
-     * request through the
-     * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, SessionCommand2)}.
      */
     public static final int COMMAND_CODE_PLAYLIST_GET_LIST = 18;
 
@@ -213,10 +207,6 @@
     /**
      * Command code for {@link MediaController2#getPlaylistMetadata()}. This will expose
      * metadata information to the controller.
-     * <p>
-     * Command would be sent directly to the playlist agent if the session doesn't reject the
-     * request through the
-     * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, SessionCommand2)}.
      */
     public static final int COMMAND_CODE_PLAYLIST_GET_LIST_METADATA = 20;
 
@@ -230,6 +220,12 @@
     public static final int COMMAND_CODE_PLAYLIST_SET_LIST_METADATA = 21;
 
     /**
+     * Command code for {@link MediaController2#getCurrentMediaItem()}. This will expose
+     * metadata information to the controller.
+     */
+    public static final int COMMAND_CODE_PLAYLIST_GET_CURRENT_MEDIA_ITEM = 20;
+
+    /**
      * Command code for {@link MediaController2#playFromMediaId(String, Bundle)}.
      */
     public static final int COMMAND_CODE_SESSION_PLAY_FROM_MEDIA_ID = 22;
@@ -279,40 +275,53 @@
      */
     public static final int COMMAND_CODE_SESSION_SELECT_ROUTE = 38;
 
-
     /**
+     * @hide
      * Command code for {@link MediaBrowser2#getChildren(String, int, int, Bundle)}.
      */
+    @RestrictTo(LIBRARY_GROUP)
     public static final int COMMAND_CODE_LIBRARY_GET_CHILDREN = 29;
 
     /**
+     * @hide
      * Command code for {@link MediaBrowser2#getItem(String)}.
      */
+    @RestrictTo(LIBRARY_GROUP)
     public static final int COMMAND_CODE_LIBRARY_GET_ITEM = 30;
 
     /**
+     * @hide
      * Command code for {@link MediaBrowser2#getLibraryRoot(Bundle)}.
      */
+    @RestrictTo(LIBRARY_GROUP)
     public static final int COMMAND_CODE_LIBRARY_GET_LIBRARY_ROOT = 31;
 
     /**
+     * @hide
      * Command code for {@link MediaBrowser2#getSearchResult(String, int, int, Bundle)}.
      */
+    @RestrictTo(LIBRARY_GROUP)
     public static final int COMMAND_CODE_LIBRARY_GET_SEARCH_RESULT = 32;
 
     /**
+     * @hide
      * Command code for {@link MediaBrowser2#search(String, Bundle)}.
      */
+    @RestrictTo(LIBRARY_GROUP)
     public static final int COMMAND_CODE_LIBRARY_SEARCH = 33;
 
     /**
+     * @hide
      * Command code for {@link MediaBrowser2#subscribe(String, Bundle)}.
      */
+    @RestrictTo(LIBRARY_GROUP)
     public static final int COMMAND_CODE_LIBRARY_SUBSCRIBE = 34;
 
     /**
+     * @hide
      * Command code for {@link MediaBrowser2#unsubscribe(String)}.
      */
+    @RestrictTo(LIBRARY_GROUP)
     public static final int COMMAND_CODE_LIBRARY_UNSUBSCRIBE = 35;
 
     /**
@@ -429,7 +438,6 @@
             return false;
         }
         SessionCommand2 other = (SessionCommand2) obj;
-        // TODO(jaewan): Compare Commands with the generated UUID, as we're doing for the MI2.
         return mCommandCode == other.mCommandCode
                 && TextUtils.equals(mCustomCommand, other.mCustomCommand);
     }
diff --git a/media/src/main/java/androidx/media/SessionCommandGroup2.java b/media/src/main/java/androidx/media/SessionCommandGroup2.java
index af4d189..691eb70 100644
--- a/media/src/main/java/androidx/media/SessionCommandGroup2.java
+++ b/media/src/main/java/androidx/media/SessionCommandGroup2.java
@@ -34,10 +34,8 @@
 import java.util.Set;
 
 /**
- * @hide
  * A set of {@link SessionCommand2} which represents a command group.
  */
-@RestrictTo(LIBRARY_GROUP)
 public final class SessionCommandGroup2 {
 
     private static final String TAG = "SessionCommandGroup2";
@@ -114,7 +112,6 @@
     }
 
     private void addCommandsWithPrefix(String prefix) {
-        // TODO(jaewan): (Can be post-P): Don't use reflection for this purpose.
         final Field[] fields = SessionCommand2.class.getFields();
         if (fields != null) {
             for (int i = 0; i < fields.length; i++) {
diff --git a/media/src/main/java/androidx/media/SessionToken2.java b/media/src/main/java/androidx/media/SessionToken2.java
index 6b6021a..eb42297 100644
--- a/media/src/main/java/androidx/media/SessionToken2.java
+++ b/media/src/main/java/androidx/media/SessionToken2.java
@@ -30,6 +30,7 @@
 
 import androidx.annotation.IntDef;
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
 
 import java.lang.annotation.Retention;
@@ -37,9 +38,7 @@
 import java.util.List;
 
 /**
- * @hide
- * Represents an ongoing {@link MediaSession2} or a {@link MediaSessionService2}.
- * If it's representing a session service, it may not be ongoing.
+ * Represents an ongoing {@link MediaSession2}.
  * <p>
  * This may be passed to apps by the session owner to allow them to create a
  * {@link MediaController2} to communicate with the session.
@@ -50,15 +49,31 @@
 //   - Stop implementing Parcelable for updatable support
 //   - Represent session and library service (formerly browser service) in one class.
 //     Previously MediaSession.Token was for session and ComponentName was for service.
-@RestrictTo(LIBRARY_GROUP)
 public final class SessionToken2 {
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(value = {TYPE_SESSION, TYPE_SESSION_SERVICE, TYPE_LIBRARY_SERVICE})
     public @interface TokenType {
     }
 
+    /**
+     * Type for {@link MediaSession2}.
+     */
     public static final int TYPE_SESSION = 0;
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
     public static final int TYPE_SESSION_SERVICE = 1;
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
     public static final int TYPE_LIBRARY_SERVICE = 2;
 
     //private final SessionToken2Provider mProvider;
@@ -79,14 +94,17 @@
     private final String mServiceName;
     private final String mId;
     private final MediaSessionCompat.Token mSessionCompatToken;
+    private final ComponentName mComponentName;
 
     /**
+     * @hide
      * Constructor for the token. You can only create token for session service or library service
      * to use by {@link MediaController2} or {@link MediaBrowser2}.
      *
      * @param context The context.
      * @param serviceComponent The component name of the media browser service.
      */
+    @RestrictTo(LIBRARY_GROUP)
     public SessionToken2(@NonNull Context context, @NonNull ComponentName serviceComponent) {
         this(context, serviceComponent, UID_UNKNOWN);
     }
@@ -106,6 +124,7 @@
         if (serviceComponent == null) {
             throw new IllegalArgumentException("serviceComponent shouldn't be null");
         }
+        mComponentName = serviceComponent;
         mPackageName = serviceComponent.getPackageName();
         mServiceName = serviceComponent.getClassName();
         // Calculate uid if it's not specified.
@@ -117,11 +136,9 @@
                 throw new IllegalArgumentException("Cannot find package " + mPackageName);
             }
         }
-
         mUid = uid;
 
         // Infer id and type from package name and service name
-        // TODO(jaewan): Handle multi-user.
         String id = getSessionIdFromService(manager, MediaLibraryService2.SERVICE_INTERFACE,
                 serviceComponent);
         if (id != null) {
@@ -144,12 +161,14 @@
      * @hide
      */
     @RestrictTo(LIBRARY_GROUP)
-    public SessionToken2(int uid, int type, String packageName, String serviceName,
+    SessionToken2(int uid, int type, String packageName, String serviceName,
             String id, MediaSessionCompat.Token sessionCompatToken) {
         mUid = uid;
         mType = type;
         mPackageName = packageName;
         mServiceName = serviceName;
+        mComponentName = (mType == TYPE_SESSION) ? null
+                : new ComponentName(packageName, serviceName);
         mId = id;
         mSessionCompatToken = sessionCompatToken;
     }
@@ -193,14 +212,14 @@
     /**
      * @return package name
      */
-    public String getPackageName() {
+    public @NonNull String getPackageName() {
         return mPackageName;
     }
 
     /**
-     * @return service name
+     * @return service name. Can be {@code null} for TYPE_SESSION.
      */
-    public String getServiceName() {
+    public @Nullable String getServiceName() {
         return mServiceName;
     }
 
@@ -210,8 +229,7 @@
      */
     @RestrictTo(LIBRARY_GROUP)
     public ComponentName getComponentName() {
-        // TODO: Cache the component name?
-        return mType == TYPE_SESSION ? null : new ComponentName(mPackageName, mServiceName);
+        return mComponentName;
     }
 
     /**
@@ -224,7 +242,6 @@
     /**
      * @return type of the token
      * @see #TYPE_SESSION
-     * @see #TYPE_SESSION_SERVICE
      */
     public @TokenType int getType() {
         return mType;