MediaController.java revision 031149cd5f22bd858142633c7a763450f42793f7
101fe661ae5da3739215d93922412df4b24c859a2RoboErik/* 201fe661ae5da3739215d93922412df4b24c859a2RoboErik * Copyright (C) 2014 The Android Open Source Project 301fe661ae5da3739215d93922412df4b24c859a2RoboErik * 401fe661ae5da3739215d93922412df4b24c859a2RoboErik * Licensed under the Apache License, Version 2.0 (the "License"); 501fe661ae5da3739215d93922412df4b24c859a2RoboErik * you may not use this file except in compliance with the License. 601fe661ae5da3739215d93922412df4b24c859a2RoboErik * You may obtain a copy of the License at 701fe661ae5da3739215d93922412df4b24c859a2RoboErik * 801fe661ae5da3739215d93922412df4b24c859a2RoboErik * http://www.apache.org/licenses/LICENSE-2.0 901fe661ae5da3739215d93922412df4b24c859a2RoboErik * 1001fe661ae5da3739215d93922412df4b24c859a2RoboErik * Unless required by applicable law or agreed to in writing, software 1101fe661ae5da3739215d93922412df4b24c859a2RoboErik * distributed under the License is distributed on an "AS IS" BASIS, 1201fe661ae5da3739215d93922412df4b24c859a2RoboErik * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1301fe661ae5da3739215d93922412df4b24c859a2RoboErik * See the License for the specific language governing permissions and 1401fe661ae5da3739215d93922412df4b24c859a2RoboErik * limitations under the License. 1501fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 1601fe661ae5da3739215d93922412df4b24c859a2RoboErik 172f5b057da7d05d5d699a272aa24fd7c97cdda820RoboErikpackage android.media.session; 1801fe661ae5da3739215d93922412df4b24c859a2RoboErik 19bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brownimport android.annotation.NonNull; 20bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brownimport android.annotation.Nullable; 21e34c09daf89fb888fe2638e71758573462d85173RoboErikimport android.app.PendingIntent; 22031149cd5f22bd858142633c7a763450f42793f7RoboErikimport android.content.Context; 23f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Pealimport android.content.pm.ParceledListSlice; 249db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErikimport android.media.AudioAttributes; 2519c9518f6a817d53d5234de0020313cab6950b2fRoboErikimport android.media.AudioManager; 2642ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErikimport android.media.MediaMetadata; 27c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErikimport android.media.Rating; 28ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErikimport android.media.VolumeProvider; 291a937b04e63539cb1fab1bde601031d415c7156fJeff Brownimport android.media.routing.MediaRouter; 30f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Pealimport android.net.Uri; 3101fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.os.Bundle; 3201fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.os.Handler; 3301fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.os.Looper; 3401fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.os.Message; 3501fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.os.RemoteException; 368ae0f34db936a649ddaf9cdd086c224f6514efebRoboErikimport android.os.ResultReceiver; 3701fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.text.TextUtils; 3801fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.util.Log; 3901fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.view.KeyEvent; 4001fe661ae5da3739215d93922412df4b24c859a2RoboErik 418ae0f34db936a649ddaf9cdd086c224f6514efebRoboErikimport java.lang.ref.WeakReference; 4201fe661ae5da3739215d93922412df4b24c859a2RoboErikimport java.util.ArrayList; 43f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Pealimport java.util.List; 4401fe661ae5da3739215d93922412df4b24c859a2RoboErik 4501fe661ae5da3739215d93922412df4b24c859a2RoboErik/** 4601fe661ae5da3739215d93922412df4b24c859a2RoboErik * Allows an app to interact with an ongoing media session. Media buttons and 4701fe661ae5da3739215d93922412df4b24c859a2RoboErik * other commands can be sent to the session. A callback may be registered to 4801fe661ae5da3739215d93922412df4b24c859a2RoboErik * receive updates from the session, such as metadata and play state changes. 4901fe661ae5da3739215d93922412df4b24c859a2RoboErik * <p> 5042ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik * A MediaController can be created through {@link MediaSessionManager} if you 5101fe661ae5da3739215d93922412df4b24c859a2RoboErik * hold the "android.permission.MEDIA_CONTENT_CONTROL" permission or directly if 52dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown * you have a {@link MediaSession.Token} from the session owner. 5301fe661ae5da3739215d93922412df4b24c859a2RoboErik * <p> 5401fe661ae5da3739215d93922412df4b24c859a2RoboErik * MediaController objects are thread-safe. 5501fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 5642ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErikpublic final class MediaController { 57bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown private static final String TAG = "MediaController"; 5801fe661ae5da3739215d93922412df4b24c859a2RoboErik 598ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik private static final int MSG_EVENT = 1; 60c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik private static final int MSG_UPDATE_PLAYBACK_STATE = 2; 61c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik private static final int MSG_UPDATE_METADATA = 3; 6201a500ed1c6ae3fff66678144ae637aa8cad0eccJeff Brown private static final int MSG_UPDATE_VOLUME = 4; 63f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal private static final int MSG_UPDATE_QUEUE = 5; 64f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal private static final int MSG_UPDATE_QUEUE_TITLE = 6; 65f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal private static final int MSG_UPDATE_EXTRAS = 7; 6601fe661ae5da3739215d93922412df4b24c859a2RoboErik 6707c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik private final ISessionController mSessionBinder; 6801fe661ae5da3739215d93922412df4b24c859a2RoboErik 6976fca4e177e18b591439fdff64b8f5242a5122d0RoboErik private final MediaSession.Token mToken; 70031149cd5f22bd858142633c7a763450f42793f7RoboErik private final Context mContext; 718ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik private final CallbackStub mCbStub = new CallbackStub(this); 728ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik private final ArrayList<MessageHandler> mCallbacks = new ArrayList<MessageHandler>(); 7301fe661ae5da3739215d93922412df4b24c859a2RoboErik private final Object mLock = new Object(); 7401fe661ae5da3739215d93922412df4b24c859a2RoboErik 7501fe661ae5da3739215d93922412df4b24c859a2RoboErik private boolean mCbRegistered = false; 76aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik private String mPackageName; 77aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik private String mTag; 7801fe661ae5da3739215d93922412df4b24c859a2RoboErik 791a937b04e63539cb1fab1bde601031d415c7156fJeff Brown private final TransportControls mTransportControls; 808ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik 8101fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 828b4bffcac996b4083e720310a09d315ca1c4a000RoboErik * Call for creating a MediaController directly from a binder. Should only 838b4bffcac996b4083e720310a09d315ca1c4a000RoboErik * be used by framework code. 848b4bffcac996b4083e720310a09d315ca1c4a000RoboErik * 858ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * @hide 8601fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 87031149cd5f22bd858142633c7a763450f42793f7RoboErik public MediaController(Context context, ISessionController sessionBinder) { 888b4bffcac996b4083e720310a09d315ca1c4a000RoboErik if (sessionBinder == null) { 898b4bffcac996b4083e720310a09d315ca1c4a000RoboErik throw new IllegalArgumentException("Session token cannot be null"); 908b4bffcac996b4083e720310a09d315ca1c4a000RoboErik } 91031149cd5f22bd858142633c7a763450f42793f7RoboErik if (context == null) { 92031149cd5f22bd858142633c7a763450f42793f7RoboErik throw new IllegalArgumentException("Context cannot be null"); 93031149cd5f22bd858142633c7a763450f42793f7RoboErik } 948b4bffcac996b4083e720310a09d315ca1c4a000RoboErik mSessionBinder = sessionBinder; 958b4bffcac996b4083e720310a09d315ca1c4a000RoboErik mTransportControls = new TransportControls(); 9676fca4e177e18b591439fdff64b8f5242a5122d0RoboErik mToken = new MediaSession.Token(sessionBinder); 97031149cd5f22bd858142633c7a763450f42793f7RoboErik mContext = context; 9801fe661ae5da3739215d93922412df4b24c859a2RoboErik } 9901fe661ae5da3739215d93922412df4b24c859a2RoboErik 10001fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 1018b4bffcac996b4083e720310a09d315ca1c4a000RoboErik * Create a new MediaController from a session's token. 1028ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * 103031149cd5f22bd858142633c7a763450f42793f7RoboErik * @param context The caller's context. 1048b4bffcac996b4083e720310a09d315ca1c4a000RoboErik * @param token The token for the session. 10501fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 106031149cd5f22bd858142633c7a763450f42793f7RoboErik public MediaController(@NonNull Context context, @NonNull MediaSession.Token token) { 107031149cd5f22bd858142633c7a763450f42793f7RoboErik this(context, token.getBinder()); 10801fe661ae5da3739215d93922412df4b24c859a2RoboErik } 10901fe661ae5da3739215d93922412df4b24c859a2RoboErik 11001fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 1111a937b04e63539cb1fab1bde601031d415c7156fJeff Brown * Get a {@link TransportControls} instance to send transport actions to 1121a937b04e63539cb1fab1bde601031d415c7156fJeff Brown * the associated session. 11301fe661ae5da3739215d93922412df4b24c859a2RoboErik * 1141a937b04e63539cb1fab1bde601031d415c7156fJeff Brown * @return A transport controls instance. 11501fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 116bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public @NonNull TransportControls getTransportControls() { 1171a937b04e63539cb1fab1bde601031d415c7156fJeff Brown return mTransportControls; 1181a937b04e63539cb1fab1bde601031d415c7156fJeff Brown } 1191a937b04e63539cb1fab1bde601031d415c7156fJeff Brown 1201a937b04e63539cb1fab1bde601031d415c7156fJeff Brown /** 1211a937b04e63539cb1fab1bde601031d415c7156fJeff Brown * Creates a media router delegate through which the destination of the media 1221a937b04e63539cb1fab1bde601031d415c7156fJeff Brown * router may be observed and controlled. 1231a937b04e63539cb1fab1bde601031d415c7156fJeff Brown * 1241a937b04e63539cb1fab1bde601031d415c7156fJeff Brown * @return The media router delegate, or null if the media session does 1251a937b04e63539cb1fab1bde601031d415c7156fJeff Brown * not support media routing. 1261a937b04e63539cb1fab1bde601031d415c7156fJeff Brown */ 1271a937b04e63539cb1fab1bde601031d415c7156fJeff Brown public @Nullable MediaRouter.Delegate createMediaRouterDelegate() { 1281a937b04e63539cb1fab1bde601031d415c7156fJeff Brown return new MediaRouter.Delegate(); 12901fe661ae5da3739215d93922412df4b24c859a2RoboErik } 13001fe661ae5da3739215d93922412df4b24c859a2RoboErik 13101fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 13279fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik * Send the specified media button event to the session. Only media keys can 13379fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik * be sent by this method, other keys will be ignored. 13401fe661ae5da3739215d93922412df4b24c859a2RoboErik * 13579fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik * @param keyEvent The media button event to dispatch. 13679fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik * @return true if the event was sent to the session, false otherwise. 13701fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 138bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public boolean dispatchMediaButtonEvent(@NonNull KeyEvent keyEvent) { 13979fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik if (keyEvent == null) { 14079fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik throw new IllegalArgumentException("KeyEvent may not be null"); 14179fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik } 14279fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik if (!KeyEvent.isMediaKey(keyEvent.getKeyCode())) { 14379fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik return false; 14401fe661ae5da3739215d93922412df4b24c859a2RoboErik } 14501fe661ae5da3739215d93922412df4b24c859a2RoboErik try { 14679fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik return mSessionBinder.sendMediaButton(keyEvent); 14701fe661ae5da3739215d93922412df4b24c859a2RoboErik } catch (RemoteException e) { 148c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik // System is dead. =( 14901fe661ae5da3739215d93922412df4b24c859a2RoboErik } 15079fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik return false; 15101fe661ae5da3739215d93922412df4b24c859a2RoboErik } 15201fe661ae5da3739215d93922412df4b24c859a2RoboErik 15301fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 154c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Get the current playback state for this session. 155c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 156c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @return The current PlaybackState or null 157c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 158bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public @Nullable PlaybackState getPlaybackState() { 159c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 160c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return mSessionBinder.getPlaybackState(); 161c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 162c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling getPlaybackState.", e); 163c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return null; 164c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 165c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 166c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 167c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 168c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Get the current metadata for this session. 169c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 170c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @return The current MediaMetadata or null. 171c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 172bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public @Nullable MediaMetadata getMetadata() { 173c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 174c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return mSessionBinder.getMetadata(); 175c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 176c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling getMetadata.", e); 177c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return null; 178c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 179c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 180c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 181c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 182f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * Get the current play queue for this session. 183f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * 184f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * @return The current play queue or null. 185f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal */ 186f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public @Nullable List<MediaSession.Track> getQueue() { 187f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal try { 188f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal ParceledListSlice queue = mSessionBinder.getQueue(); 189f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal if (queue != null) { 190f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal return queue.getList(); 191f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 192f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } catch (RemoteException e) { 193f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal Log.wtf(TAG, "Error calling getQueue.", e); 194f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 195f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal return null; 196f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 197f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 198f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal /** 199c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Get the rating type supported by the session. One of: 200c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <ul> 201c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_NONE}</li> 202c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_HEART}</li> 203c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_THUMB_UP_DOWN}</li> 204c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_3_STARS}</li> 205c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_4_STARS}</li> 206c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_5_STARS}</li> 207c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_PERCENTAGE}</li> 208c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * </ul> 209c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 210c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @return The supported rating type 211c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 212c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public int getRatingType() { 213c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 214c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return mSessionBinder.getRatingType(); 215c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 216c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling getRatingType.", e); 217c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return Rating.RATING_NONE; 218c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 219c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 220c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 221c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 22276fca4e177e18b591439fdff64b8f5242a5122d0RoboErik * Get the flags for this session. Flags are defined in {@link MediaSession}. 22373e23e229dd1a2d25687b1c6a63c708665378e41RoboErik * 22473e23e229dd1a2d25687b1c6a63c708665378e41RoboErik * @return The current set of flags for the session. 22573e23e229dd1a2d25687b1c6a63c708665378e41RoboErik */ 22676fca4e177e18b591439fdff64b8f5242a5122d0RoboErik public @MediaSession.SessionFlags long getFlags() { 22773e23e229dd1a2d25687b1c6a63c708665378e41RoboErik try { 22873e23e229dd1a2d25687b1c6a63c708665378e41RoboErik return mSessionBinder.getFlags(); 22973e23e229dd1a2d25687b1c6a63c708665378e41RoboErik } catch (RemoteException e) { 23073e23e229dd1a2d25687b1c6a63c708665378e41RoboErik Log.wtf(TAG, "Error calling getFlags.", e); 23173e23e229dd1a2d25687b1c6a63c708665378e41RoboErik } 23273e23e229dd1a2d25687b1c6a63c708665378e41RoboErik return 0; 23373e23e229dd1a2d25687b1c6a63c708665378e41RoboErik } 23473e23e229dd1a2d25687b1c6a63c708665378e41RoboErik 23573e23e229dd1a2d25687b1c6a63c708665378e41RoboErik /** 236ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Get the current volume info for this session. 237ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 238ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @return The current volume info or null. 239ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 240bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public @Nullable VolumeInfo getVolumeInfo() { 241ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik try { 242ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik ParcelableVolumeInfo result = mSessionBinder.getVolumeAttributes(); 2439db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik return new VolumeInfo(result.volumeType, result.audioAttrs, result.controlType, 244ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik result.maxVolume, result.currentVolume); 245ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 246ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } catch (RemoteException e) { 247ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik Log.wtf(TAG, "Error calling getVolumeInfo.", e); 248ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 249ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return null; 250ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 251ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 252ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 253e34c09daf89fb888fe2638e71758573462d85173RoboErik * Get an intent for launching UI associated with this session if one 254e34c09daf89fb888fe2638e71758573462d85173RoboErik * exists. 255e34c09daf89fb888fe2638e71758573462d85173RoboErik * 256e34c09daf89fb888fe2638e71758573462d85173RoboErik * @return A {@link PendingIntent} to launch UI or null. 257e34c09daf89fb888fe2638e71758573462d85173RoboErik */ 258e34c09daf89fb888fe2638e71758573462d85173RoboErik public @Nullable PendingIntent getLaunchActivity() { 259e34c09daf89fb888fe2638e71758573462d85173RoboErik try { 260e34c09daf89fb888fe2638e71758573462d85173RoboErik return mSessionBinder.getLaunchPendingIntent(); 261e34c09daf89fb888fe2638e71758573462d85173RoboErik } catch (RemoteException e) { 262e34c09daf89fb888fe2638e71758573462d85173RoboErik Log.wtf(TAG, "Error calling getPendingIntent.", e); 263e34c09daf89fb888fe2638e71758573462d85173RoboErik } 264e34c09daf89fb888fe2638e71758573462d85173RoboErik return null; 265e34c09daf89fb888fe2638e71758573462d85173RoboErik } 266e34c09daf89fb888fe2638e71758573462d85173RoboErik 267e34c09daf89fb888fe2638e71758573462d85173RoboErik /** 26876fca4e177e18b591439fdff64b8f5242a5122d0RoboErik * Get the token for the session this is connected to. 26976fca4e177e18b591439fdff64b8f5242a5122d0RoboErik * 27076fca4e177e18b591439fdff64b8f5242a5122d0RoboErik * @return The token for the connected session. 27176fca4e177e18b591439fdff64b8f5242a5122d0RoboErik */ 27276fca4e177e18b591439fdff64b8f5242a5122d0RoboErik public @NonNull MediaSession.Token getSessionToken() { 27376fca4e177e18b591439fdff64b8f5242a5122d0RoboErik return mToken; 27476fca4e177e18b591439fdff64b8f5242a5122d0RoboErik } 27576fca4e177e18b591439fdff64b8f5242a5122d0RoboErik 27676fca4e177e18b591439fdff64b8f5242a5122d0RoboErik /** 2779db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * Set the volume of the output this session is playing on. The command will 2789db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * be ignored if it does not support 27919c9518f6a817d53d5234de0020313cab6950b2fRoboErik * {@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}. The flags in 28019c9518f6a817d53d5234de0020313cab6950b2fRoboErik * {@link AudioManager} may be used to affect the handling. 28119c9518f6a817d53d5234de0020313cab6950b2fRoboErik * 28219c9518f6a817d53d5234de0020313cab6950b2fRoboErik * @see #getVolumeInfo() 28319c9518f6a817d53d5234de0020313cab6950b2fRoboErik * @param value The value to set it to, between 0 and the reported max. 28419c9518f6a817d53d5234de0020313cab6950b2fRoboErik * @param flags Any flags to pass with the command. 28519c9518f6a817d53d5234de0020313cab6950b2fRoboErik */ 28619c9518f6a817d53d5234de0020313cab6950b2fRoboErik public void setVolumeTo(int value, int flags) { 28719c9518f6a817d53d5234de0020313cab6950b2fRoboErik try { 28819c9518f6a817d53d5234de0020313cab6950b2fRoboErik mSessionBinder.setVolumeTo(value, flags); 28919c9518f6a817d53d5234de0020313cab6950b2fRoboErik } catch (RemoteException e) { 29019c9518f6a817d53d5234de0020313cab6950b2fRoboErik Log.wtf(TAG, "Error calling setVolumeTo.", e); 29119c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 29219c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 29319c9518f6a817d53d5234de0020313cab6950b2fRoboErik 29419c9518f6a817d53d5234de0020313cab6950b2fRoboErik /** 2959db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * Adjust the volume of the output this session is playing on. The direction 2969db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * must be one of {@link AudioManager#ADJUST_LOWER}, 2971ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik * {@link AudioManager#ADJUST_RAISE}, or {@link AudioManager#ADJUST_SAME}. 2981ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik * The command will be ignored if the session does not support 2991ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik * {@link VolumeProvider#VOLUME_CONTROL_RELATIVE} or 30019c9518f6a817d53d5234de0020313cab6950b2fRoboErik * {@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}. The flags in 30119c9518f6a817d53d5234de0020313cab6950b2fRoboErik * {@link AudioManager} may be used to affect the handling. 30219c9518f6a817d53d5234de0020313cab6950b2fRoboErik * 30319c9518f6a817d53d5234de0020313cab6950b2fRoboErik * @see #getVolumeInfo() 3041ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik * @param direction The direction to adjust the volume in. 30519c9518f6a817d53d5234de0020313cab6950b2fRoboErik * @param flags Any flags to pass with the command. 30619c9518f6a817d53d5234de0020313cab6950b2fRoboErik */ 3071ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik public void adjustVolume(int direction, int flags) { 30819c9518f6a817d53d5234de0020313cab6950b2fRoboErik try { 3091ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik mSessionBinder.adjustVolume(direction, flags); 31019c9518f6a817d53d5234de0020313cab6950b2fRoboErik } catch (RemoteException e) { 31119c9518f6a817d53d5234de0020313cab6950b2fRoboErik Log.wtf(TAG, "Error calling adjustVolumeBy.", e); 31219c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 31319c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 31419c9518f6a817d53d5234de0020313cab6950b2fRoboErik 31519c9518f6a817d53d5234de0020313cab6950b2fRoboErik /** 31601fe661ae5da3739215d93922412df4b24c859a2RoboErik * Adds a callback to receive updates from the Session. Updates will be 31701fe661ae5da3739215d93922412df4b24c859a2RoboErik * posted on the caller's thread. 31801fe661ae5da3739215d93922412df4b24c859a2RoboErik * 319bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * @param callback The callback object, must not be null. 32001fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 321bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public void addCallback(@NonNull Callback callback) { 322bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown addCallback(callback, null); 32301fe661ae5da3739215d93922412df4b24c859a2RoboErik } 32401fe661ae5da3739215d93922412df4b24c859a2RoboErik 32501fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 32601fe661ae5da3739215d93922412df4b24c859a2RoboErik * Adds a callback to receive updates from the session. Updates will be 3278ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * posted on the specified handler's thread. 32801fe661ae5da3739215d93922412df4b24c859a2RoboErik * 329bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * @param callback The callback object, must not be null. 3308ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * @param handler The handler to post updates on. If null the callers thread 331bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * will be used. 33201fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 333bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public void addCallback(@NonNull Callback callback, @Nullable Handler handler) { 334bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown if (callback == null) { 335bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown throw new IllegalArgumentException("callback must not be null"); 336bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown } 33701fe661ae5da3739215d93922412df4b24c859a2RoboErik if (handler == null) { 33801fe661ae5da3739215d93922412df4b24c859a2RoboErik handler = new Handler(); 33901fe661ae5da3739215d93922412df4b24c859a2RoboErik } 34001fe661ae5da3739215d93922412df4b24c859a2RoboErik synchronized (mLock) { 341bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown addCallbackLocked(callback, handler); 34201fe661ae5da3739215d93922412df4b24c859a2RoboErik } 34301fe661ae5da3739215d93922412df4b24c859a2RoboErik } 34401fe661ae5da3739215d93922412df4b24c859a2RoboErik 34501fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 34601fe661ae5da3739215d93922412df4b24c859a2RoboErik * Stop receiving updates on the specified callback. If an update has 34701fe661ae5da3739215d93922412df4b24c859a2RoboErik * already been posted you may still receive it after calling this method. 34801fe661ae5da3739215d93922412df4b24c859a2RoboErik * 349bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * @param callback The callback to remove. 35001fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 351bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public void removeCallback(@NonNull Callback callback) { 352bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown if (callback == null) { 353bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown throw new IllegalArgumentException("callback must not be null"); 354bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown } 35501fe661ae5da3739215d93922412df4b24c859a2RoboErik synchronized (mLock) { 356bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown removeCallbackLocked(callback); 35701fe661ae5da3739215d93922412df4b24c859a2RoboErik } 35801fe661ae5da3739215d93922412df4b24c859a2RoboErik } 35901fe661ae5da3739215d93922412df4b24c859a2RoboErik 3608ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik /** 3618ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * Sends a generic command to the session. It is up to the session creator 3628ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * to decide what commands and parameters they will support. As such, 3638ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * commands should only be sent to sessions that the controller owns. 3648ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * 3658ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * @param command The command to send 366f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * @param args Any parameters to include with the command 3678ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * @param cb The callback to receive the result on 3688ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik */ 369f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal public void sendCommand(@NonNull String command, @Nullable Bundle args, 370bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown @Nullable ResultReceiver cb) { 3718ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (TextUtils.isEmpty(command)) { 3728ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik throw new IllegalArgumentException("command cannot be null or empty"); 3738ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 3748ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik try { 375f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal mSessionBinder.sendCommand(command, args, cb); 3768ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } catch (RemoteException e) { 3778ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik Log.d(TAG, "Dead object in sendCommand.", e); 3788ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 3798ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 3808ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik 38107c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik /** 382aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik * Get the session owner's package name. 383fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik * 384aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik * @return The package name of of the session owner. 385aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik */ 386aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik public String getPackageName() { 387aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik if (mPackageName == null) { 388aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik try { 389aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik mPackageName = mSessionBinder.getPackageName(); 390aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik } catch (RemoteException e) { 391aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik Log.d(TAG, "Dead object in getPackageName.", e); 392aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik } 393aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik } 394aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik return mPackageName; 395aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik } 396aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik 397aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik /** 398aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik * Get the session's tag for debugging purposes. 399aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik * 400aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik * @return The session's tag. 401fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik * @hide 402fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik */ 403aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik public String getTag() { 404aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik if (mTag == null) { 40573e23e229dd1a2d25687b1c6a63c708665378e41RoboErik try { 406aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik mTag = mSessionBinder.getTag(); 40773e23e229dd1a2d25687b1c6a63c708665378e41RoboErik } catch (RemoteException e) { 408aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik Log.d(TAG, "Dead object in getTag.", e); 40973e23e229dd1a2d25687b1c6a63c708665378e41RoboErik } 410fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik } 411aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik return mTag; 412fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik } 413fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik 41401fe661ae5da3739215d93922412df4b24c859a2RoboErik /* 41501fe661ae5da3739215d93922412df4b24c859a2RoboErik * @hide 41601fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 41707c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik ISessionController getSessionBinder() { 41801fe661ae5da3739215d93922412df4b24c859a2RoboErik return mSessionBinder; 41901fe661ae5da3739215d93922412df4b24c859a2RoboErik } 42001fe661ae5da3739215d93922412df4b24c859a2RoboErik 42101fe661ae5da3739215d93922412df4b24c859a2RoboErik private void addCallbackLocked(Callback cb, Handler handler) { 4228ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (getHandlerForCallbackLocked(cb) != null) { 42301fe661ae5da3739215d93922412df4b24c859a2RoboErik Log.w(TAG, "Callback is already added, ignoring"); 42401fe661ae5da3739215d93922412df4b24c859a2RoboErik return; 42501fe661ae5da3739215d93922412df4b24c859a2RoboErik } 4268ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik MessageHandler holder = new MessageHandler(handler.getLooper(), cb); 4278ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik mCallbacks.add(holder); 42801fe661ae5da3739215d93922412df4b24c859a2RoboErik 42901fe661ae5da3739215d93922412df4b24c859a2RoboErik if (!mCbRegistered) { 43001fe661ae5da3739215d93922412df4b24c859a2RoboErik try { 43101fe661ae5da3739215d93922412df4b24c859a2RoboErik mSessionBinder.registerCallbackListener(mCbStub); 43201fe661ae5da3739215d93922412df4b24c859a2RoboErik mCbRegistered = true; 43301fe661ae5da3739215d93922412df4b24c859a2RoboErik } catch (RemoteException e) { 434d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik Log.e(TAG, "Dead object in registerCallback", e); 43501fe661ae5da3739215d93922412df4b24c859a2RoboErik } 43601fe661ae5da3739215d93922412df4b24c859a2RoboErik } 43701fe661ae5da3739215d93922412df4b24c859a2RoboErik } 43801fe661ae5da3739215d93922412df4b24c859a2RoboErik 4398ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik private boolean removeCallbackLocked(Callback cb) { 440d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik boolean success = false; 4418ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik for (int i = mCallbacks.size() - 1; i >= 0; i--) { 4428ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik MessageHandler handler = mCallbacks.get(i); 4438ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (cb == handler.mCallback) { 4448ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik mCallbacks.remove(i); 445d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik success = true; 44601fe661ae5da3739215d93922412df4b24c859a2RoboErik } 44701fe661ae5da3739215d93922412df4b24c859a2RoboErik } 448d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik if (mCbRegistered && mCallbacks.size() == 0) { 449d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik try { 450d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik mSessionBinder.unregisterCallbackListener(mCbStub); 451d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik } catch (RemoteException e) { 452d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik Log.e(TAG, "Dead object in removeCallbackLocked"); 453d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik } 454d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik mCbRegistered = false; 455d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik } 456d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik return success; 45701fe661ae5da3739215d93922412df4b24c859a2RoboErik } 45801fe661ae5da3739215d93922412df4b24c859a2RoboErik 4598ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik private MessageHandler getHandlerForCallbackLocked(Callback cb) { 4608ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (cb == null) { 4618ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik throw new IllegalArgumentException("Callback cannot be null"); 46201fe661ae5da3739215d93922412df4b24c859a2RoboErik } 4638ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik for (int i = mCallbacks.size() - 1; i >= 0; i--) { 4648ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik MessageHandler handler = mCallbacks.get(i); 4658ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (cb == handler.mCallback) { 4668ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik return handler; 4678ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 46801fe661ae5da3739215d93922412df4b24c859a2RoboErik } 4698ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik return null; 47001fe661ae5da3739215d93922412df4b24c859a2RoboErik } 47101fe661ae5da3739215d93922412df4b24c859a2RoboErik 472c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik private final void postMessage(int what, Object obj, Bundle data) { 4738ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik synchronized (mLock) { 4748ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik for (int i = mCallbacks.size() - 1; i >= 0; i--) { 475c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mCallbacks.get(i).post(what, obj, data); 4768ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 47701fe661ae5da3739215d93922412df4b24c859a2RoboErik } 47801fe661ae5da3739215d93922412df4b24c859a2RoboErik } 47901fe661ae5da3739215d93922412df4b24c859a2RoboErik 48001fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 4818ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * Callback for receiving updates on from the session. A Callback can be 4828ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * registered using {@link #addCallback} 48301fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 48401fe661ae5da3739215d93922412df4b24c859a2RoboErik public static abstract class Callback { 48501fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 4868ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * Override to handle custom events sent by the session owner without a 4878ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * specified interface. Controllers should only handle these for 4888ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * sessions they own. 48901fe661ae5da3739215d93922412df4b24c859a2RoboErik * 490bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * @param event The event from the session. 491bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * @param extras Optional parameters for the event, may be null. 49201fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 493bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public void onSessionEvent(@NonNull String event, @Nullable Bundle extras) { 49401fe661ae5da3739215d93922412df4b24c859a2RoboErik } 49501fe661ae5da3739215d93922412df4b24c859a2RoboErik 49601fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 497c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Override to handle changes in playback state. 498c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 499c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @param state The new playback state of the session 500c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 501bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public void onPlaybackStateChanged(@NonNull PlaybackState state) { 502c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 503c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 504c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 505c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Override to handle changes to the current metadata. 506c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 507bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * @param metadata The current metadata for the session or null if none. 508c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @see MediaMetadata 509c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 510bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public void onMetadataChanged(@Nullable MediaMetadata metadata) { 511c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 51219c9518f6a817d53d5234de0020313cab6950b2fRoboErik 51319c9518f6a817d53d5234de0020313cab6950b2fRoboErik /** 514f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * Override to handle changes to tracks in the queue. 515f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * 516f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * @param queue A list of tracks in the current play queue. It should include the currently 517f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * playing track as well as previous and upcoming tracks if applicable. 518f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * @see MediaSession.Track 519f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal */ 520f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public void onQueueChanged(@Nullable List<MediaSession.Track> queue) { 521f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 522f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 523f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal /** 524f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * Override to handle changes to the queue title. 525f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * 526f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * @param title The title that should be displayed along with the play queue such as 527f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * "Now Playing". May be null if there is no such title. 528f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal */ 529f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public void onQueueTitleChanged(@Nullable CharSequence title) { 530f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 531f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 532f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal /** 533f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * Override to handle changes to the {@link MediaSession} extras. 534f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * 535f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * @param extras The extras that can include other information associated with the 536f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * {@link MediaSession}. 537f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal */ 538f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public void onExtrasChanged(@Nullable Bundle extras) { 539f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 540f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 541f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal /** 54219c9518f6a817d53d5234de0020313cab6950b2fRoboErik * Override to handle changes to the volume info. 54319c9518f6a817d53d5234de0020313cab6950b2fRoboErik * 54419c9518f6a817d53d5234de0020313cab6950b2fRoboErik * @param info The current volume info for this session. 54519c9518f6a817d53d5234de0020313cab6950b2fRoboErik */ 54619c9518f6a817d53d5234de0020313cab6950b2fRoboErik public void onVolumeInfoChanged(VolumeInfo info) { 54719c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 548c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 549c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 550c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 551c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Interface for controlling media playback on a session. This allows an app 552c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * to send media transport commands to the session. 553c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 554c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public final class TransportControls { 555c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik private static final String TAG = "TransportController"; 556c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 557c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik private TransportControls() { 558c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 559c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 560c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 561c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Request that the player start its playback at its current position. 562c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 563c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void play() { 564c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 565c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.play(); 566c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 567c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling play.", e); 568c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 569c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 570c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 571c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 572f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * Request that the player start playback for a specific {@link Uri}. 573f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * 574f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * @param uri The uri of the requested media. 575f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * @param extras Optional extras that can include extra information about the media item 576f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * to be played. 577f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal */ 578f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public void playUri(Uri uri, Bundle extras) { 579f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal if (uri == null) { 580f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal throw new IllegalArgumentException("You must specify a non-null Uri for playUri."); 581f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 582f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal try { 583f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal mSessionBinder.playUri(uri, extras); 584f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } catch (RemoteException e) { 585f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal Log.wtf(TAG, "Error calling play(" + uri + ").", e); 586f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 587f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 588f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 589f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal /** 590f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * Request that the player start playback for a specific search query. 591f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * 592f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * @param query The search query. 593f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * @param extras Optional extras that can include extra information about the query. 594f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal */ 595f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public void playFromSearch(String query, Bundle extras) { 596f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal if (TextUtils.isEmpty(query)) { 597f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal throw new IllegalArgumentException( 598f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal "You must specify a non-empty search query for playFromSearch."); 599f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 600f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal try { 601f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal mSessionBinder.playFromSearch(query, extras); 602f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } catch (RemoteException e) { 603f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal Log.wtf(TAG, "Error calling play(" + query + ").", e); 604f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 605f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 606f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 607f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal /** 608f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * Play a track with a specific id in the play queue. 609f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * If you specify an id that is not in the play queue, the behavior is undefined. 610f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal */ 611f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public void skipToTrack(long id) { 612f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal try { 613f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal mSessionBinder.skipToTrack(id); 614f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } catch (RemoteException e) { 615f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal Log.wtf(TAG, "Error calling skipToTrack(" + id + ").", e); 616f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 617f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 618f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 619f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal /** 620c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Request that the player pause its playback and stay at its current 621c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * position. 622c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 623c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void pause() { 624c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 625c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.pause(); 626c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 627c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling pause.", e); 628c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 629c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 630c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 631c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 632c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Request that the player stop its playback; it may clear its state in 633c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * whatever way is appropriate. 634c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 635c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void stop() { 636c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 637c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.stop(); 638c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 639c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling stop.", e); 640c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 641c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 642c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 643c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 644c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Move to a new location in the media stream. 645c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 646c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @param pos Position to move to, in milliseconds. 647c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 648c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void seekTo(long pos) { 649c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 650c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.seekTo(pos); 651c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 652c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling seekTo.", e); 653c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 654c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 655c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 656c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 657c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Start fast forwarding. If playback is already fast forwarding this 658c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * may increase the rate. 659c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 660c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void fastForward() { 661c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 662c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.fastForward(); 663c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 664c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling fastForward.", e); 665c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 666c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 667c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 668c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 669c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Skip to the next item. 670c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 671c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void skipToNext() { 672c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 673c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.next(); 674c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 675c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling next.", e); 676c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 677c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 678c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 679c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 680c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Start rewinding. If playback is already rewinding this may increase 681c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * the rate. 682c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 683c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void rewind() { 684c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 685c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.rewind(); 686c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 687c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling rewind.", e); 688c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 689c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 690c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 691c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 692c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Skip to the previous item. 693c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 694c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void skipToPrevious() { 695c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 696c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.previous(); 697c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 698c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling previous.", e); 699c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 700c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 701c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 702c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 703c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Rate the current content. This will cause the rating to be set for 704c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * the current user. The Rating type must match the type returned by 705c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * {@link #getRatingType()}. 706c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 707c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @param rating The rating to set for the current content 708c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 709c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void setRating(Rating rating) { 710c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 711c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.rate(rating); 712c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 713c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling rate.", e); 714c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 715c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 716f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal 717f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal /** 718f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * Send a custom action back for the {@link MediaSession} to perform. 719f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * 720f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * @param customAction The action to perform. 721f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * @param args Optional arguments to supply to the {@link MediaSession} for this 722f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * custom action. 723f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal */ 724f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal public void sendCustomAction(@NonNull PlaybackState.CustomAction customAction, 725f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal @Nullable Bundle args) { 726f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal if (customAction == null) { 727f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal throw new IllegalArgumentException("CustomAction cannot be null."); 728f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal } 729f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal sendCustomAction(customAction.getAction(), args); 730f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal } 731f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal 732f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal /** 733f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * Send the id and args from a custom action back for the {@link MediaSession} to perform. 734f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * 735f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * @see #sendCustomAction(PlaybackState.CustomAction action, Bundle args) 736f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * @param action The action identifier of the {@link PlaybackState.CustomAction} as 737f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * specified by the {@link MediaSession}. 738f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * @param args Optional arguments to supply to the {@link MediaSession} for this 739f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * custom action. 740f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal */ 741f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal public void sendCustomAction(@NonNull String action, @Nullable Bundle args) { 742f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal if (TextUtils.isEmpty(action)) { 743f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal throw new IllegalArgumentException("CustomAction cannot be null."); 744f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal } 745f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal try { 746f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal mSessionBinder.sendCustomAction(action, args); 747f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal } catch (RemoteException e) { 748f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal Log.d(TAG, "Dead object in sendCustomAction.", e); 749f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal } 750f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal } 7518ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 75201fe661ae5da3739215d93922412df4b24c859a2RoboErik 753ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 754ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Holds information about the way volume is handled for this session. 755ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 756ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik public static final class VolumeInfo { 757ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik private final int mVolumeType; 758ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik private final int mVolumeControl; 759ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik private final int mMaxVolume; 760ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik private final int mCurrentVolume; 7619db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik private final AudioAttributes mAudioAttrs; 762ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 763ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 764ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @hide 765ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 7669db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik public VolumeInfo(int type, AudioAttributes attrs, int control, int max, int current) { 767ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik mVolumeType = type; 7689db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik mAudioAttrs = attrs; 769ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik mVolumeControl = control; 770ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik mMaxVolume = max; 771ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik mCurrentVolume = current; 772ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 773ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 774ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 775ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Get the type of volume handling, either local or remote. One of: 776ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * <ul> 77719c9518f6a817d53d5234de0020313cab6950b2fRoboErik * <li>{@link MediaSession#PLAYBACK_TYPE_LOCAL}</li> 77819c9518f6a817d53d5234de0020313cab6950b2fRoboErik * <li>{@link MediaSession#PLAYBACK_TYPE_REMOTE}</li> 779ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * </ul> 780ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 781ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @return The type of volume handling this session is using. 782ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 783ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik public int getVolumeType() { 784ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return mVolumeType; 785ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 786ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 787ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 7889db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * Get the audio attributes for this session. The attributes will affect 7899db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * volume handling for the session. When the volume type is 7909db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * {@link MediaSession#PLAYBACK_TYPE_REMOTE} these may be ignored by the 7919db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * remote volume handler. 792ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 7939db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * @return The attributes for this session. 794ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 7959db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik public AudioAttributes getAudioAttributes() { 7969db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik return mAudioAttrs; 797ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 798ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 799ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 800ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Get the type of volume control that can be used. One of: 801ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * <ul> 802ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * <li>{@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}</li> 803ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * <li>{@link VolumeProvider#VOLUME_CONTROL_RELATIVE}</li> 804ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * <li>{@link VolumeProvider#VOLUME_CONTROL_FIXED}</li> 805ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * </ul> 806ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 807ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @return The type of volume control that may be used with this 808ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * session. 809ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 810ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik public int getVolumeControl() { 811ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return mVolumeControl; 812ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 813ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 814ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 815ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Get the maximum volume that may be set for this session. 816ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 817ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @return The maximum allowed volume where this session is playing. 818ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 819ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik public int getMaxVolume() { 820ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return mMaxVolume; 821ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 822ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 823ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 824ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Get the current volume for this session. 825ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 826ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @return The current volume where this session is playing. 827ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 828ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik public int getCurrentVolume() { 829ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return mCurrentVolume; 830ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 831ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 832ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 83307c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik private final static class CallbackStub extends ISessionControllerCallback.Stub { 83442ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik private final WeakReference<MediaController> mController; 83501fe661ae5da3739215d93922412df4b24c859a2RoboErik 83642ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik public CallbackStub(MediaController controller) { 83742ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik mController = new WeakReference<MediaController>(controller); 83801fe661ae5da3739215d93922412df4b24c859a2RoboErik } 83901fe661ae5da3739215d93922412df4b24c859a2RoboErik 84001fe661ae5da3739215d93922412df4b24c859a2RoboErik @Override 8418ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik public void onEvent(String event, Bundle extras) { 84242ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik MediaController controller = mController.get(); 8438ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (controller != null) { 844c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik controller.postMessage(MSG_EVENT, event, extras); 84501fe661ae5da3739215d93922412df4b24c859a2RoboErik } 84601fe661ae5da3739215d93922412df4b24c859a2RoboErik } 84701fe661ae5da3739215d93922412df4b24c859a2RoboErik 84801fe661ae5da3739215d93922412df4b24c859a2RoboErik @Override 8498ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik public void onPlaybackStateChanged(PlaybackState state) { 85042ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik MediaController controller = mController.get(); 8518ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (controller != null) { 852c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik controller.postMessage(MSG_UPDATE_PLAYBACK_STATE, state, null); 85301fe661ae5da3739215d93922412df4b24c859a2RoboErik } 85401fe661ae5da3739215d93922412df4b24c859a2RoboErik } 85501fe661ae5da3739215d93922412df4b24c859a2RoboErik 85601fe661ae5da3739215d93922412df4b24c859a2RoboErik @Override 8578ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik public void onMetadataChanged(MediaMetadata metadata) { 85842ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik MediaController controller = mController.get(); 8598ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (controller != null) { 860c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik controller.postMessage(MSG_UPDATE_METADATA, metadata, null); 86101fe661ae5da3739215d93922412df4b24c859a2RoboErik } 86201fe661ae5da3739215d93922412df4b24c859a2RoboErik } 86301fe661ae5da3739215d93922412df4b24c859a2RoboErik 86419c9518f6a817d53d5234de0020313cab6950b2fRoboErik @Override 865f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public void onQueueChanged(ParceledListSlice parceledQueue) { 866f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal List<MediaSession.Track> queue = parceledQueue.getList(); 867f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal MediaController controller = mController.get(); 868f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal if (controller != null) { 869f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal controller.postMessage(MSG_UPDATE_QUEUE, queue, null); 870f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 871f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 872f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 873f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal @Override 874f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public void onQueueTitleChanged(CharSequence title) { 875f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal MediaController controller = mController.get(); 876f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal if (controller != null) { 877f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal controller.postMessage(MSG_UPDATE_QUEUE_TITLE, title, null); 878f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 879f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 880f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 881f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal @Override 882f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public void onExtrasChanged(Bundle extras) { 883f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal MediaController controller = mController.get(); 884f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal if (controller != null) { 885f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal controller.postMessage(MSG_UPDATE_EXTRAS, extras, null); 886f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 887f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 888f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 889f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal @Override 89019c9518f6a817d53d5234de0020313cab6950b2fRoboErik public void onVolumeInfoChanged(ParcelableVolumeInfo pvi) { 89119c9518f6a817d53d5234de0020313cab6950b2fRoboErik MediaController controller = mController.get(); 89219c9518f6a817d53d5234de0020313cab6950b2fRoboErik if (controller != null) { 8939db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik VolumeInfo info = new VolumeInfo(pvi.volumeType, pvi.audioAttrs, pvi.controlType, 89419c9518f6a817d53d5234de0020313cab6950b2fRoboErik pvi.maxVolume, pvi.currentVolume); 89519c9518f6a817d53d5234de0020313cab6950b2fRoboErik controller.postMessage(MSG_UPDATE_VOLUME, info, null); 89619c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 89719c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 89819c9518f6a817d53d5234de0020313cab6950b2fRoboErik 89901fe661ae5da3739215d93922412df4b24c859a2RoboErik } 90001fe661ae5da3739215d93922412df4b24c859a2RoboErik 90101fe661ae5da3739215d93922412df4b24c859a2RoboErik private final static class MessageHandler extends Handler { 90242ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik private final MediaController.Callback mCallback; 90301fe661ae5da3739215d93922412df4b24c859a2RoboErik 90442ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik public MessageHandler(Looper looper, MediaController.Callback cb) { 9058ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik super(looper, null, true); 9068ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik mCallback = cb; 90701fe661ae5da3739215d93922412df4b24c859a2RoboErik } 90801fe661ae5da3739215d93922412df4b24c859a2RoboErik 90901fe661ae5da3739215d93922412df4b24c859a2RoboErik @Override 91001fe661ae5da3739215d93922412df4b24c859a2RoboErik public void handleMessage(Message msg) { 91101fe661ae5da3739215d93922412df4b24c859a2RoboErik switch (msg.what) { 9128ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik case MSG_EVENT: 91379fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik mCallback.onSessionEvent((String) msg.obj, msg.getData()); 91401fe661ae5da3739215d93922412df4b24c859a2RoboErik break; 915c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik case MSG_UPDATE_PLAYBACK_STATE: 916c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mCallback.onPlaybackStateChanged((PlaybackState) msg.obj); 917c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik break; 918c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik case MSG_UPDATE_METADATA: 919c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mCallback.onMetadataChanged((MediaMetadata) msg.obj); 920c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik break; 921f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal case MSG_UPDATE_QUEUE: 922f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal mCallback.onQueueChanged((List<MediaSession.Track>) msg.obj); 923f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal break; 924f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal case MSG_UPDATE_QUEUE_TITLE: 925f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal mCallback.onQueueTitleChanged((CharSequence) msg.obj); 926f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal break; 927f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal case MSG_UPDATE_EXTRAS: 928f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal mCallback.onExtrasChanged((Bundle) msg.obj); 929f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal break; 93019c9518f6a817d53d5234de0020313cab6950b2fRoboErik case MSG_UPDATE_VOLUME: 93119c9518f6a817d53d5234de0020313cab6950b2fRoboErik mCallback.onVolumeInfoChanged((VolumeInfo) msg.obj); 93219c9518f6a817d53d5234de0020313cab6950b2fRoboErik break; 93301fe661ae5da3739215d93922412df4b24c859a2RoboErik } 93401fe661ae5da3739215d93922412df4b24c859a2RoboErik } 9358ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik 9368ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik public void post(int what, Object obj, Bundle data) { 9378ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik obtainMessage(what, obj).sendToTarget(); 9388ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 93901fe661ae5da3739215d93922412df4b24c859a2RoboErik } 94001fe661ae5da3739215d93922412df4b24c859a2RoboErik 94101fe661ae5da3739215d93922412df4b24c859a2RoboErik} 942