MediaController.java revision aa4e23bbb36994708ba72c5f4c83255025d99e07
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; 22f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Pealimport android.content.pm.ParceledListSlice; 239db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErikimport android.media.AudioAttributes; 2419c9518f6a817d53d5234de0020313cab6950b2fRoboErikimport android.media.AudioManager; 2542ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErikimport android.media.MediaMetadata; 26c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErikimport android.media.Rating; 27ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErikimport android.media.VolumeProvider; 281a937b04e63539cb1fab1bde601031d415c7156fJeff Brownimport android.media.routing.MediaRouter; 29f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Pealimport android.net.Uri; 3001fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.os.Bundle; 3101fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.os.Handler; 3201fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.os.Looper; 3301fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.os.Message; 3401fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.os.RemoteException; 358ae0f34db936a649ddaf9cdd086c224f6514efebRoboErikimport android.os.ResultReceiver; 3601fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.text.TextUtils; 3701fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.util.Log; 3801fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.view.KeyEvent; 3901fe661ae5da3739215d93922412df4b24c859a2RoboErik 408ae0f34db936a649ddaf9cdd086c224f6514efebRoboErikimport java.lang.ref.WeakReference; 4101fe661ae5da3739215d93922412df4b24c859a2RoboErikimport java.util.ArrayList; 42f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Pealimport java.util.List; 4301fe661ae5da3739215d93922412df4b24c859a2RoboErik 4401fe661ae5da3739215d93922412df4b24c859a2RoboErik/** 4501fe661ae5da3739215d93922412df4b24c859a2RoboErik * Allows an app to interact with an ongoing media session. Media buttons and 4601fe661ae5da3739215d93922412df4b24c859a2RoboErik * other commands can be sent to the session. A callback may be registered to 4701fe661ae5da3739215d93922412df4b24c859a2RoboErik * receive updates from the session, such as metadata and play state changes. 4801fe661ae5da3739215d93922412df4b24c859a2RoboErik * <p> 4942ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik * A MediaController can be created through {@link MediaSessionManager} if you 5001fe661ae5da3739215d93922412df4b24c859a2RoboErik * hold the "android.permission.MEDIA_CONTENT_CONTROL" permission or directly if 51dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown * you have a {@link MediaSession.Token} from the session owner. 5201fe661ae5da3739215d93922412df4b24c859a2RoboErik * <p> 5301fe661ae5da3739215d93922412df4b24c859a2RoboErik * MediaController objects are thread-safe. 5401fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 5542ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErikpublic final class MediaController { 56bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown private static final String TAG = "MediaController"; 5701fe661ae5da3739215d93922412df4b24c859a2RoboErik 588ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik private static final int MSG_EVENT = 1; 59c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik private static final int MSG_UPDATE_PLAYBACK_STATE = 2; 60c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik private static final int MSG_UPDATE_METADATA = 3; 6101a500ed1c6ae3fff66678144ae637aa8cad0eccJeff Brown private static final int MSG_UPDATE_VOLUME = 4; 62f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal private static final int MSG_UPDATE_QUEUE = 5; 63f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal private static final int MSG_UPDATE_QUEUE_TITLE = 6; 64f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal private static final int MSG_UPDATE_EXTRAS = 7; 6501fe661ae5da3739215d93922412df4b24c859a2RoboErik 6607c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik private final ISessionController mSessionBinder; 6701fe661ae5da3739215d93922412df4b24c859a2RoboErik 6876fca4e177e18b591439fdff64b8f5242a5122d0RoboErik private final MediaSession.Token mToken; 698ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik private final CallbackStub mCbStub = new CallbackStub(this); 708ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik private final ArrayList<MessageHandler> mCallbacks = new ArrayList<MessageHandler>(); 7101fe661ae5da3739215d93922412df4b24c859a2RoboErik private final Object mLock = new Object(); 7201fe661ae5da3739215d93922412df4b24c859a2RoboErik 7301fe661ae5da3739215d93922412df4b24c859a2RoboErik private boolean mCbRegistered = false; 74aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik private String mPackageName; 75aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik private String mTag; 7601fe661ae5da3739215d93922412df4b24c859a2RoboErik 771a937b04e63539cb1fab1bde601031d415c7156fJeff Brown private final TransportControls mTransportControls; 788ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik 7901fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 808b4bffcac996b4083e720310a09d315ca1c4a000RoboErik * Call for creating a MediaController directly from a binder. Should only 818b4bffcac996b4083e720310a09d315ca1c4a000RoboErik * be used by framework code. 828b4bffcac996b4083e720310a09d315ca1c4a000RoboErik * 838ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * @hide 8401fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 858b4bffcac996b4083e720310a09d315ca1c4a000RoboErik public MediaController(ISessionController sessionBinder) { 868b4bffcac996b4083e720310a09d315ca1c4a000RoboErik if (sessionBinder == null) { 878b4bffcac996b4083e720310a09d315ca1c4a000RoboErik throw new IllegalArgumentException("Session token cannot be null"); 888b4bffcac996b4083e720310a09d315ca1c4a000RoboErik } 898b4bffcac996b4083e720310a09d315ca1c4a000RoboErik mSessionBinder = sessionBinder; 908b4bffcac996b4083e720310a09d315ca1c4a000RoboErik mTransportControls = new TransportControls(); 9176fca4e177e18b591439fdff64b8f5242a5122d0RoboErik mToken = new MediaSession.Token(sessionBinder); 9201fe661ae5da3739215d93922412df4b24c859a2RoboErik } 9301fe661ae5da3739215d93922412df4b24c859a2RoboErik 9401fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 958b4bffcac996b4083e720310a09d315ca1c4a000RoboErik * Create a new MediaController from a session's token. 968ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * 978b4bffcac996b4083e720310a09d315ca1c4a000RoboErik * @param token The token for the session. 9801fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 998b4bffcac996b4083e720310a09d315ca1c4a000RoboErik public MediaController(@NonNull MediaSession.Token token) { 1008b4bffcac996b4083e720310a09d315ca1c4a000RoboErik this(token.getBinder()); 10101fe661ae5da3739215d93922412df4b24c859a2RoboErik } 10201fe661ae5da3739215d93922412df4b24c859a2RoboErik 10301fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 1041a937b04e63539cb1fab1bde601031d415c7156fJeff Brown * Get a {@link TransportControls} instance to send transport actions to 1051a937b04e63539cb1fab1bde601031d415c7156fJeff Brown * the associated session. 10601fe661ae5da3739215d93922412df4b24c859a2RoboErik * 1071a937b04e63539cb1fab1bde601031d415c7156fJeff Brown * @return A transport controls instance. 10801fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 109bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public @NonNull TransportControls getTransportControls() { 1101a937b04e63539cb1fab1bde601031d415c7156fJeff Brown return mTransportControls; 1111a937b04e63539cb1fab1bde601031d415c7156fJeff Brown } 1121a937b04e63539cb1fab1bde601031d415c7156fJeff Brown 1131a937b04e63539cb1fab1bde601031d415c7156fJeff Brown /** 1141a937b04e63539cb1fab1bde601031d415c7156fJeff Brown * Creates a media router delegate through which the destination of the media 1151a937b04e63539cb1fab1bde601031d415c7156fJeff Brown * router may be observed and controlled. 1161a937b04e63539cb1fab1bde601031d415c7156fJeff Brown * 1171a937b04e63539cb1fab1bde601031d415c7156fJeff Brown * @return The media router delegate, or null if the media session does 1181a937b04e63539cb1fab1bde601031d415c7156fJeff Brown * not support media routing. 1191a937b04e63539cb1fab1bde601031d415c7156fJeff Brown */ 1201a937b04e63539cb1fab1bde601031d415c7156fJeff Brown public @Nullable MediaRouter.Delegate createMediaRouterDelegate() { 1211a937b04e63539cb1fab1bde601031d415c7156fJeff Brown return new MediaRouter.Delegate(); 12201fe661ae5da3739215d93922412df4b24c859a2RoboErik } 12301fe661ae5da3739215d93922412df4b24c859a2RoboErik 12401fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 12579fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik * Send the specified media button event to the session. Only media keys can 12679fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik * be sent by this method, other keys will be ignored. 12701fe661ae5da3739215d93922412df4b24c859a2RoboErik * 12879fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik * @param keyEvent The media button event to dispatch. 12979fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik * @return true if the event was sent to the session, false otherwise. 13001fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 131bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public boolean dispatchMediaButtonEvent(@NonNull KeyEvent keyEvent) { 13279fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik if (keyEvent == null) { 13379fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik throw new IllegalArgumentException("KeyEvent may not be null"); 13479fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik } 13579fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik if (!KeyEvent.isMediaKey(keyEvent.getKeyCode())) { 13679fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik return false; 13701fe661ae5da3739215d93922412df4b24c859a2RoboErik } 13801fe661ae5da3739215d93922412df4b24c859a2RoboErik try { 13979fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik return mSessionBinder.sendMediaButton(keyEvent); 14001fe661ae5da3739215d93922412df4b24c859a2RoboErik } catch (RemoteException e) { 141c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik // System is dead. =( 14201fe661ae5da3739215d93922412df4b24c859a2RoboErik } 14379fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik return false; 14401fe661ae5da3739215d93922412df4b24c859a2RoboErik } 14501fe661ae5da3739215d93922412df4b24c859a2RoboErik 14601fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 147c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Get the current playback state for this session. 148c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 149c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @return The current PlaybackState or null 150c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 151bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public @Nullable PlaybackState getPlaybackState() { 152c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 153c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return mSessionBinder.getPlaybackState(); 154c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 155c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling getPlaybackState.", e); 156c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return null; 157c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 158c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 159c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 160c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 161c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Get the current metadata for this session. 162c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 163c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @return The current MediaMetadata or null. 164c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 165bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public @Nullable MediaMetadata getMetadata() { 166c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 167c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return mSessionBinder.getMetadata(); 168c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 169c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling getMetadata.", e); 170c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return null; 171c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 172c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 173c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 174c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 175f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * Get the current play queue for this session. 176f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * 177f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * @return The current play queue or null. 178f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal */ 179f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public @Nullable List<MediaSession.Track> getQueue() { 180f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal try { 181f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal ParceledListSlice queue = mSessionBinder.getQueue(); 182f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal if (queue != null) { 183f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal return queue.getList(); 184f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 185f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } catch (RemoteException e) { 186f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal Log.wtf(TAG, "Error calling getQueue.", e); 187f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 188f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal return null; 189f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 190f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 191f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal /** 192c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Get the rating type supported by the session. One of: 193c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <ul> 194c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_NONE}</li> 195c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_HEART}</li> 196c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_THUMB_UP_DOWN}</li> 197c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_3_STARS}</li> 198c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_4_STARS}</li> 199c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_5_STARS}</li> 200c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_PERCENTAGE}</li> 201c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * </ul> 202c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 203c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @return The supported rating type 204c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 205c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public int getRatingType() { 206c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 207c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return mSessionBinder.getRatingType(); 208c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 209c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling getRatingType.", e); 210c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return Rating.RATING_NONE; 211c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 212c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 213c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 214c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 21576fca4e177e18b591439fdff64b8f5242a5122d0RoboErik * Get the flags for this session. Flags are defined in {@link MediaSession}. 21673e23e229dd1a2d25687b1c6a63c708665378e41RoboErik * 21773e23e229dd1a2d25687b1c6a63c708665378e41RoboErik * @return The current set of flags for the session. 21873e23e229dd1a2d25687b1c6a63c708665378e41RoboErik */ 21976fca4e177e18b591439fdff64b8f5242a5122d0RoboErik public @MediaSession.SessionFlags long getFlags() { 22073e23e229dd1a2d25687b1c6a63c708665378e41RoboErik try { 22173e23e229dd1a2d25687b1c6a63c708665378e41RoboErik return mSessionBinder.getFlags(); 22273e23e229dd1a2d25687b1c6a63c708665378e41RoboErik } catch (RemoteException e) { 22373e23e229dd1a2d25687b1c6a63c708665378e41RoboErik Log.wtf(TAG, "Error calling getFlags.", e); 22473e23e229dd1a2d25687b1c6a63c708665378e41RoboErik } 22573e23e229dd1a2d25687b1c6a63c708665378e41RoboErik return 0; 22673e23e229dd1a2d25687b1c6a63c708665378e41RoboErik } 22773e23e229dd1a2d25687b1c6a63c708665378e41RoboErik 22873e23e229dd1a2d25687b1c6a63c708665378e41RoboErik /** 229ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Get the current volume info for this session. 230ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 231ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @return The current volume info or null. 232ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 233bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public @Nullable VolumeInfo getVolumeInfo() { 234ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik try { 235ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik ParcelableVolumeInfo result = mSessionBinder.getVolumeAttributes(); 2369db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik return new VolumeInfo(result.volumeType, result.audioAttrs, result.controlType, 237ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik result.maxVolume, result.currentVolume); 238ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 239ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } catch (RemoteException e) { 240ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik Log.wtf(TAG, "Error calling getVolumeInfo.", e); 241ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 242ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return null; 243ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 244ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 245ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 246e34c09daf89fb888fe2638e71758573462d85173RoboErik * Get an intent for launching UI associated with this session if one 247e34c09daf89fb888fe2638e71758573462d85173RoboErik * exists. 248e34c09daf89fb888fe2638e71758573462d85173RoboErik * 249e34c09daf89fb888fe2638e71758573462d85173RoboErik * @return A {@link PendingIntent} to launch UI or null. 250e34c09daf89fb888fe2638e71758573462d85173RoboErik */ 251e34c09daf89fb888fe2638e71758573462d85173RoboErik public @Nullable PendingIntent getLaunchActivity() { 252e34c09daf89fb888fe2638e71758573462d85173RoboErik try { 253e34c09daf89fb888fe2638e71758573462d85173RoboErik return mSessionBinder.getLaunchPendingIntent(); 254e34c09daf89fb888fe2638e71758573462d85173RoboErik } catch (RemoteException e) { 255e34c09daf89fb888fe2638e71758573462d85173RoboErik Log.wtf(TAG, "Error calling getPendingIntent.", e); 256e34c09daf89fb888fe2638e71758573462d85173RoboErik } 257e34c09daf89fb888fe2638e71758573462d85173RoboErik return null; 258e34c09daf89fb888fe2638e71758573462d85173RoboErik } 259e34c09daf89fb888fe2638e71758573462d85173RoboErik 260e34c09daf89fb888fe2638e71758573462d85173RoboErik /** 26176fca4e177e18b591439fdff64b8f5242a5122d0RoboErik * Get the token for the session this is connected to. 26276fca4e177e18b591439fdff64b8f5242a5122d0RoboErik * 26376fca4e177e18b591439fdff64b8f5242a5122d0RoboErik * @return The token for the connected session. 26476fca4e177e18b591439fdff64b8f5242a5122d0RoboErik */ 26576fca4e177e18b591439fdff64b8f5242a5122d0RoboErik public @NonNull MediaSession.Token getSessionToken() { 26676fca4e177e18b591439fdff64b8f5242a5122d0RoboErik return mToken; 26776fca4e177e18b591439fdff64b8f5242a5122d0RoboErik } 26876fca4e177e18b591439fdff64b8f5242a5122d0RoboErik 26976fca4e177e18b591439fdff64b8f5242a5122d0RoboErik /** 2709db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * Set the volume of the output this session is playing on. The command will 2719db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * be ignored if it does not support 27219c9518f6a817d53d5234de0020313cab6950b2fRoboErik * {@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}. The flags in 27319c9518f6a817d53d5234de0020313cab6950b2fRoboErik * {@link AudioManager} may be used to affect the handling. 27419c9518f6a817d53d5234de0020313cab6950b2fRoboErik * 27519c9518f6a817d53d5234de0020313cab6950b2fRoboErik * @see #getVolumeInfo() 27619c9518f6a817d53d5234de0020313cab6950b2fRoboErik * @param value The value to set it to, between 0 and the reported max. 27719c9518f6a817d53d5234de0020313cab6950b2fRoboErik * @param flags Any flags to pass with the command. 27819c9518f6a817d53d5234de0020313cab6950b2fRoboErik */ 27919c9518f6a817d53d5234de0020313cab6950b2fRoboErik public void setVolumeTo(int value, int flags) { 28019c9518f6a817d53d5234de0020313cab6950b2fRoboErik try { 28119c9518f6a817d53d5234de0020313cab6950b2fRoboErik mSessionBinder.setVolumeTo(value, flags); 28219c9518f6a817d53d5234de0020313cab6950b2fRoboErik } catch (RemoteException e) { 28319c9518f6a817d53d5234de0020313cab6950b2fRoboErik Log.wtf(TAG, "Error calling setVolumeTo.", e); 28419c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 28519c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 28619c9518f6a817d53d5234de0020313cab6950b2fRoboErik 28719c9518f6a817d53d5234de0020313cab6950b2fRoboErik /** 2889db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * Adjust the volume of the output this session is playing on. The direction 2899db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * must be one of {@link AudioManager#ADJUST_LOWER}, 2901ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik * {@link AudioManager#ADJUST_RAISE}, or {@link AudioManager#ADJUST_SAME}. 2911ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik * The command will be ignored if the session does not support 2921ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik * {@link VolumeProvider#VOLUME_CONTROL_RELATIVE} or 29319c9518f6a817d53d5234de0020313cab6950b2fRoboErik * {@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}. The flags in 29419c9518f6a817d53d5234de0020313cab6950b2fRoboErik * {@link AudioManager} may be used to affect the handling. 29519c9518f6a817d53d5234de0020313cab6950b2fRoboErik * 29619c9518f6a817d53d5234de0020313cab6950b2fRoboErik * @see #getVolumeInfo() 2971ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik * @param direction The direction to adjust the volume in. 29819c9518f6a817d53d5234de0020313cab6950b2fRoboErik * @param flags Any flags to pass with the command. 29919c9518f6a817d53d5234de0020313cab6950b2fRoboErik */ 3001ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik public void adjustVolume(int direction, int flags) { 30119c9518f6a817d53d5234de0020313cab6950b2fRoboErik try { 3021ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik mSessionBinder.adjustVolume(direction, flags); 30319c9518f6a817d53d5234de0020313cab6950b2fRoboErik } catch (RemoteException e) { 30419c9518f6a817d53d5234de0020313cab6950b2fRoboErik Log.wtf(TAG, "Error calling adjustVolumeBy.", e); 30519c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 30619c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 30719c9518f6a817d53d5234de0020313cab6950b2fRoboErik 30819c9518f6a817d53d5234de0020313cab6950b2fRoboErik /** 30901fe661ae5da3739215d93922412df4b24c859a2RoboErik * Adds a callback to receive updates from the Session. Updates will be 31001fe661ae5da3739215d93922412df4b24c859a2RoboErik * posted on the caller's thread. 31101fe661ae5da3739215d93922412df4b24c859a2RoboErik * 312bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * @param callback The callback object, must not be null. 31301fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 314bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public void addCallback(@NonNull Callback callback) { 315bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown addCallback(callback, null); 31601fe661ae5da3739215d93922412df4b24c859a2RoboErik } 31701fe661ae5da3739215d93922412df4b24c859a2RoboErik 31801fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 31901fe661ae5da3739215d93922412df4b24c859a2RoboErik * Adds a callback to receive updates from the session. Updates will be 3208ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * posted on the specified handler's thread. 32101fe661ae5da3739215d93922412df4b24c859a2RoboErik * 322bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * @param callback The callback object, must not be null. 3238ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * @param handler The handler to post updates on. If null the callers thread 324bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * will be used. 32501fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 326bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public void addCallback(@NonNull Callback callback, @Nullable Handler handler) { 327bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown if (callback == null) { 328bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown throw new IllegalArgumentException("callback must not be null"); 329bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown } 33001fe661ae5da3739215d93922412df4b24c859a2RoboErik if (handler == null) { 33101fe661ae5da3739215d93922412df4b24c859a2RoboErik handler = new Handler(); 33201fe661ae5da3739215d93922412df4b24c859a2RoboErik } 33301fe661ae5da3739215d93922412df4b24c859a2RoboErik synchronized (mLock) { 334bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown addCallbackLocked(callback, handler); 33501fe661ae5da3739215d93922412df4b24c859a2RoboErik } 33601fe661ae5da3739215d93922412df4b24c859a2RoboErik } 33701fe661ae5da3739215d93922412df4b24c859a2RoboErik 33801fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 33901fe661ae5da3739215d93922412df4b24c859a2RoboErik * Stop receiving updates on the specified callback. If an update has 34001fe661ae5da3739215d93922412df4b24c859a2RoboErik * already been posted you may still receive it after calling this method. 34101fe661ae5da3739215d93922412df4b24c859a2RoboErik * 342bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * @param callback The callback to remove. 34301fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 344bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public void removeCallback(@NonNull Callback callback) { 345bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown if (callback == null) { 346bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown throw new IllegalArgumentException("callback must not be null"); 347bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown } 34801fe661ae5da3739215d93922412df4b24c859a2RoboErik synchronized (mLock) { 349bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown removeCallbackLocked(callback); 35001fe661ae5da3739215d93922412df4b24c859a2RoboErik } 35101fe661ae5da3739215d93922412df4b24c859a2RoboErik } 35201fe661ae5da3739215d93922412df4b24c859a2RoboErik 3538ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik /** 3548ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * Sends a generic command to the session. It is up to the session creator 3558ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * to decide what commands and parameters they will support. As such, 3568ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * commands should only be sent to sessions that the controller owns. 3578ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * 3588ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * @param command The command to send 359f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * @param args Any parameters to include with the command 3608ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * @param cb The callback to receive the result on 3618ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik */ 362f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal public void sendCommand(@NonNull String command, @Nullable Bundle args, 363bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown @Nullable ResultReceiver cb) { 3648ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (TextUtils.isEmpty(command)) { 3658ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik throw new IllegalArgumentException("command cannot be null or empty"); 3668ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 3678ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik try { 368f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal mSessionBinder.sendCommand(command, args, cb); 3698ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } catch (RemoteException e) { 3708ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik Log.d(TAG, "Dead object in sendCommand.", e); 3718ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 3728ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 3738ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik 37407c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik /** 375aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik * Get the session owner's package name. 376fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik * 377aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik * @return The package name of of the session owner. 378aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik */ 379aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik public String getPackageName() { 380aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik if (mPackageName == null) { 381aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik try { 382aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik mPackageName = mSessionBinder.getPackageName(); 383aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik } catch (RemoteException e) { 384aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik Log.d(TAG, "Dead object in getPackageName.", e); 385aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik } 386aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik } 387aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik return mPackageName; 388aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik } 389aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik 390aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik /** 391aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik * Get the session's tag for debugging purposes. 392aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik * 393aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik * @return The session's tag. 394fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik * @hide 395fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik */ 396aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik public String getTag() { 397aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik if (mTag == null) { 39873e23e229dd1a2d25687b1c6a63c708665378e41RoboErik try { 399aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik mTag = mSessionBinder.getTag(); 40073e23e229dd1a2d25687b1c6a63c708665378e41RoboErik } catch (RemoteException e) { 401aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik Log.d(TAG, "Dead object in getTag.", e); 40273e23e229dd1a2d25687b1c6a63c708665378e41RoboErik } 403fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik } 404aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik return mTag; 405fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik } 406fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik 40701fe661ae5da3739215d93922412df4b24c859a2RoboErik /* 40801fe661ae5da3739215d93922412df4b24c859a2RoboErik * @hide 40901fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 41007c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik ISessionController getSessionBinder() { 41101fe661ae5da3739215d93922412df4b24c859a2RoboErik return mSessionBinder; 41201fe661ae5da3739215d93922412df4b24c859a2RoboErik } 41301fe661ae5da3739215d93922412df4b24c859a2RoboErik 41401fe661ae5da3739215d93922412df4b24c859a2RoboErik private void addCallbackLocked(Callback cb, Handler handler) { 4158ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (getHandlerForCallbackLocked(cb) != null) { 41601fe661ae5da3739215d93922412df4b24c859a2RoboErik Log.w(TAG, "Callback is already added, ignoring"); 41701fe661ae5da3739215d93922412df4b24c859a2RoboErik return; 41801fe661ae5da3739215d93922412df4b24c859a2RoboErik } 4198ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik MessageHandler holder = new MessageHandler(handler.getLooper(), cb); 4208ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik mCallbacks.add(holder); 42101fe661ae5da3739215d93922412df4b24c859a2RoboErik 42201fe661ae5da3739215d93922412df4b24c859a2RoboErik if (!mCbRegistered) { 42301fe661ae5da3739215d93922412df4b24c859a2RoboErik try { 42401fe661ae5da3739215d93922412df4b24c859a2RoboErik mSessionBinder.registerCallbackListener(mCbStub); 42501fe661ae5da3739215d93922412df4b24c859a2RoboErik mCbRegistered = true; 42601fe661ae5da3739215d93922412df4b24c859a2RoboErik } catch (RemoteException e) { 427d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik Log.e(TAG, "Dead object in registerCallback", e); 42801fe661ae5da3739215d93922412df4b24c859a2RoboErik } 42901fe661ae5da3739215d93922412df4b24c859a2RoboErik } 43001fe661ae5da3739215d93922412df4b24c859a2RoboErik } 43101fe661ae5da3739215d93922412df4b24c859a2RoboErik 4328ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik private boolean removeCallbackLocked(Callback cb) { 433d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik boolean success = false; 4348ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik for (int i = mCallbacks.size() - 1; i >= 0; i--) { 4358ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik MessageHandler handler = mCallbacks.get(i); 4368ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (cb == handler.mCallback) { 4378ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik mCallbacks.remove(i); 438d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik success = true; 43901fe661ae5da3739215d93922412df4b24c859a2RoboErik } 44001fe661ae5da3739215d93922412df4b24c859a2RoboErik } 441d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik if (mCbRegistered && mCallbacks.size() == 0) { 442d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik try { 443d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik mSessionBinder.unregisterCallbackListener(mCbStub); 444d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik } catch (RemoteException e) { 445d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik Log.e(TAG, "Dead object in removeCallbackLocked"); 446d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik } 447d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik mCbRegistered = false; 448d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik } 449d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik return success; 45001fe661ae5da3739215d93922412df4b24c859a2RoboErik } 45101fe661ae5da3739215d93922412df4b24c859a2RoboErik 4528ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik private MessageHandler getHandlerForCallbackLocked(Callback cb) { 4538ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (cb == null) { 4548ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik throw new IllegalArgumentException("Callback cannot be null"); 45501fe661ae5da3739215d93922412df4b24c859a2RoboErik } 4568ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik for (int i = mCallbacks.size() - 1; i >= 0; i--) { 4578ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik MessageHandler handler = mCallbacks.get(i); 4588ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (cb == handler.mCallback) { 4598ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik return handler; 4608ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 46101fe661ae5da3739215d93922412df4b24c859a2RoboErik } 4628ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik return null; 46301fe661ae5da3739215d93922412df4b24c859a2RoboErik } 46401fe661ae5da3739215d93922412df4b24c859a2RoboErik 465c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik private final void postMessage(int what, Object obj, Bundle data) { 4668ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik synchronized (mLock) { 4678ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik for (int i = mCallbacks.size() - 1; i >= 0; i--) { 468c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mCallbacks.get(i).post(what, obj, data); 4698ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 47001fe661ae5da3739215d93922412df4b24c859a2RoboErik } 47101fe661ae5da3739215d93922412df4b24c859a2RoboErik } 47201fe661ae5da3739215d93922412df4b24c859a2RoboErik 47301fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 4748ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * Callback for receiving updates on from the session. A Callback can be 4758ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * registered using {@link #addCallback} 47601fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 47701fe661ae5da3739215d93922412df4b24c859a2RoboErik public static abstract class Callback { 47801fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 4798ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * Override to handle custom events sent by the session owner without a 4808ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * specified interface. Controllers should only handle these for 4818ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * sessions they own. 48201fe661ae5da3739215d93922412df4b24c859a2RoboErik * 483bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * @param event The event from the session. 484bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * @param extras Optional parameters for the event, may be null. 48501fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 486bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public void onSessionEvent(@NonNull String event, @Nullable Bundle extras) { 48701fe661ae5da3739215d93922412df4b24c859a2RoboErik } 48801fe661ae5da3739215d93922412df4b24c859a2RoboErik 48901fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 490c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Override to handle changes in playback state. 491c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 492c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @param state The new playback state of the session 493c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 494bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public void onPlaybackStateChanged(@NonNull PlaybackState state) { 495c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 496c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 497c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 498c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Override to handle changes to the current metadata. 499c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 500bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * @param metadata The current metadata for the session or null if none. 501c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @see MediaMetadata 502c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 503bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public void onMetadataChanged(@Nullable MediaMetadata metadata) { 504c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 50519c9518f6a817d53d5234de0020313cab6950b2fRoboErik 50619c9518f6a817d53d5234de0020313cab6950b2fRoboErik /** 507f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * Override to handle changes to tracks in the queue. 508f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * 509f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * @param queue A list of tracks in the current play queue. It should include the currently 510f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * playing track as well as previous and upcoming tracks if applicable. 511f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * @see MediaSession.Track 512f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal */ 513f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public void onQueueChanged(@Nullable List<MediaSession.Track> queue) { 514f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 515f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 516f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal /** 517f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * Override to handle changes to the queue title. 518f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * 519f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * @param title The title that should be displayed along with the play queue such as 520f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * "Now Playing". May be null if there is no such title. 521f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal */ 522f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public void onQueueTitleChanged(@Nullable CharSequence title) { 523f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 524f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 525f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal /** 526f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * Override to handle changes to the {@link MediaSession} extras. 527f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * 528f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * @param extras The extras that can include other information associated with the 529f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * {@link MediaSession}. 530f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal */ 531f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public void onExtrasChanged(@Nullable Bundle extras) { 532f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 533f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 534f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal /** 53519c9518f6a817d53d5234de0020313cab6950b2fRoboErik * Override to handle changes to the volume info. 53619c9518f6a817d53d5234de0020313cab6950b2fRoboErik * 53719c9518f6a817d53d5234de0020313cab6950b2fRoboErik * @param info The current volume info for this session. 53819c9518f6a817d53d5234de0020313cab6950b2fRoboErik */ 53919c9518f6a817d53d5234de0020313cab6950b2fRoboErik public void onVolumeInfoChanged(VolumeInfo info) { 54019c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 541c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 542c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 543c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 544c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Interface for controlling media playback on a session. This allows an app 545c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * to send media transport commands to the session. 546c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 547c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public final class TransportControls { 548c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik private static final String TAG = "TransportController"; 549c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 550c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik private TransportControls() { 551c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 552c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 553c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 554c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Request that the player start its playback at its current position. 555c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 556c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void play() { 557c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 558c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.play(); 559c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 560c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling play.", e); 561c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 562c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 563c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 564c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 565f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * Request that the player start playback for a specific {@link Uri}. 566f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * 567f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * @param uri The uri of the requested media. 568f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * @param extras Optional extras that can include extra information about the media item 569f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * to be played. 570f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal */ 571f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public void playUri(Uri uri, Bundle extras) { 572f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal if (uri == null) { 573f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal throw new IllegalArgumentException("You must specify a non-null Uri for playUri."); 574f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 575f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal try { 576f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal mSessionBinder.playUri(uri, extras); 577f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } catch (RemoteException e) { 578f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal Log.wtf(TAG, "Error calling play(" + uri + ").", e); 579f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 580f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 581f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 582f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal /** 583f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * Request that the player start playback for a specific search query. 584f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * 585f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * @param query The search query. 586f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * @param extras Optional extras that can include extra information about the query. 587f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal */ 588f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public void playFromSearch(String query, Bundle extras) { 589f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal if (TextUtils.isEmpty(query)) { 590f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal throw new IllegalArgumentException( 591f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal "You must specify a non-empty search query for playFromSearch."); 592f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 593f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal try { 594f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal mSessionBinder.playFromSearch(query, extras); 595f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } catch (RemoteException e) { 596f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal Log.wtf(TAG, "Error calling play(" + query + ").", e); 597f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 598f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 599f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 600f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal /** 601f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * Play a track with a specific id in the play queue. 602f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * If you specify an id that is not in the play queue, the behavior is undefined. 603f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal */ 604f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public void skipToTrack(long id) { 605f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal try { 606f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal mSessionBinder.skipToTrack(id); 607f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } catch (RemoteException e) { 608f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal Log.wtf(TAG, "Error calling skipToTrack(" + id + ").", e); 609f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 610f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 611f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 612f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal /** 613c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Request that the player pause its playback and stay at its current 614c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * position. 615c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 616c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void pause() { 617c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 618c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.pause(); 619c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 620c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling pause.", e); 621c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 622c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 623c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 624c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 625c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Request that the player stop its playback; it may clear its state in 626c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * whatever way is appropriate. 627c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 628c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void stop() { 629c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 630c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.stop(); 631c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 632c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling stop.", e); 633c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 634c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 635c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 636c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 637c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Move to a new location in the media stream. 638c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 639c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @param pos Position to move to, in milliseconds. 640c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 641c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void seekTo(long pos) { 642c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 643c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.seekTo(pos); 644c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 645c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling seekTo.", e); 646c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 647c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 648c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 649c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 650c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Start fast forwarding. If playback is already fast forwarding this 651c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * may increase the rate. 652c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 653c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void fastForward() { 654c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 655c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.fastForward(); 656c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 657c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling fastForward.", e); 658c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 659c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 660c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 661c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 662c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Skip to the next item. 663c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 664c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void skipToNext() { 665c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 666c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.next(); 667c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 668c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling next.", e); 669c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 670c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 671c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 672c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 673c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Start rewinding. If playback is already rewinding this may increase 674c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * the rate. 675c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 676c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void rewind() { 677c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 678c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.rewind(); 679c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 680c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling rewind.", e); 681c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 682c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 683c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 684c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 685c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Skip to the previous item. 686c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 687c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void skipToPrevious() { 688c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 689c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.previous(); 690c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 691c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling previous.", e); 692c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 693c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 694c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 695c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 696c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Rate the current content. This will cause the rating to be set for 697c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * the current user. The Rating type must match the type returned by 698c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * {@link #getRatingType()}. 699c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 700c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @param rating The rating to set for the current content 701c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 702c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void setRating(Rating rating) { 703c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 704c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.rate(rating); 705c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 706c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling rate.", e); 707c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 708c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 709f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal 710f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal /** 711f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * Send a custom action back for the {@link MediaSession} to perform. 712f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * 713f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * @param customAction The action to perform. 714f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * @param args Optional arguments to supply to the {@link MediaSession} for this 715f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * custom action. 716f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal */ 717f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal public void sendCustomAction(@NonNull PlaybackState.CustomAction customAction, 718f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal @Nullable Bundle args) { 719f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal if (customAction == null) { 720f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal throw new IllegalArgumentException("CustomAction cannot be null."); 721f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal } 722f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal sendCustomAction(customAction.getAction(), args); 723f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal } 724f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal 725f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal /** 726f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * Send the id and args from a custom action back for the {@link MediaSession} to perform. 727f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * 728f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * @see #sendCustomAction(PlaybackState.CustomAction action, Bundle args) 729f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * @param action The action identifier of the {@link PlaybackState.CustomAction} as 730f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * specified by the {@link MediaSession}. 731f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * @param args Optional arguments to supply to the {@link MediaSession} for this 732f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * custom action. 733f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal */ 734f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal public void sendCustomAction(@NonNull String action, @Nullable Bundle args) { 735f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal if (TextUtils.isEmpty(action)) { 736f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal throw new IllegalArgumentException("CustomAction cannot be null."); 737f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal } 738f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal try { 739f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal mSessionBinder.sendCustomAction(action, args); 740f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal } catch (RemoteException e) { 741f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal Log.d(TAG, "Dead object in sendCustomAction.", e); 742f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal } 743f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal } 7448ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 74501fe661ae5da3739215d93922412df4b24c859a2RoboErik 746ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 747ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Holds information about the way volume is handled for this session. 748ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 749ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik public static final class VolumeInfo { 750ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik private final int mVolumeType; 751ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik private final int mVolumeControl; 752ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik private final int mMaxVolume; 753ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik private final int mCurrentVolume; 7549db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik private final AudioAttributes mAudioAttrs; 755ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 756ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 757ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @hide 758ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 7599db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik public VolumeInfo(int type, AudioAttributes attrs, int control, int max, int current) { 760ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik mVolumeType = type; 7619db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik mAudioAttrs = attrs; 762ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik mVolumeControl = control; 763ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik mMaxVolume = max; 764ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik mCurrentVolume = current; 765ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 766ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 767ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 768ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Get the type of volume handling, either local or remote. One of: 769ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * <ul> 77019c9518f6a817d53d5234de0020313cab6950b2fRoboErik * <li>{@link MediaSession#PLAYBACK_TYPE_LOCAL}</li> 77119c9518f6a817d53d5234de0020313cab6950b2fRoboErik * <li>{@link MediaSession#PLAYBACK_TYPE_REMOTE}</li> 772ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * </ul> 773ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 774ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @return The type of volume handling this session is using. 775ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 776ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik public int getVolumeType() { 777ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return mVolumeType; 778ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 779ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 780ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 7819db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * Get the audio attributes for this session. The attributes will affect 7829db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * volume handling for the session. When the volume type is 7839db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * {@link MediaSession#PLAYBACK_TYPE_REMOTE} these may be ignored by the 7849db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * remote volume handler. 785ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 7869db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * @return The attributes for this session. 787ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 7889db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik public AudioAttributes getAudioAttributes() { 7899db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik return mAudioAttrs; 790ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 791ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 792ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 793ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Get the type of volume control that can be used. One of: 794ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * <ul> 795ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * <li>{@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}</li> 796ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * <li>{@link VolumeProvider#VOLUME_CONTROL_RELATIVE}</li> 797ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * <li>{@link VolumeProvider#VOLUME_CONTROL_FIXED}</li> 798ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * </ul> 799ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 800ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @return The type of volume control that may be used with this 801ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * session. 802ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 803ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik public int getVolumeControl() { 804ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return mVolumeControl; 805ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 806ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 807ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 808ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Get the maximum volume that may be set for this session. 809ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 810ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @return The maximum allowed volume where this session is playing. 811ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 812ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik public int getMaxVolume() { 813ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return mMaxVolume; 814ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 815ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 816ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 817ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Get the current volume for this session. 818ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 819ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @return The current volume where this session is playing. 820ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 821ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik public int getCurrentVolume() { 822ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return mCurrentVolume; 823ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 824ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 825ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 82607c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik private final static class CallbackStub extends ISessionControllerCallback.Stub { 82742ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik private final WeakReference<MediaController> mController; 82801fe661ae5da3739215d93922412df4b24c859a2RoboErik 82942ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik public CallbackStub(MediaController controller) { 83042ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik mController = new WeakReference<MediaController>(controller); 83101fe661ae5da3739215d93922412df4b24c859a2RoboErik } 83201fe661ae5da3739215d93922412df4b24c859a2RoboErik 83301fe661ae5da3739215d93922412df4b24c859a2RoboErik @Override 8348ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik public void onEvent(String event, Bundle extras) { 83542ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik MediaController controller = mController.get(); 8368ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (controller != null) { 837c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik controller.postMessage(MSG_EVENT, event, extras); 83801fe661ae5da3739215d93922412df4b24c859a2RoboErik } 83901fe661ae5da3739215d93922412df4b24c859a2RoboErik } 84001fe661ae5da3739215d93922412df4b24c859a2RoboErik 84101fe661ae5da3739215d93922412df4b24c859a2RoboErik @Override 8428ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik public void onPlaybackStateChanged(PlaybackState state) { 84342ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik MediaController controller = mController.get(); 8448ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (controller != null) { 845c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik controller.postMessage(MSG_UPDATE_PLAYBACK_STATE, state, null); 84601fe661ae5da3739215d93922412df4b24c859a2RoboErik } 84701fe661ae5da3739215d93922412df4b24c859a2RoboErik } 84801fe661ae5da3739215d93922412df4b24c859a2RoboErik 84901fe661ae5da3739215d93922412df4b24c859a2RoboErik @Override 8508ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik public void onMetadataChanged(MediaMetadata metadata) { 85142ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik MediaController controller = mController.get(); 8528ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (controller != null) { 853c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik controller.postMessage(MSG_UPDATE_METADATA, metadata, null); 85401fe661ae5da3739215d93922412df4b24c859a2RoboErik } 85501fe661ae5da3739215d93922412df4b24c859a2RoboErik } 85601fe661ae5da3739215d93922412df4b24c859a2RoboErik 85719c9518f6a817d53d5234de0020313cab6950b2fRoboErik @Override 858f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public void onQueueChanged(ParceledListSlice parceledQueue) { 859f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal List<MediaSession.Track> queue = parceledQueue.getList(); 860f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal MediaController controller = mController.get(); 861f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal if (controller != null) { 862f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal controller.postMessage(MSG_UPDATE_QUEUE, queue, null); 863f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 864f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 865f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 866f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal @Override 867f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public void onQueueTitleChanged(CharSequence title) { 868f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal MediaController controller = mController.get(); 869f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal if (controller != null) { 870f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal controller.postMessage(MSG_UPDATE_QUEUE_TITLE, title, null); 871f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 872f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 873f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 874f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal @Override 875f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public void onExtrasChanged(Bundle extras) { 876f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal MediaController controller = mController.get(); 877f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal if (controller != null) { 878f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal controller.postMessage(MSG_UPDATE_EXTRAS, extras, null); 879f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 880f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 881f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 882f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal @Override 88319c9518f6a817d53d5234de0020313cab6950b2fRoboErik public void onVolumeInfoChanged(ParcelableVolumeInfo pvi) { 88419c9518f6a817d53d5234de0020313cab6950b2fRoboErik MediaController controller = mController.get(); 88519c9518f6a817d53d5234de0020313cab6950b2fRoboErik if (controller != null) { 8869db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik VolumeInfo info = new VolumeInfo(pvi.volumeType, pvi.audioAttrs, pvi.controlType, 88719c9518f6a817d53d5234de0020313cab6950b2fRoboErik pvi.maxVolume, pvi.currentVolume); 88819c9518f6a817d53d5234de0020313cab6950b2fRoboErik controller.postMessage(MSG_UPDATE_VOLUME, info, null); 88919c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 89019c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 89119c9518f6a817d53d5234de0020313cab6950b2fRoboErik 89201fe661ae5da3739215d93922412df4b24c859a2RoboErik } 89301fe661ae5da3739215d93922412df4b24c859a2RoboErik 89401fe661ae5da3739215d93922412df4b24c859a2RoboErik private final static class MessageHandler extends Handler { 89542ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik private final MediaController.Callback mCallback; 89601fe661ae5da3739215d93922412df4b24c859a2RoboErik 89742ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik public MessageHandler(Looper looper, MediaController.Callback cb) { 8988ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik super(looper, null, true); 8998ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik mCallback = cb; 90001fe661ae5da3739215d93922412df4b24c859a2RoboErik } 90101fe661ae5da3739215d93922412df4b24c859a2RoboErik 90201fe661ae5da3739215d93922412df4b24c859a2RoboErik @Override 90301fe661ae5da3739215d93922412df4b24c859a2RoboErik public void handleMessage(Message msg) { 90401fe661ae5da3739215d93922412df4b24c859a2RoboErik switch (msg.what) { 9058ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik case MSG_EVENT: 90679fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik mCallback.onSessionEvent((String) msg.obj, msg.getData()); 90701fe661ae5da3739215d93922412df4b24c859a2RoboErik break; 908c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik case MSG_UPDATE_PLAYBACK_STATE: 909c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mCallback.onPlaybackStateChanged((PlaybackState) msg.obj); 910c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik break; 911c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik case MSG_UPDATE_METADATA: 912c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mCallback.onMetadataChanged((MediaMetadata) msg.obj); 913c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik break; 914f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal case MSG_UPDATE_QUEUE: 915f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal mCallback.onQueueChanged((List<MediaSession.Track>) msg.obj); 916f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal break; 917f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal case MSG_UPDATE_QUEUE_TITLE: 918f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal mCallback.onQueueTitleChanged((CharSequence) msg.obj); 919f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal break; 920f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal case MSG_UPDATE_EXTRAS: 921f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal mCallback.onExtrasChanged((Bundle) msg.obj); 922f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal break; 92319c9518f6a817d53d5234de0020313cab6950b2fRoboErik case MSG_UPDATE_VOLUME: 92419c9518f6a817d53d5234de0020313cab6950b2fRoboErik mCallback.onVolumeInfoChanged((VolumeInfo) msg.obj); 92519c9518f6a817d53d5234de0020313cab6950b2fRoboErik break; 92601fe661ae5da3739215d93922412df4b24c859a2RoboErik } 92701fe661ae5da3739215d93922412df4b24c859a2RoboErik } 9288ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik 9298ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik public void post(int what, Object obj, Bundle data) { 9308ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik obtainMessage(what, obj).sendToTarget(); 9318ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 93201fe661ae5da3739215d93922412df4b24c859a2RoboErik } 93301fe661ae5da3739215d93922412df4b24c859a2RoboErik 93401fe661ae5da3739215d93922412df4b24c859a2RoboErik} 935