method public void adjustVolume(int, int);
method public android.media.routing.MediaRouter.Delegate createMediaRouterDelegate();
method public boolean dispatchMediaButtonEvent(android.view.KeyEvent);
+ method public android.media.session.MediaController.AudioInfo getAudioInfo();
method public android.os.Bundle getExtras();
method public long getFlags();
method public android.app.PendingIntent getLaunchActivity();
method public android.media.MediaMetadata getMetadata();
method public java.lang.String getPackageName();
method public android.media.session.PlaybackState getPlaybackState();
- method public java.util.List<android.media.session.MediaSession.Track> getQueue();
+ method public java.util.List<android.media.session.MediaSession.Item> getQueue();
method public java.lang.CharSequence getQueueTitle();
method public int getRatingType();
method public android.media.session.MediaSession.Token getSessionToken();
method public android.media.session.MediaController.TransportControls getTransportControls();
- method public android.media.session.MediaController.VolumeInfo getVolumeInfo();
method public void removeCallback(android.media.session.MediaController.Callback);
method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
method public void setVolumeTo(int, int);
}
+ public static final class MediaController.AudioInfo {
+ method public android.media.AudioAttributes getAudioAttributes();
+ method public int getCurrentVolume();
+ method public int getMaxVolume();
+ method public int getVolumeControl();
+ method public int getVolumeType();
+ }
+
public static abstract class MediaController.Callback {
ctor public MediaController.Callback();
+ method public void onAudioInfoChanged(android.media.session.MediaController.AudioInfo);
method public void onExtrasChanged(android.os.Bundle);
method public void onMetadataChanged(android.media.MediaMetadata);
method public void onPlaybackStateChanged(android.media.session.PlaybackState);
- method public void onQueueChanged(java.util.List<android.media.session.MediaSession.Track>);
+ method public void onQueueChanged(java.util.List<android.media.session.MediaSession.Item>);
method public void onQueueTitleChanged(java.lang.CharSequence);
method public void onSessionDestroyed();
method public void onSessionEvent(java.lang.String, android.os.Bundle);
- method public void onVolumeInfoChanged(android.media.session.MediaController.VolumeInfo);
}
public final class MediaController.TransportControls {
method public void sendCustomAction(android.media.session.PlaybackState.CustomAction, android.os.Bundle);
method public void sendCustomAction(java.lang.String, android.os.Bundle);
method public void setRating(android.media.Rating);
+ method public void skipToItem(long);
method public void skipToNext();
method public void skipToPrevious();
- method public void skipToTrack(long);
method public void stop();
}
- public static final class MediaController.VolumeInfo {
- method public android.media.AudioAttributes getAudioAttributes();
- method public int getCurrentVolume();
- method public int getMaxVolume();
- method public int getVolumeControl();
- method public int getVolumeType();
- }
-
public final class MediaSession {
ctor public MediaSession(android.content.Context, java.lang.String);
method public android.media.session.MediaController getController();
method public void setPlaybackState(android.media.session.PlaybackState);
method public void setPlaybackToLocal(android.media.AudioAttributes);
method public void setPlaybackToRemote(android.media.VolumeProvider);
- method public void setQueue(java.util.List<android.media.session.MediaSession.Track>);
+ method public void setQueue(java.util.List<android.media.session.MediaSession.Item>);
method public void setQueueTitle(java.lang.CharSequence);
field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
method public void onRewind();
method public void onSeekTo(long);
method public void onSetRating(android.media.Rating);
+ method public void onSkipToItem(long);
method public void onSkipToNext();
method public void onSkipToPrevious();
- method public void onSkipToTrack(long);
method public void onStop();
}
- public static final class MediaSession.Token implements android.os.Parcelable {
- method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator CREATOR;
- }
-
- public static final class MediaSession.Track implements android.os.Parcelable {
+ public static final class MediaSession.Item implements android.os.Parcelable {
method public int describeContents();
method public android.os.Bundle getExtras();
method public long getId();
field public static final int UNKNOWN_ID = -1; // 0xffffffff
}
- public static final class MediaSession.Track.Builder {
- ctor public MediaSession.Track.Builder(android.media.MediaMetadata, long, android.net.Uri);
- method public android.media.session.MediaSession.Track build();
- method public android.media.session.MediaSession.Track.Builder setExtras(android.os.Bundle);
+ public static final class MediaSession.Item.Builder {
+ ctor public MediaSession.Item.Builder(android.media.MediaMetadata, long, android.net.Uri);
+ method public android.media.session.MediaSession.Item build();
+ method public android.media.session.MediaSession.Item.Builder setExtras(android.os.Bundle);
+ }
+
+ public static final class MediaSession.Token implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
}
public final class MediaSessionManager {
- method public void addActiveSessionsListener(android.media.session.MediaSessionManager.SessionListener, android.content.ComponentName);
+ method public void addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, android.content.ComponentName);
method public java.util.List<android.media.session.MediaController> getActiveSessions(android.content.ComponentName);
- method public void removeActiveSessionsListener(android.media.session.MediaSessionManager.SessionListener);
+ method public void removeOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener);
}
- public static abstract class MediaSessionManager.SessionListener {
- ctor public MediaSessionManager.SessionListener(android.content.Context);
+ public static abstract interface MediaSessionManager.OnActiveSessionsChangedListener {
method public abstract void onActiveSessionsChanged(java.util.List<android.media.session.MediaController>);
}
field public static final long ACTION_REWIND = 8L; // 0x8L
field public static final long ACTION_SEEK_TO = 256L; // 0x100L
field public static final long ACTION_SET_RATING = 128L; // 0x80L
+ field public static final long ACTION_SKIP_TO_ITEM = 4096L; // 0x1000L
field public static final long ACTION_SKIP_TO_NEXT = 32L; // 0x20L
field public static final long ACTION_SKIP_TO_PREVIOUS = 16L; // 0x10L
- field public static final long ACTION_SKIP_TO_TRACK = 4096L; // 0x1000L
field public static final long ACTION_STOP = 1L; // 0x1L
field public static final android.os.Parcelable.Creator CREATOR;
field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
method public android.media.session.PlaybackState.Builder addCustomAction(android.media.session.PlaybackState.CustomAction);
method public android.media.session.PlaybackState build();
method public android.media.session.PlaybackState.Builder setActions(long);
- method public android.media.session.PlaybackState.Builder setActiveTrack(long);
+ method public android.media.session.PlaybackState.Builder setActiveItem(long);
method public android.media.session.PlaybackState.Builder setBufferPosition(long);
method public android.media.session.PlaybackState.Builder setErrorMessage(java.lang.CharSequence);
method public android.media.session.PlaybackState.Builder setState(int, long, float, long);
}
/**
- * Registers a {@link RemoteController} instance for it to receive media metadata updates
- * and playback state information from applications using {@link RemoteControlClient}, and
- * control their playback.
- * <p>Registration requires the {@link OnClientUpdateListener} listener to be one of the
- * enabled notification listeners (see
+ * Registers a {@link RemoteController} instance for it to receive media
+ * metadata updates and playback state information from applications using
+ * {@link RemoteControlClient}, and control their playback.
+ * <p>
+ * Registration requires the {@link OnClientUpdateListener} listener to be
+ * one of the enabled notification listeners (see
* {@link android.service.notification.NotificationListenerService}).
+ *
* @param rctlr the object to register.
- * @return true if the {@link RemoteController} was successfully registered, false if an
- * error occurred, due to an internal system error, or insufficient permissions.
+ * @return true if the {@link RemoteController} was successfully registered,
+ * false if an error occurred, due to an internal system error, or
+ * insufficient permissions.
* @deprecated Use
- * {@link MediaSessionManager#addActiveSessionsListener(android.media.session.MediaSessionManager.SessionListener, ComponentName)}
- * and {@link MediaController} instead.
+ * {@link MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, ComponentName)}
+ * and {@link MediaController} instead.
*/
@Deprecated
public boolean registerRemoteController(RemoteController rctlr) {
}
/**
- * Unregisters a {@link RemoteController}, causing it to no longer receive media metadata and
- * playback state information, and no longer be capable of controlling playback.
+ * Unregisters a {@link RemoteController}, causing it to no longer receive
+ * media metadata and playback state information, and no longer be capable
+ * of controlling playback.
+ *
* @param rctlr the object to unregister.
* @deprecated Use
- * {@link MediaSessionManager#removeActiveSessionsListener(android.media.session.MediaSessionManager.SessionListener)}
- * instead.
+ * {@link MediaSessionManager#removeOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener)}
+ * instead.
*/
@Deprecated
public void unregisterRemoteController(RemoteController rctlr) {
private MetadataEditor mMetadataEditor;
private MediaSessionManager mSessionManager;
- private MediaSessionManager.SessionListener mSessionListener;
+ private MediaSessionManager.OnActiveSessionsChangedListener mSessionListener;
private MediaController.Callback mSessionCb = new MediaControllerCallback();
/**
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
mSessionManager = (MediaSessionManager) context
.getSystemService(Context.MEDIA_SESSION_SERVICE);
- mSessionListener = new TopTransportSessionListener(context);
+ mSessionListener = new TopTransportSessionListener();
if (ActivityManager.isLowRamDeviceStatic()) {
mMaxBitmapDimension = MAX_BITMAP_DIMENSION;
* Listens for changes to the active session stack and replaces the
* currently tracked session if it has changed.
*/
- private class TopTransportSessionListener extends MediaSessionManager.SessionListener {
-
- public TopTransportSessionListener(Context context) {
- super(context);
- }
+ private class TopTransportSessionListener implements
+ MediaSessionManager.OnActiveSessionsChangedListener {
@Override
public void onActiveSessionsChanged(List<MediaController> controllers) {
void startListeningToSessions() {
final ComponentName listenerComponent = new ComponentName(mContext,
mOnClientUpdateListener.getClass());
- mSessionManager.addActiveSessionsListener(mSessionListener, listenerComponent,
+ mSessionManager.addOnActiveSessionsChangedListener(mSessionListener, listenerComponent,
UserHandle.myUserId(), null);
mSessionListener.onActiveSessionsChanged(mSessionManager
.getActiveSessions(listenerComponent));
* @hide
*/
void stopListeningToSessions() {
- mSessionManager.removeActiveSessionsListener(mSessionListener);
+ mSessionManager.removeOnActiveSessionsChangedListener(mSessionListener);
if (DEBUG) {
Log.d(TAG, "Unregistered session listener for user "
+ UserHandle.myUserId());
*
* @return The current play queue or null.
*/
- public @Nullable List<MediaSession.Track> getQueue() {
+ public @Nullable List<MediaSession.Item> getQueue() {
try {
ParceledListSlice queue = mSessionBinder.getQueue();
if (queue != null) {
}
/**
- * Get the current volume info for this session.
+ * Get the current audio info for this session.
*
- * @return The current volume info or null.
+ * @return The current audio info or null.
*/
- public @Nullable VolumeInfo getVolumeInfo() {
+ public @Nullable AudioInfo getAudioInfo() {
try {
ParcelableVolumeInfo result = mSessionBinder.getVolumeAttributes();
- return new VolumeInfo(result.volumeType, result.audioAttrs, result.controlType,
+ return new AudioInfo(result.volumeType, result.audioAttrs, result.controlType,
result.maxVolume, result.currentVolume);
} catch (RemoteException e) {
- Log.wtf(TAG, "Error calling getVolumeInfo.", e);
+ Log.wtf(TAG, "Error calling getAudioInfo.", e);
}
return null;
}
* {@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}. The flags in
* {@link AudioManager} may be used to affect the handling.
*
- * @see #getVolumeInfo()
+ * @see #getAudioInfo()
* @param value The value to set it to, between 0 and the reported max.
* @param flags Any flags to pass with the command.
*/
* {@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}. The flags in
* {@link AudioManager} may be used to affect the handling.
*
- * @see #getVolumeInfo()
+ * @see #getAudioInfo()
* @param direction The direction to adjust the volume in.
* @param flags Any flags to pass with the command.
*/
}
/**
- * Override to handle changes to tracks in the queue.
+ * Override to handle changes to items in the queue.
*
- * @param queue A list of tracks in the current play queue. It should include the currently
- * playing track as well as previous and upcoming tracks if applicable.
- * @see MediaSession.Track
+ * @param queue A list of items in the current play queue. It should
+ * include the currently playing item as well as previous and
+ * upcoming items if applicable.
+ * @see MediaSession.Item
*/
- public void onQueueChanged(@Nullable List<MediaSession.Track> queue) {
+ public void onQueueChanged(@Nullable List<MediaSession.Item> queue) {
}
/**
}
/**
- * Override to handle changes to the volume info.
+ * Override to handle changes to the audio info.
*
- * @param info The current volume info for this session.
+ * @param info The current audio info for this session.
*/
- public void onVolumeInfoChanged(VolumeInfo info) {
+ public void onAudioInfoChanged(AudioInfo info) {
}
}
}
/**
- * Play a track with a specific id in the play queue.
- * If you specify an id that is not in the play queue, the behavior is undefined.
+ * Play an item with a specific id in the play queue. If you specify an
+ * id that is not in the play queue, the behavior is undefined.
*/
- public void skipToTrack(long id) {
+ public void skipToItem(long id) {
try {
mSessionBinder.skipToTrack(id);
} catch (RemoteException e) {
- Log.wtf(TAG, "Error calling skipToTrack(" + id + ").", e);
+ Log.wtf(TAG, "Error calling skipToItem(" + id + ").", e);
}
}
}
/**
- * Holds information about the way volume is handled for this session.
+ * Holds information about the way audio is handled for this session.
*/
- public static final class VolumeInfo {
+ public static final class AudioInfo {
private final int mVolumeType;
private final int mVolumeControl;
private final int mMaxVolume;
/**
* @hide
*/
- public VolumeInfo(int type, AudioAttributes attrs, int control, int max, int current) {
+ public AudioInfo(int type, AudioAttributes attrs, int control, int max, int current) {
mVolumeType = type;
mAudioAttrs = attrs;
mVolumeControl = control;
@Override
public void onQueueChanged(ParceledListSlice parceledQueue) {
- List<MediaSession.Track> queue = parceledQueue.getList();
+ List<MediaSession.Item> queue = parceledQueue.getList();
MediaController controller = mController.get();
if (controller != null) {
controller.postMessage(MSG_UPDATE_QUEUE, queue, null);
public void onVolumeInfoChanged(ParcelableVolumeInfo pvi) {
MediaController controller = mController.get();
if (controller != null) {
- VolumeInfo info = new VolumeInfo(pvi.volumeType, pvi.audioAttrs, pvi.controlType,
+ AudioInfo info = new AudioInfo(pvi.volumeType, pvi.audioAttrs, pvi.controlType,
pvi.maxVolume, pvi.currentVolume);
controller.postMessage(MSG_UPDATE_VOLUME, info, null);
}
mCallback.onMetadataChanged((MediaMetadata) msg.obj);
break;
case MSG_UPDATE_QUEUE:
- mCallback.onQueueChanged((List<MediaSession.Track>) msg.obj);
+ mCallback.onQueueChanged((List<MediaSession.Item>) msg.obj);
break;
case MSG_UPDATE_QUEUE_TITLE:
mCallback.onQueueTitleChanged((CharSequence) msg.obj);
mCallback.onExtrasChanged((Bundle) msg.obj);
break;
case MSG_UPDATE_VOLUME:
- mCallback.onVolumeInfoChanged((VolumeInfo) msg.obj);
+ mCallback.onAudioInfoChanged((AudioInfo) msg.obj);
break;
case MSG_DESTROYED:
mCallback.onSessionDestroyed();
}
/**
- * Update the list of tracks in the play queue. It is an ordered list and should contain the
- * current track, and previous or upcoming tracks if they exist.
- * Specify null if there is no current play queue.
+ * Update the list of items in the play queue. It is an ordered list and
+ * should contain the current item, and previous or upcoming items if they
+ * exist. Specify null if there is no current play queue.
* <p>
- * The queue should be of reasonable size. If the play queue is unbounded within your
- * app, it is better to send a reasonable amount in a sliding window instead.
+ * The queue should be of reasonable size. If the play queue is unbounded
+ * within your app, it is better to send a reasonable amount in a sliding
+ * window instead.
*
- * @param queue A list of tracks in the play queue.
+ * @param queue A list of items in the play queue.
*/
- public void setQueue(@Nullable List<Track> queue) {
+ public void setQueue(@Nullable List<Item> queue) {
try {
- mBinder.setQueue(new ParceledListSlice<Track>(queue));
+ mBinder.setQueue(new ParceledListSlice<Item>(queue));
} catch (RemoteException e) {
Log.wtf("Dead object in setQueue.", e);
}
postToCallback(CallbackMessageHandler.MSG_PLAY_SEARCH, query, extras);
}
- private void dispatchSkipToTrack(long id) {
- postToCallback(CallbackMessageHandler.MSG_SKIP_TO_TRACK, id);
+ private void dispatchSkipToItem(long id) {
+ postToCallback(CallbackMessageHandler.MSG_SKIP_TO_ITEM, id);
}
private void dispatchPause() {
}
/**
- * Override to handle requests to play a track with a given id from the play queue.
+ * Override to handle requests to play an item with a given id from the
+ * play queue.
*/
- public void onSkipToTrack(long id) {
+ public void onSkipToItem(long id) {
}
/**
public void onSkipToTrack(long id) {
MediaSession session = mMediaSession.get();
if (session != null) {
- session.dispatchSkipToTrack(id);
+ session.dispatchSkipToItem(id);
}
}
}
/**
- * A single track that is part of the play queue. It contains information necessary to display
- * a single track in the queue.
+ * A single item that is part of the play queue. It contains information
+ * necessary to display a single item in the queue.
*/
- public static final class Track implements Parcelable {
+ public static final class Item implements Parcelable {
/**
- * This id is reserved. No tracks can be explicitly asigned this id.
+ * This id is reserved. No items can be explicitly asigned this id.
*/
public static final int UNKNOWN_ID = -1;
private final Bundle mExtras;
/**
- * Create a new {@link MediaSession.Track}.
+ * Create a new {@link MediaSession.Item}.
*
- * @param metadata The metadata for this track.
- * @param id An identifier for this track. It must be unique within the play queue.
- * @param uri The uri for this track.
- * @param extras A bundle of extras that can be used to add extra information about the
- * track.
+ * @param metadata The metadata for this item.
+ * @param id An identifier for this item. It must be unique within the
+ * play queue.
+ * @param uri The uri for this item.
+ * @param extras A bundle of extras that can be used to add extra
+ * information about this item.
*/
- private Track(MediaMetadata metadata, long id, Uri uri, Bundle extras) {
+ private Item(MediaMetadata metadata, long id, Uri uri, Bundle extras) {
mMetadata = metadata;
mId = id;
mUri = uri;
mExtras = extras;
}
- private Track(Parcel in) {
+ private Item(Parcel in) {
mMetadata = MediaMetadata.CREATOR.createFromParcel(in);
mId = in.readLong();
mUri = Uri.CREATOR.createFromParcel(in);
}
/**
- * Get the metadata for this track.
+ * Get the metadata for this item.
*/
public MediaMetadata getMetadata() {
return mMetadata;
}
/**
- * Get the id for this track.
+ * Get the id for this item.
*/
public long getId() {
return mId;
}
/**
- * Get the Uri for this track.
+ * Get the Uri for this item.
*/
public Uri getUri() {
return mUri;
}
/**
- * Get the extras for this track.
+ * Get the extras for this item.
*/
public Bundle getExtras() {
return mExtras;
}
/**
- * Builder for {@link MediaSession.Track} objects.
+ * Builder for {@link MediaSession.Item} objects.
*/
public static final class Builder {
private final MediaMetadata mMetadata;
public Builder(MediaMetadata metadata, long id, Uri uri) {
if (metadata == null) {
throw new IllegalArgumentException(
- "You must specify a non-null MediaMetadata to build a Track.");
+ "You must specify a non-null MediaMetadata to build an Item.");
}
if (uri == null) {
throw new IllegalArgumentException(
- "You must specify a non-null Uri to build a Track.");
+ "You must specify a non-null Uri to build an Item.");
}
if (id == UNKNOWN_ID) {
throw new IllegalArgumentException(
- "You must specify an id other than UNKNOWN_ID to build a Track.");
+ "You must specify an id other than UNKNOWN_ID to build an Item.");
}
mMetadata = metadata;
mId = id;
}
/**
- * Set optional extras for the track.
+ * Set optional extras for the item.
*/
- public MediaSession.Track.Builder setExtras(Bundle extras) {
+ public MediaSession.Item.Builder setExtras(Bundle extras) {
mExtras = extras;
return this;
}
/**
- * Create the {@link Track}.
+ * Create the {@link Item}.
*/
- public MediaSession.Track build() {
- return new MediaSession.Track(mMetadata, mId, mUri, mExtras);
+ public MediaSession.Item build() {
+ return new MediaSession.Item(mMetadata, mId, mUri, mExtras);
}
}
return 0;
}
- public static final Creator<MediaSession.Track> CREATOR
- = new Creator<MediaSession.Track>() {
+ public static final Creator<MediaSession.Item> CREATOR
+ = new Creator<MediaSession.Item>() {
@Override
- public MediaSession.Track createFromParcel(Parcel p) {
- return new MediaSession.Track(p);
+ public MediaSession.Item createFromParcel(Parcel p) {
+ return new MediaSession.Item(p);
}
@Override
- public MediaSession.Track[] newArray(int size) {
- return new MediaSession.Track[size];
+ public MediaSession.Item[] newArray(int size) {
+ return new MediaSession.Item[size];
}
};
@Override
public String toString() {
- return "MediaSession.Track {" +
+ return "MediaSession.Item {" +
"Metadata=" + mMetadata +
", Id=" + mId +
", Uri=" + mUri +
private static final int MSG_PLAY = 1;
private static final int MSG_PLAY_URI = 2;
private static final int MSG_PLAY_SEARCH = 3;
- private static final int MSG_SKIP_TO_TRACK = 4;
+ private static final int MSG_SKIP_TO_ITEM = 4;
private static final int MSG_PAUSE = 5;
private static final int MSG_STOP = 6;
private static final int MSG_NEXT = 7;
case MSG_PLAY_SEARCH:
mCallback.onPlayFromSearch((String) msg.obj, msg.getData());
break;
- case MSG_SKIP_TO_TRACK:
- mCallback.onSkipToTrack((Long) msg.obj);
+ case MSG_SKIP_TO_ITEM:
+ mCallback.onSkipToItem((Long) msg.obj);
case MSG_PAUSE:
mCallback.onPause();
break;
import android.os.UserHandle;
import android.service.notification.NotificationListenerService;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.Log;
import android.view.KeyEvent;
public final class MediaSessionManager {
private static final String TAG = "SessionManager";
+ private final ArrayMap<OnActiveSessionsChangedListener, SessionsChangedWrapper> mListeners
+ = new ArrayMap<OnActiveSessionsChangedListener, SessionsChangedWrapper>();
+ private final Object mLock = new Object();
private final ISessionManager mService;
private Context mContext;
* @param notificationListener The enabled notification listener component.
* May be null.
*/
- public void addActiveSessionsListener(@NonNull SessionListener sessionListener,
+ public void addOnActiveSessionsChangedListener(
+ @NonNull OnActiveSessionsChangedListener sessionListener,
@Nullable ComponentName notificationListener) {
- addActiveSessionsListener(sessionListener, notificationListener, UserHandle.myUserId(),
- null);
+ addOnActiveSessionsChangedListener(sessionListener, notificationListener,
+ UserHandle.myUserId(), null);
}
/**
* @param handler The handler to post updates on.
* @hide
*/
- public void addActiveSessionsListener(@NonNull SessionListener sessionListener,
+ public void addOnActiveSessionsChangedListener(
+ @NonNull OnActiveSessionsChangedListener sessionListener,
@Nullable ComponentName notificationListener, int userId, @Nullable Handler handler) {
if (sessionListener == null) {
throw new IllegalArgumentException("listener may not be null");
if (handler == null) {
handler = new Handler();
}
- sessionListener.setHandler(handler);
- try {
- mService.addSessionsListener(sessionListener.mStub, notificationListener, userId);
- } catch (RemoteException e) {
- Log.e(TAG, "Error in addActiveSessionsListener.", e);
+ synchronized (mLock) {
+ if (mListeners.get(sessionListener) != null) {
+ Log.w(TAG, "Attempted to add session listener twice, ignoring.");
+ return;
+ }
+ SessionsChangedWrapper wrapper = new SessionsChangedWrapper(sessionListener, handler);
+ try {
+ mService.addSessionsListener(wrapper.mStub, notificationListener, userId);
+ mListeners.put(sessionListener, wrapper);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error in addOnActiveSessionsChangedListener.", e);
+ }
}
}
*
* @param listener The listener to remove.
*/
- public void removeActiveSessionsListener(@NonNull SessionListener listener) {
+ public void removeOnActiveSessionsChangedListener(
+ @NonNull OnActiveSessionsChangedListener listener) {
if (listener == null) {
throw new IllegalArgumentException("listener may not be null");
}
- try {
- mService.removeSessionsListener(listener.mStub);
- } catch (RemoteException e) {
- Log.e(TAG, "Error in removeActiveSessionsListener.", e);
+ synchronized (mLock) {
+ SessionsChangedWrapper wrapper = mListeners.remove(listener);
+ if (wrapper != null) {
+ try {
+ mService.removeSessionsListener(wrapper.mStub);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error in removeOnActiveSessionsChangedListener.", e);
+ }
+ }
}
}
/**
* Listens for changes to the list of active sessions. This can be added
- * using {@link #addActiveSessionsListener}.
+ * using {@link #addOnActiveSessionsChangedListener}.
*/
- public static abstract class SessionListener {
- private final Context mContext;
- private Handler mHandler;
+ public interface OnActiveSessionsChangedListener {
+ public void onActiveSessionsChanged(@Nullable List<MediaController> controllers);
+ }
- public SessionListener(Context context) {
- mContext = context;
- }
- /**
- * Called when the list of active sessions has changed. This can be due
- * to a session being added or removed or the order of sessions
- * changing. The controllers will be provided in priority order with the
- * most important controller at index 0.
- *
- * @param controllers The updated list of controllers for the user that
- * changed.
- */
- public abstract void onActiveSessionsChanged(
- @Nullable List<MediaController> controllers);
+ private final class SessionsChangedWrapper {
+ private final OnActiveSessionsChangedListener mListener;
+ private final Handler mHandler;
- private final void setHandler(Handler handler) {
+ public SessionsChangedWrapper(OnActiveSessionsChangedListener listener, Handler handler) {
+ mListener = listener;
mHandler = handler;
}
for (int i = 0; i < size; i++) {
controllers.add(new MediaController(mContext, tokens.get(i)));
}
- SessionListener.this.onActiveSessionsChanged(controllers);
+ mListener.onActiveSessionsChanged(controllers);
}
});
}
/**
* Convenience class for passing information about the audio configuration of a
- * session. The public implementation is {@link MediaController.VolumeInfo}.
+ * session. The public implementation is {@link MediaController.AudioInfo}.
*
* @hide
*/
public static final long ACTION_PLAY_FROM_SEARCH = 1 << 11;
/**
- * Indicates this performer supports the skip to track command.
+ * Indicates this performer supports the skip to item command.
*
* @see Builder#setActions(long)
*/
- public static final long ACTION_SKIP_TO_TRACK = 1 << 12;
+ public static final long ACTION_SKIP_TO_ITEM = 1 << 12;
/**
* This is the default playback state and indicates that no media has been
private List<PlaybackState.CustomAction> mCustomActions;
private final CharSequence mErrorMessage;
private final long mUpdateTime;
- private final long mActiveTrackId;
+ private final long mActiveItemId;
private PlaybackState(int state, long position, long updateTime, float speed,
long bufferPosition, long transportControls,
- List<PlaybackState.CustomAction> customActions, long activeTrackId,
+ List<PlaybackState.CustomAction> customActions, long activeItemId,
CharSequence error) {
mState = state;
mPosition = position;
mBufferPosition = bufferPosition;
mActions = transportControls;
mCustomActions = new ArrayList<>(customActions);
- mActiveTrackId = activeTrackId;
+ mActiveItemId = activeItemId;
mErrorMessage = error;
}
mBufferPosition = in.readLong();
mActions = in.readLong();
mCustomActions = in.createTypedArrayList(CustomAction.CREATOR);
- mActiveTrackId = in.readLong();
+ mActiveItemId = in.readLong();
mErrorMessage = in.readCharSequence();
}
bob.append(", updated=").append(mUpdateTime);
bob.append(", actions=").append(mActions);
bob.append(", custom actions=").append(mCustomActions);
- bob.append(", active track id=").append(mActiveTrackId);
+ bob.append(", active item id=").append(mActiveItemId);
bob.append(", error=").append(mErrorMessage);
bob.append("}");
return bob.toString();
dest.writeLong(mBufferPosition);
dest.writeLong(mActions);
dest.writeTypedList(mCustomActions);
- dest.writeLong(mActiveTrackId);
+ dest.writeLong(mActiveItemId);
dest.writeCharSequence(mErrorMessage);
}
private long mActions;
private CharSequence mErrorMessage;
private long mUpdateTime;
- private long mActiveTrackId = MediaSession.Track.UNKNOWN_ID;
+ private long mActiveItemId = MediaSession.Item.UNKNOWN_ID;
/**
* Creates an initially empty state builder.
}
mErrorMessage = from.mErrorMessage;
mUpdateTime = from.mUpdateTime;
- mActiveTrackId = from.mActiveTrackId;
+ mActiveItemId = from.mActiveItemId;
}
/**
* Set the current state of playback.
* <p>
* The position must be in ms and indicates the current playback
- * position within the track. If the position is unknown use
+ * position within the item. If the position is unknown use
* {@link #PLAYBACK_POSITION_UNKNOWN}. When not using an unknown
* position the time at which the position was updated must be provided.
* It is okay to use {@link SystemClock#elapsedRealtime()} if the
* </ul>
*
* @param state The current state of playback.
- * @param position The position in the current track in ms.
+ * @param position The position in the current item in ms.
* @param playbackSpeed The current speed of playback as a multiple of
* normal playback.
* @param updateTime The time in the {@link SystemClock#elapsedRealtime}
* Set the current state of playback.
* <p>
* The position must be in ms and indicates the current playback
- * position within the track. If the position is unknown use
+ * position within the item. If the position is unknown use
* {@link #PLAYBACK_POSITION_UNKNOWN}. The update time will be set to
* the current {@link SystemClock#elapsedRealtime()}.
* <p>
* </ul>
*
* @param state The current state of playback.
- * @param position The position in the current track in ms.
+ * @param position The position in the current item in ms.
* @param playbackSpeed The current speed of playback as a multiple of
* normal playback.
* @return this
}
/**
- * Set the active track in the play queue by specifying its id.
- * The default value is {@link MediaSession.Track#UNKNOWN_ID}
+ * Set the active item in the play queue by specifying its id. The
+ * default value is {@link MediaSession.Item#UNKNOWN_ID}
*
- * @param id The id of the active track.
+ * @param id The id of the active item.
* @return this
*/
- public Builder setActiveTrack(long id) {
- mActiveTrackId = id;
+ public Builder setActiveItem(long id) {
+ mActiveItemId = id;
return this;
}
*/
public PlaybackState build() {
return new PlaybackState(mState, mPosition, mUpdateTime, mSpeed, mBufferPosition,
- mActions, mCustomActions, mActiveTrackId, mErrorMessage);
+ mActions, mCustomActions, mActiveItemId, mErrorMessage);
}
}
}
import android.media.ToneGenerator;
import android.media.VolumeProvider;
import android.media.session.MediaController;
-import android.media.session.MediaController.VolumeInfo;
+import android.media.session.MediaController.AudioInfo;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
if (mStreamControls != null) {
StreamControl sc = mStreamControls.get(streamType);
if (sc != null && sc.controller != null) {
- VolumeInfo vi = sc.controller.getVolumeInfo();
- return vi.getMaxVolume();
+ AudioInfo ai = sc.controller.getAudioInfo();
+ return ai.getMaxVolume();
}
}
return -1;
if (mStreamControls != null) {
StreamControl sc = mStreamControls.get(streamType);
if (sc != null && sc.controller != null) {
- VolumeInfo vi = sc.controller.getVolumeInfo();
- return vi.getCurrentVolume();
+ AudioInfo ai = sc.controller.getAudioInfo();
+ return ai.getCurrentVolume();
}
}
return -1;
// We still don't have one, ignore the command.
Log.w(mTag, "sent remote volume change without a controller!");
} else {
- VolumeInfo vi = controller.getVolumeInfo();
+ AudioInfo vi = controller.getAudioInfo();
index = vi.getCurrentVolume();
max = vi.getMaxVolume();
if ((vi.getVolumeControl() & VolumeProvider.VOLUME_CONTROL_FIXED) != 0) {
};
private final MediaController.Callback mMediaControllerCb = new MediaController.Callback() {
- public void onVolumeInfoChanged(VolumeInfo info) {
+ public void onAudioInfoChanged(AudioInfo info) {
onRemoteVolumeUpdateIfShown();
}
};