MediaController.java revision f364f944962c4ec66f5e5b33dafe8480f38f6db6
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; 21f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Pealimport android.content.pm.ParceledListSlice; 229db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErikimport android.media.AudioAttributes; 2319c9518f6a817d53d5234de0020313cab6950b2fRoboErikimport android.media.AudioManager; 2442ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErikimport android.media.MediaMetadata; 25c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErikimport android.media.Rating; 26ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErikimport android.media.VolumeProvider; 271a937b04e63539cb1fab1bde601031d415c7156fJeff Brownimport android.media.routing.MediaRouter; 28f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Pealimport android.net.Uri; 2901fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.os.Bundle; 3001fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.os.Handler; 3101fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.os.Looper; 3201fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.os.Message; 3301fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.os.RemoteException; 348ae0f34db936a649ddaf9cdd086c224f6514efebRoboErikimport android.os.ResultReceiver; 3501fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.text.TextUtils; 3601fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.util.Log; 3701fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.view.KeyEvent; 3801fe661ae5da3739215d93922412df4b24c859a2RoboErik 398ae0f34db936a649ddaf9cdd086c224f6514efebRoboErikimport java.lang.ref.WeakReference; 4001fe661ae5da3739215d93922412df4b24c859a2RoboErikimport java.util.ArrayList; 41f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Pealimport java.util.List; 4201fe661ae5da3739215d93922412df4b24c859a2RoboErik 4301fe661ae5da3739215d93922412df4b24c859a2RoboErik/** 4401fe661ae5da3739215d93922412df4b24c859a2RoboErik * Allows an app to interact with an ongoing media session. Media buttons and 4501fe661ae5da3739215d93922412df4b24c859a2RoboErik * other commands can be sent to the session. A callback may be registered to 4601fe661ae5da3739215d93922412df4b24c859a2RoboErik * receive updates from the session, such as metadata and play state changes. 4701fe661ae5da3739215d93922412df4b24c859a2RoboErik * <p> 4842ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik * A MediaController can be created through {@link MediaSessionManager} if you 4901fe661ae5da3739215d93922412df4b24c859a2RoboErik * hold the "android.permission.MEDIA_CONTENT_CONTROL" permission or directly if 50dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown * you have a {@link MediaSession.Token} from the session owner. 5101fe661ae5da3739215d93922412df4b24c859a2RoboErik * <p> 5201fe661ae5da3739215d93922412df4b24c859a2RoboErik * MediaController objects are thread-safe. 5301fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 5442ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErikpublic final class MediaController { 55bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown private static final String TAG = "MediaController"; 5601fe661ae5da3739215d93922412df4b24c859a2RoboErik 578ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik private static final int MSG_EVENT = 1; 58c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik private static final int MSG_UPDATE_PLAYBACK_STATE = 2; 59c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik private static final int MSG_UPDATE_METADATA = 3; 6001a500ed1c6ae3fff66678144ae637aa8cad0eccJeff Brown private static final int MSG_UPDATE_VOLUME = 4; 61f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal private static final int MSG_UPDATE_QUEUE = 5; 62f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal private static final int MSG_UPDATE_QUEUE_TITLE = 6; 63f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal private static final int MSG_UPDATE_EXTRAS = 7; 6401fe661ae5da3739215d93922412df4b24c859a2RoboErik 6507c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik private final ISessionController mSessionBinder; 6601fe661ae5da3739215d93922412df4b24c859a2RoboErik 678ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik private final CallbackStub mCbStub = new CallbackStub(this); 688ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik private final ArrayList<MessageHandler> mCallbacks = new ArrayList<MessageHandler>(); 6901fe661ae5da3739215d93922412df4b24c859a2RoboErik private final Object mLock = new Object(); 7001fe661ae5da3739215d93922412df4b24c859a2RoboErik 7101fe661ae5da3739215d93922412df4b24c859a2RoboErik private boolean mCbRegistered = false; 7273e23e229dd1a2d25687b1c6a63c708665378e41RoboErik private MediaSessionInfo mInfo; 7301fe661ae5da3739215d93922412df4b24c859a2RoboErik 741a937b04e63539cb1fab1bde601031d415c7156fJeff Brown private final TransportControls mTransportControls; 758ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik 7601fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 778b4bffcac996b4083e720310a09d315ca1c4a000RoboErik * Call for creating a MediaController directly from a binder. Should only 788b4bffcac996b4083e720310a09d315ca1c4a000RoboErik * be used by framework code. 798b4bffcac996b4083e720310a09d315ca1c4a000RoboErik * 808ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * @hide 8101fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 828b4bffcac996b4083e720310a09d315ca1c4a000RoboErik public MediaController(ISessionController sessionBinder) { 838b4bffcac996b4083e720310a09d315ca1c4a000RoboErik if (sessionBinder == null) { 848b4bffcac996b4083e720310a09d315ca1c4a000RoboErik throw new IllegalArgumentException("Session token cannot be null"); 858b4bffcac996b4083e720310a09d315ca1c4a000RoboErik } 868b4bffcac996b4083e720310a09d315ca1c4a000RoboErik mSessionBinder = sessionBinder; 878b4bffcac996b4083e720310a09d315ca1c4a000RoboErik mTransportControls = new TransportControls(); 8801fe661ae5da3739215d93922412df4b24c859a2RoboErik } 8901fe661ae5da3739215d93922412df4b24c859a2RoboErik 9001fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 918b4bffcac996b4083e720310a09d315ca1c4a000RoboErik * Create a new MediaController from a session's token. 928ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * 938b4bffcac996b4083e720310a09d315ca1c4a000RoboErik * @param token The token for the session. 9401fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 958b4bffcac996b4083e720310a09d315ca1c4a000RoboErik public MediaController(@NonNull MediaSession.Token token) { 968b4bffcac996b4083e720310a09d315ca1c4a000RoboErik this(token.getBinder()); 9701fe661ae5da3739215d93922412df4b24c859a2RoboErik } 9801fe661ae5da3739215d93922412df4b24c859a2RoboErik 9901fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 1001a937b04e63539cb1fab1bde601031d415c7156fJeff Brown * Get a {@link TransportControls} instance to send transport actions to 1011a937b04e63539cb1fab1bde601031d415c7156fJeff Brown * the associated session. 10201fe661ae5da3739215d93922412df4b24c859a2RoboErik * 1031a937b04e63539cb1fab1bde601031d415c7156fJeff Brown * @return A transport controls instance. 10401fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 105bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public @NonNull TransportControls getTransportControls() { 1061a937b04e63539cb1fab1bde601031d415c7156fJeff Brown return mTransportControls; 1071a937b04e63539cb1fab1bde601031d415c7156fJeff Brown } 1081a937b04e63539cb1fab1bde601031d415c7156fJeff Brown 1091a937b04e63539cb1fab1bde601031d415c7156fJeff Brown /** 1101a937b04e63539cb1fab1bde601031d415c7156fJeff Brown * Creates a media router delegate through which the destination of the media 1111a937b04e63539cb1fab1bde601031d415c7156fJeff Brown * router may be observed and controlled. 1121a937b04e63539cb1fab1bde601031d415c7156fJeff Brown * 1131a937b04e63539cb1fab1bde601031d415c7156fJeff Brown * @return The media router delegate, or null if the media session does 1141a937b04e63539cb1fab1bde601031d415c7156fJeff Brown * not support media routing. 1151a937b04e63539cb1fab1bde601031d415c7156fJeff Brown */ 1161a937b04e63539cb1fab1bde601031d415c7156fJeff Brown public @Nullable MediaRouter.Delegate createMediaRouterDelegate() { 1171a937b04e63539cb1fab1bde601031d415c7156fJeff Brown return new MediaRouter.Delegate(); 11801fe661ae5da3739215d93922412df4b24c859a2RoboErik } 11901fe661ae5da3739215d93922412df4b24c859a2RoboErik 12001fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 12179fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik * Send the specified media button event to the session. Only media keys can 12279fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik * be sent by this method, other keys will be ignored. 12301fe661ae5da3739215d93922412df4b24c859a2RoboErik * 12479fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik * @param keyEvent The media button event to dispatch. 12579fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik * @return true if the event was sent to the session, false otherwise. 12601fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 127bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public boolean dispatchMediaButtonEvent(@NonNull KeyEvent keyEvent) { 12879fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik if (keyEvent == null) { 12979fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik throw new IllegalArgumentException("KeyEvent may not be null"); 13079fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik } 13179fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik if (!KeyEvent.isMediaKey(keyEvent.getKeyCode())) { 13279fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik return false; 13301fe661ae5da3739215d93922412df4b24c859a2RoboErik } 13401fe661ae5da3739215d93922412df4b24c859a2RoboErik try { 13579fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik return mSessionBinder.sendMediaButton(keyEvent); 13601fe661ae5da3739215d93922412df4b24c859a2RoboErik } catch (RemoteException e) { 137c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik // System is dead. =( 13801fe661ae5da3739215d93922412df4b24c859a2RoboErik } 13979fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik return false; 14001fe661ae5da3739215d93922412df4b24c859a2RoboErik } 14101fe661ae5da3739215d93922412df4b24c859a2RoboErik 14201fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 143c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Get the current playback state for this session. 144c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 145c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @return The current PlaybackState or null 146c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 147bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public @Nullable PlaybackState getPlaybackState() { 148c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 149c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return mSessionBinder.getPlaybackState(); 150c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 151c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling getPlaybackState.", e); 152c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return null; 153c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 154c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 155c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 156c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 157c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Get the current metadata for this session. 158c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 159c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @return The current MediaMetadata or null. 160c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 161bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public @Nullable MediaMetadata getMetadata() { 162c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 163c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return mSessionBinder.getMetadata(); 164c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 165c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling getMetadata.", e); 166c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return null; 167c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 168c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 169c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 170c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 171f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * Get the current play queue for this session. 172f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * 173f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * @return The current play queue or null. 174f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal */ 175f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public @Nullable List<MediaSession.Track> getQueue() { 176f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal try { 177f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal ParceledListSlice queue = mSessionBinder.getQueue(); 178f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal if (queue != null) { 179f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal return queue.getList(); 180f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 181f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } catch (RemoteException e) { 182f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal Log.wtf(TAG, "Error calling getQueue.", e); 183f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 184f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal return null; 185f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 186f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 187f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal /** 188c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Get the rating type supported by the session. One of: 189c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <ul> 190c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_NONE}</li> 191c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_HEART}</li> 192c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_THUMB_UP_DOWN}</li> 193c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_3_STARS}</li> 194c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_4_STARS}</li> 195c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_5_STARS}</li> 196c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_PERCENTAGE}</li> 197c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * </ul> 198c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 199c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @return The supported rating type 200c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 201c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public int getRatingType() { 202c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 203c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return mSessionBinder.getRatingType(); 204c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 205c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling getRatingType.", e); 206c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return Rating.RATING_NONE; 207c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 208c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 209c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 210c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 21173e23e229dd1a2d25687b1c6a63c708665378e41RoboErik * Get the flags for this session. 21273e23e229dd1a2d25687b1c6a63c708665378e41RoboErik * 21373e23e229dd1a2d25687b1c6a63c708665378e41RoboErik * @return The current set of flags for the session. 21473e23e229dd1a2d25687b1c6a63c708665378e41RoboErik * @hide 21573e23e229dd1a2d25687b1c6a63c708665378e41RoboErik */ 21673e23e229dd1a2d25687b1c6a63c708665378e41RoboErik public long getFlags() { 21773e23e229dd1a2d25687b1c6a63c708665378e41RoboErik try { 21873e23e229dd1a2d25687b1c6a63c708665378e41RoboErik return mSessionBinder.getFlags(); 21973e23e229dd1a2d25687b1c6a63c708665378e41RoboErik } catch (RemoteException e) { 22073e23e229dd1a2d25687b1c6a63c708665378e41RoboErik Log.wtf(TAG, "Error calling getFlags.", e); 22173e23e229dd1a2d25687b1c6a63c708665378e41RoboErik } 22273e23e229dd1a2d25687b1c6a63c708665378e41RoboErik return 0; 22373e23e229dd1a2d25687b1c6a63c708665378e41RoboErik } 22473e23e229dd1a2d25687b1c6a63c708665378e41RoboErik 22573e23e229dd1a2d25687b1c6a63c708665378e41RoboErik /** 226ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Get the current volume info for this session. 227ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 228ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @return The current volume info or null. 229ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 230bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public @Nullable VolumeInfo getVolumeInfo() { 231ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik try { 232ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik ParcelableVolumeInfo result = mSessionBinder.getVolumeAttributes(); 2339db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik return new VolumeInfo(result.volumeType, result.audioAttrs, result.controlType, 234ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik result.maxVolume, result.currentVolume); 235ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 236ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } catch (RemoteException e) { 237ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik Log.wtf(TAG, "Error calling getVolumeInfo.", e); 238ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 239ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return null; 240ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 241ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 242ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 2439db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * Set the volume of the output this session is playing on. The command will 2449db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * be ignored if it does not support 24519c9518f6a817d53d5234de0020313cab6950b2fRoboErik * {@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}. The flags in 24619c9518f6a817d53d5234de0020313cab6950b2fRoboErik * {@link AudioManager} may be used to affect the handling. 24719c9518f6a817d53d5234de0020313cab6950b2fRoboErik * 24819c9518f6a817d53d5234de0020313cab6950b2fRoboErik * @see #getVolumeInfo() 24919c9518f6a817d53d5234de0020313cab6950b2fRoboErik * @param value The value to set it to, between 0 and the reported max. 25019c9518f6a817d53d5234de0020313cab6950b2fRoboErik * @param flags Any flags to pass with the command. 25119c9518f6a817d53d5234de0020313cab6950b2fRoboErik */ 25219c9518f6a817d53d5234de0020313cab6950b2fRoboErik public void setVolumeTo(int value, int flags) { 25319c9518f6a817d53d5234de0020313cab6950b2fRoboErik try { 25419c9518f6a817d53d5234de0020313cab6950b2fRoboErik mSessionBinder.setVolumeTo(value, flags); 25519c9518f6a817d53d5234de0020313cab6950b2fRoboErik } catch (RemoteException e) { 25619c9518f6a817d53d5234de0020313cab6950b2fRoboErik Log.wtf(TAG, "Error calling setVolumeTo.", e); 25719c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 25819c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 25919c9518f6a817d53d5234de0020313cab6950b2fRoboErik 26019c9518f6a817d53d5234de0020313cab6950b2fRoboErik /** 2619db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * Adjust the volume of the output this session is playing on. The direction 2629db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * must be one of {@link AudioManager#ADJUST_LOWER}, 2631ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik * {@link AudioManager#ADJUST_RAISE}, or {@link AudioManager#ADJUST_SAME}. 2641ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik * The command will be ignored if the session does not support 2651ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik * {@link VolumeProvider#VOLUME_CONTROL_RELATIVE} or 26619c9518f6a817d53d5234de0020313cab6950b2fRoboErik * {@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}. The flags in 26719c9518f6a817d53d5234de0020313cab6950b2fRoboErik * {@link AudioManager} may be used to affect the handling. 26819c9518f6a817d53d5234de0020313cab6950b2fRoboErik * 26919c9518f6a817d53d5234de0020313cab6950b2fRoboErik * @see #getVolumeInfo() 2701ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik * @param direction The direction to adjust the volume in. 27119c9518f6a817d53d5234de0020313cab6950b2fRoboErik * @param flags Any flags to pass with the command. 27219c9518f6a817d53d5234de0020313cab6950b2fRoboErik */ 2731ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik public void adjustVolume(int direction, int flags) { 27419c9518f6a817d53d5234de0020313cab6950b2fRoboErik try { 2751ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik mSessionBinder.adjustVolume(direction, flags); 27619c9518f6a817d53d5234de0020313cab6950b2fRoboErik } catch (RemoteException e) { 27719c9518f6a817d53d5234de0020313cab6950b2fRoboErik Log.wtf(TAG, "Error calling adjustVolumeBy.", e); 27819c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 27919c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 28019c9518f6a817d53d5234de0020313cab6950b2fRoboErik 28119c9518f6a817d53d5234de0020313cab6950b2fRoboErik /** 28201fe661ae5da3739215d93922412df4b24c859a2RoboErik * Adds a callback to receive updates from the Session. Updates will be 28301fe661ae5da3739215d93922412df4b24c859a2RoboErik * posted on the caller's thread. 28401fe661ae5da3739215d93922412df4b24c859a2RoboErik * 285bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * @param callback The callback object, must not be null. 28601fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 287bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public void addCallback(@NonNull Callback callback) { 288bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown addCallback(callback, null); 28901fe661ae5da3739215d93922412df4b24c859a2RoboErik } 29001fe661ae5da3739215d93922412df4b24c859a2RoboErik 29101fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 29201fe661ae5da3739215d93922412df4b24c859a2RoboErik * Adds a callback to receive updates from the session. Updates will be 2938ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * posted on the specified handler's thread. 29401fe661ae5da3739215d93922412df4b24c859a2RoboErik * 295bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * @param callback The callback object, must not be null. 2968ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * @param handler The handler to post updates on. If null the callers thread 297bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * will be used. 29801fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 299bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public void addCallback(@NonNull Callback callback, @Nullable Handler handler) { 300bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown if (callback == null) { 301bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown throw new IllegalArgumentException("callback must not be null"); 302bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown } 30301fe661ae5da3739215d93922412df4b24c859a2RoboErik if (handler == null) { 30401fe661ae5da3739215d93922412df4b24c859a2RoboErik handler = new Handler(); 30501fe661ae5da3739215d93922412df4b24c859a2RoboErik } 30601fe661ae5da3739215d93922412df4b24c859a2RoboErik synchronized (mLock) { 307bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown addCallbackLocked(callback, handler); 30801fe661ae5da3739215d93922412df4b24c859a2RoboErik } 30901fe661ae5da3739215d93922412df4b24c859a2RoboErik } 31001fe661ae5da3739215d93922412df4b24c859a2RoboErik 31101fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 31201fe661ae5da3739215d93922412df4b24c859a2RoboErik * Stop receiving updates on the specified callback. If an update has 31301fe661ae5da3739215d93922412df4b24c859a2RoboErik * already been posted you may still receive it after calling this method. 31401fe661ae5da3739215d93922412df4b24c859a2RoboErik * 315bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * @param callback The callback to remove. 31601fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 317bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public void removeCallback(@NonNull Callback callback) { 318bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown if (callback == null) { 319bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown throw new IllegalArgumentException("callback must not be null"); 320bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown } 32101fe661ae5da3739215d93922412df4b24c859a2RoboErik synchronized (mLock) { 322bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown removeCallbackLocked(callback); 32301fe661ae5da3739215d93922412df4b24c859a2RoboErik } 32401fe661ae5da3739215d93922412df4b24c859a2RoboErik } 32501fe661ae5da3739215d93922412df4b24c859a2RoboErik 3268ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik /** 3278ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * Sends a generic command to the session. It is up to the session creator 3288ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * to decide what commands and parameters they will support. As such, 3298ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * commands should only be sent to sessions that the controller owns. 3308ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * 3318ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * @param command The command to send 332f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * @param args Any parameters to include with the command 3338ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * @param cb The callback to receive the result on 3348ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik */ 335f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal public void sendCommand(@NonNull String command, @Nullable Bundle args, 336bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown @Nullable ResultReceiver cb) { 3378ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (TextUtils.isEmpty(command)) { 3388ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik throw new IllegalArgumentException("command cannot be null or empty"); 3398ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 3408ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik try { 341f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal mSessionBinder.sendCommand(command, args, cb); 3428ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } catch (RemoteException e) { 3438ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik Log.d(TAG, "Dead object in sendCommand.", e); 3448ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 3458ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 3468ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik 34707c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik /** 348fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik * Get the info for the session this controller is connected to. 349fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik * 350fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik * @return The session info for the connected session. 351fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik * @hide 352fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik */ 353fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik public MediaSessionInfo getSessionInfo() { 35473e23e229dd1a2d25687b1c6a63c708665378e41RoboErik if (mInfo == null) { 35573e23e229dd1a2d25687b1c6a63c708665378e41RoboErik try { 35673e23e229dd1a2d25687b1c6a63c708665378e41RoboErik mInfo = mSessionBinder.getSessionInfo(); 35773e23e229dd1a2d25687b1c6a63c708665378e41RoboErik } catch (RemoteException e) { 35873e23e229dd1a2d25687b1c6a63c708665378e41RoboErik Log.e(TAG, "Error in getSessionInfo.", e); 35973e23e229dd1a2d25687b1c6a63c708665378e41RoboErik } 360fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik } 36173e23e229dd1a2d25687b1c6a63c708665378e41RoboErik return mInfo; 362fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik } 363fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik 36401fe661ae5da3739215d93922412df4b24c859a2RoboErik /* 36501fe661ae5da3739215d93922412df4b24c859a2RoboErik * @hide 36601fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 36707c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik ISessionController getSessionBinder() { 36801fe661ae5da3739215d93922412df4b24c859a2RoboErik return mSessionBinder; 36901fe661ae5da3739215d93922412df4b24c859a2RoboErik } 37001fe661ae5da3739215d93922412df4b24c859a2RoboErik 37101fe661ae5da3739215d93922412df4b24c859a2RoboErik private void addCallbackLocked(Callback cb, Handler handler) { 3728ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (getHandlerForCallbackLocked(cb) != null) { 37301fe661ae5da3739215d93922412df4b24c859a2RoboErik Log.w(TAG, "Callback is already added, ignoring"); 37401fe661ae5da3739215d93922412df4b24c859a2RoboErik return; 37501fe661ae5da3739215d93922412df4b24c859a2RoboErik } 3768ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik MessageHandler holder = new MessageHandler(handler.getLooper(), cb); 3778ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik mCallbacks.add(holder); 37801fe661ae5da3739215d93922412df4b24c859a2RoboErik 37901fe661ae5da3739215d93922412df4b24c859a2RoboErik if (!mCbRegistered) { 38001fe661ae5da3739215d93922412df4b24c859a2RoboErik try { 38101fe661ae5da3739215d93922412df4b24c859a2RoboErik mSessionBinder.registerCallbackListener(mCbStub); 38201fe661ae5da3739215d93922412df4b24c859a2RoboErik mCbRegistered = true; 38301fe661ae5da3739215d93922412df4b24c859a2RoboErik } catch (RemoteException e) { 384d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik Log.e(TAG, "Dead object in registerCallback", e); 38501fe661ae5da3739215d93922412df4b24c859a2RoboErik } 38601fe661ae5da3739215d93922412df4b24c859a2RoboErik } 38701fe661ae5da3739215d93922412df4b24c859a2RoboErik } 38801fe661ae5da3739215d93922412df4b24c859a2RoboErik 3898ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik private boolean removeCallbackLocked(Callback cb) { 390d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik boolean success = false; 3918ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik for (int i = mCallbacks.size() - 1; i >= 0; i--) { 3928ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik MessageHandler handler = mCallbacks.get(i); 3938ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (cb == handler.mCallback) { 3948ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik mCallbacks.remove(i); 395d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik success = true; 39601fe661ae5da3739215d93922412df4b24c859a2RoboErik } 39701fe661ae5da3739215d93922412df4b24c859a2RoboErik } 398d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik if (mCbRegistered && mCallbacks.size() == 0) { 399d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik try { 400d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik mSessionBinder.unregisterCallbackListener(mCbStub); 401d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik } catch (RemoteException e) { 402d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik Log.e(TAG, "Dead object in removeCallbackLocked"); 403d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik } 404d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik mCbRegistered = false; 405d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik } 406d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik return success; 40701fe661ae5da3739215d93922412df4b24c859a2RoboErik } 40801fe661ae5da3739215d93922412df4b24c859a2RoboErik 4098ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik private MessageHandler getHandlerForCallbackLocked(Callback cb) { 4108ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (cb == null) { 4118ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik throw new IllegalArgumentException("Callback cannot be null"); 41201fe661ae5da3739215d93922412df4b24c859a2RoboErik } 4138ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik for (int i = mCallbacks.size() - 1; i >= 0; i--) { 4148ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik MessageHandler handler = mCallbacks.get(i); 4158ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (cb == handler.mCallback) { 4168ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik return handler; 4178ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 41801fe661ae5da3739215d93922412df4b24c859a2RoboErik } 4198ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik return null; 42001fe661ae5da3739215d93922412df4b24c859a2RoboErik } 42101fe661ae5da3739215d93922412df4b24c859a2RoboErik 422c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik private final void postMessage(int what, Object obj, Bundle data) { 4238ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik synchronized (mLock) { 4248ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik for (int i = mCallbacks.size() - 1; i >= 0; i--) { 425c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mCallbacks.get(i).post(what, obj, data); 4268ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 42701fe661ae5da3739215d93922412df4b24c859a2RoboErik } 42801fe661ae5da3739215d93922412df4b24c859a2RoboErik } 42901fe661ae5da3739215d93922412df4b24c859a2RoboErik 43001fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 4318ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * Callback for receiving updates on from the session. A Callback can be 4328ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * registered using {@link #addCallback} 43301fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 43401fe661ae5da3739215d93922412df4b24c859a2RoboErik public static abstract class Callback { 43501fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 4368ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * Override to handle custom events sent by the session owner without a 4378ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * specified interface. Controllers should only handle these for 4388ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * sessions they own. 43901fe661ae5da3739215d93922412df4b24c859a2RoboErik * 440bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * @param event The event from the session. 441bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * @param extras Optional parameters for the event, may be null. 44201fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 443bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public void onSessionEvent(@NonNull String event, @Nullable Bundle extras) { 44401fe661ae5da3739215d93922412df4b24c859a2RoboErik } 44501fe661ae5da3739215d93922412df4b24c859a2RoboErik 44601fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 447c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Override to handle changes in playback state. 448c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 449c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @param state The new playback state of the session 450c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 451bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public void onPlaybackStateChanged(@NonNull PlaybackState state) { 452c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 453c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 454c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 455c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Override to handle changes to the current metadata. 456c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 457bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * @param metadata The current metadata for the session or null if none. 458c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @see MediaMetadata 459c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 460bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public void onMetadataChanged(@Nullable MediaMetadata metadata) { 461c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 46219c9518f6a817d53d5234de0020313cab6950b2fRoboErik 46319c9518f6a817d53d5234de0020313cab6950b2fRoboErik /** 464f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * Override to handle changes to tracks in the queue. 465f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * 466f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * @param queue A list of tracks in the current play queue. It should include the currently 467f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * playing track as well as previous and upcoming tracks if applicable. 468f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * @see MediaSession.Track 469f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal */ 470f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public void onQueueChanged(@Nullable List<MediaSession.Track> queue) { 471f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 472f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 473f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal /** 474f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * Override to handle changes to the queue title. 475f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * 476f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * @param title The title that should be displayed along with the play queue such as 477f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * "Now Playing". May be null if there is no such title. 478f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal */ 479f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public void onQueueTitleChanged(@Nullable CharSequence title) { 480f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 481f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 482f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal /** 483f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * Override to handle changes to the {@link MediaSession} extras. 484f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * 485f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * @param extras The extras that can include other information associated with the 486f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * {@link MediaSession}. 487f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal */ 488f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public void onExtrasChanged(@Nullable Bundle extras) { 489f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 490f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 491f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal /** 49219c9518f6a817d53d5234de0020313cab6950b2fRoboErik * Override to handle changes to the volume info. 49319c9518f6a817d53d5234de0020313cab6950b2fRoboErik * 49419c9518f6a817d53d5234de0020313cab6950b2fRoboErik * @param info The current volume info for this session. 49519c9518f6a817d53d5234de0020313cab6950b2fRoboErik */ 49619c9518f6a817d53d5234de0020313cab6950b2fRoboErik public void onVolumeInfoChanged(VolumeInfo info) { 49719c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 498c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 499c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 500c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 501c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Interface for controlling media playback on a session. This allows an app 502c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * to send media transport commands to the session. 503c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 504c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public final class TransportControls { 505c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik private static final String TAG = "TransportController"; 506c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 507c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik private TransportControls() { 508c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 509c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 510c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 511c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Request that the player start its playback at its current position. 512c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 513c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void play() { 514c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 515c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.play(); 516c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 517c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling play.", e); 518c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 519c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 520c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 521c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 522f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * Request that the player start playback for a specific {@link Uri}. 523f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * 524f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * @param uri The uri of the requested media. 525f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * @param extras Optional extras that can include extra information about the media item 526f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * to be played. 527f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal */ 528f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public void playUri(Uri uri, Bundle extras) { 529f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal if (uri == null) { 530f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal throw new IllegalArgumentException("You must specify a non-null Uri for playUri."); 531f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 532f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal try { 533f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal mSessionBinder.playUri(uri, extras); 534f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } catch (RemoteException e) { 535f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal Log.wtf(TAG, "Error calling play(" + uri + ").", e); 536f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 537f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 538f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 539f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal /** 540f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * Request that the player start playback for a specific search query. 541f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * 542f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * @param query The search query. 543f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * @param extras Optional extras that can include extra information about the query. 544f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal */ 545f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public void playFromSearch(String query, Bundle extras) { 546f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal if (TextUtils.isEmpty(query)) { 547f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal throw new IllegalArgumentException( 548f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal "You must specify a non-empty search query for playFromSearch."); 549f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 550f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal try { 551f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal mSessionBinder.playFromSearch(query, extras); 552f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } catch (RemoteException e) { 553f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal Log.wtf(TAG, "Error calling play(" + query + ").", e); 554f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 555f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 556f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 557f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal /** 558f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * Play a track with a specific id in the play queue. 559f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * If you specify an id that is not in the play queue, the behavior is undefined. 560f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal */ 561f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public void skipToTrack(long id) { 562f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal try { 563f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal mSessionBinder.skipToTrack(id); 564f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } catch (RemoteException e) { 565f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal Log.wtf(TAG, "Error calling skipToTrack(" + id + ").", e); 566f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 567f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 568f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 569f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal /** 570c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Request that the player pause its playback and stay at its current 571c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * position. 572c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 573c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void pause() { 574c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 575c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.pause(); 576c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 577c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling pause.", e); 578c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 579c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 580c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 581c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 582c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Request that the player stop its playback; it may clear its state in 583c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * whatever way is appropriate. 584c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 585c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void stop() { 586c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 587c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.stop(); 588c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 589c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling stop.", e); 590c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 591c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 592c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 593c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 594c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Move to a new location in the media stream. 595c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 596c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @param pos Position to move to, in milliseconds. 597c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 598c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void seekTo(long pos) { 599c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 600c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.seekTo(pos); 601c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 602c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling seekTo.", e); 603c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 604c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 605c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 606c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 607c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Start fast forwarding. If playback is already fast forwarding this 608c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * may increase the rate. 609c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 610c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void fastForward() { 611c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 612c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.fastForward(); 613c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 614c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling fastForward.", e); 615c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 616c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 617c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 618c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 619c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Skip to the next item. 620c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 621c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void skipToNext() { 622c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 623c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.next(); 624c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 625c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling next.", e); 626c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 627c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 628c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 629c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 630c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Start rewinding. If playback is already rewinding this may increase 631c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * the rate. 632c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 633c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void rewind() { 634c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 635c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.rewind(); 636c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 637c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling rewind.", e); 638c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 639c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 640c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 641c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 642c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Skip to the previous item. 643c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 644c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void skipToPrevious() { 645c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 646c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.previous(); 647c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 648c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling previous.", e); 649c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 650c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 651c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 652c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 653c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Rate the current content. This will cause the rating to be set for 654c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * the current user. The Rating type must match the type returned by 655c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * {@link #getRatingType()}. 656c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 657c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @param rating The rating to set for the current content 658c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 659c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void setRating(Rating rating) { 660c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 661c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.rate(rating); 662c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 663c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling rate.", e); 664c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 665c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 666f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal 667f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal /** 668f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * Send a custom action back for the {@link MediaSession} to perform. 669f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * 670f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * @param customAction The action to perform. 671f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * @param args Optional arguments to supply to the {@link MediaSession} for this 672f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * custom action. 673f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal */ 674f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal public void sendCustomAction(@NonNull PlaybackState.CustomAction customAction, 675f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal @Nullable Bundle args) { 676f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal if (customAction == null) { 677f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal throw new IllegalArgumentException("CustomAction cannot be null."); 678f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal } 679f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal sendCustomAction(customAction.getAction(), args); 680f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal } 681f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal 682f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal /** 683f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * Send the id and args from a custom action back for the {@link MediaSession} to perform. 684f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * 685f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * @see #sendCustomAction(PlaybackState.CustomAction action, Bundle args) 686f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * @param action The action identifier of the {@link PlaybackState.CustomAction} as 687f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * specified by the {@link MediaSession}. 688f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * @param args Optional arguments to supply to the {@link MediaSession} for this 689f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * custom action. 690f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal */ 691f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal public void sendCustomAction(@NonNull String action, @Nullable Bundle args) { 692f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal if (TextUtils.isEmpty(action)) { 693f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal throw new IllegalArgumentException("CustomAction cannot be null."); 694f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal } 695f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal try { 696f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal mSessionBinder.sendCustomAction(action, args); 697f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal } catch (RemoteException e) { 698f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal Log.d(TAG, "Dead object in sendCustomAction.", e); 699f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal } 700f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal } 7018ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 70201fe661ae5da3739215d93922412df4b24c859a2RoboErik 703ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 704ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Holds information about the way volume is handled for this session. 705ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 706ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik public static final class VolumeInfo { 707ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik private final int mVolumeType; 708ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik private final int mVolumeControl; 709ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik private final int mMaxVolume; 710ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik private final int mCurrentVolume; 7119db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik private final AudioAttributes mAudioAttrs; 712ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 713ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 714ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @hide 715ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 7169db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik public VolumeInfo(int type, AudioAttributes attrs, int control, int max, int current) { 717ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik mVolumeType = type; 7189db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik mAudioAttrs = attrs; 719ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik mVolumeControl = control; 720ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik mMaxVolume = max; 721ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik mCurrentVolume = current; 722ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 723ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 724ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 725ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Get the type of volume handling, either local or remote. One of: 726ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * <ul> 72719c9518f6a817d53d5234de0020313cab6950b2fRoboErik * <li>{@link MediaSession#PLAYBACK_TYPE_LOCAL}</li> 72819c9518f6a817d53d5234de0020313cab6950b2fRoboErik * <li>{@link MediaSession#PLAYBACK_TYPE_REMOTE}</li> 729ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * </ul> 730ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 731ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @return The type of volume handling this session is using. 732ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 733ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik public int getVolumeType() { 734ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return mVolumeType; 735ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 736ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 737ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 7389db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * Get the audio attributes for this session. The attributes will affect 7399db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * volume handling for the session. When the volume type is 7409db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * {@link MediaSession#PLAYBACK_TYPE_REMOTE} these may be ignored by the 7419db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * remote volume handler. 742ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 7439db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * @return The attributes for this session. 744ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 7459db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik public AudioAttributes getAudioAttributes() { 7469db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik return mAudioAttrs; 747ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 748ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 749ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 750ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Get the type of volume control that can be used. One of: 751ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * <ul> 752ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * <li>{@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}</li> 753ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * <li>{@link VolumeProvider#VOLUME_CONTROL_RELATIVE}</li> 754ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * <li>{@link VolumeProvider#VOLUME_CONTROL_FIXED}</li> 755ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * </ul> 756ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 757ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @return The type of volume control that may be used with this 758ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * session. 759ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 760ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik public int getVolumeControl() { 761ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return mVolumeControl; 762ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 763ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 764ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 765ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Get the maximum volume that may be set for this session. 766ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 767ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @return The maximum allowed volume where this session is playing. 768ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 769ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik public int getMaxVolume() { 770ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return mMaxVolume; 771ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 772ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 773ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 774ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Get the current volume for this session. 775ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 776ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @return The current volume where this session is playing. 777ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 778ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik public int getCurrentVolume() { 779ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return mCurrentVolume; 780ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 781ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 782ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 78307c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik private final static class CallbackStub extends ISessionControllerCallback.Stub { 78442ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik private final WeakReference<MediaController> mController; 78501fe661ae5da3739215d93922412df4b24c859a2RoboErik 78642ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik public CallbackStub(MediaController controller) { 78742ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik mController = new WeakReference<MediaController>(controller); 78801fe661ae5da3739215d93922412df4b24c859a2RoboErik } 78901fe661ae5da3739215d93922412df4b24c859a2RoboErik 79001fe661ae5da3739215d93922412df4b24c859a2RoboErik @Override 7918ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik public void onEvent(String event, Bundle extras) { 79242ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik MediaController controller = mController.get(); 7938ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (controller != null) { 794c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik controller.postMessage(MSG_EVENT, event, extras); 79501fe661ae5da3739215d93922412df4b24c859a2RoboErik } 79601fe661ae5da3739215d93922412df4b24c859a2RoboErik } 79701fe661ae5da3739215d93922412df4b24c859a2RoboErik 79801fe661ae5da3739215d93922412df4b24c859a2RoboErik @Override 7998ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik public void onPlaybackStateChanged(PlaybackState state) { 80042ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik MediaController controller = mController.get(); 8018ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (controller != null) { 802c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik controller.postMessage(MSG_UPDATE_PLAYBACK_STATE, state, null); 80301fe661ae5da3739215d93922412df4b24c859a2RoboErik } 80401fe661ae5da3739215d93922412df4b24c859a2RoboErik } 80501fe661ae5da3739215d93922412df4b24c859a2RoboErik 80601fe661ae5da3739215d93922412df4b24c859a2RoboErik @Override 8078ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik public void onMetadataChanged(MediaMetadata metadata) { 80842ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik MediaController controller = mController.get(); 8098ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (controller != null) { 810c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik controller.postMessage(MSG_UPDATE_METADATA, metadata, null); 81101fe661ae5da3739215d93922412df4b24c859a2RoboErik } 81201fe661ae5da3739215d93922412df4b24c859a2RoboErik } 81301fe661ae5da3739215d93922412df4b24c859a2RoboErik 81419c9518f6a817d53d5234de0020313cab6950b2fRoboErik @Override 815f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public void onQueueChanged(ParceledListSlice parceledQueue) { 816f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal List<MediaSession.Track> queue = parceledQueue.getList(); 817f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal MediaController controller = mController.get(); 818f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal if (controller != null) { 819f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal controller.postMessage(MSG_UPDATE_QUEUE, queue, null); 820f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 821f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 822f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 823f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal @Override 824f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public void onQueueTitleChanged(CharSequence title) { 825f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal MediaController controller = mController.get(); 826f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal if (controller != null) { 827f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal controller.postMessage(MSG_UPDATE_QUEUE_TITLE, title, null); 828f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 829f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 830f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 831f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal @Override 832f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public void onExtrasChanged(Bundle extras) { 833f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal MediaController controller = mController.get(); 834f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal if (controller != null) { 835f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal controller.postMessage(MSG_UPDATE_EXTRAS, extras, null); 836f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 837f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 838f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 839f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal @Override 84019c9518f6a817d53d5234de0020313cab6950b2fRoboErik public void onVolumeInfoChanged(ParcelableVolumeInfo pvi) { 84119c9518f6a817d53d5234de0020313cab6950b2fRoboErik MediaController controller = mController.get(); 84219c9518f6a817d53d5234de0020313cab6950b2fRoboErik if (controller != null) { 8439db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik VolumeInfo info = new VolumeInfo(pvi.volumeType, pvi.audioAttrs, pvi.controlType, 84419c9518f6a817d53d5234de0020313cab6950b2fRoboErik pvi.maxVolume, pvi.currentVolume); 84519c9518f6a817d53d5234de0020313cab6950b2fRoboErik controller.postMessage(MSG_UPDATE_VOLUME, info, null); 84619c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 84719c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 84819c9518f6a817d53d5234de0020313cab6950b2fRoboErik 84901fe661ae5da3739215d93922412df4b24c859a2RoboErik } 85001fe661ae5da3739215d93922412df4b24c859a2RoboErik 85101fe661ae5da3739215d93922412df4b24c859a2RoboErik private final static class MessageHandler extends Handler { 85242ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik private final MediaController.Callback mCallback; 85301fe661ae5da3739215d93922412df4b24c859a2RoboErik 85442ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik public MessageHandler(Looper looper, MediaController.Callback cb) { 8558ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik super(looper, null, true); 8568ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik mCallback = cb; 85701fe661ae5da3739215d93922412df4b24c859a2RoboErik } 85801fe661ae5da3739215d93922412df4b24c859a2RoboErik 85901fe661ae5da3739215d93922412df4b24c859a2RoboErik @Override 86001fe661ae5da3739215d93922412df4b24c859a2RoboErik public void handleMessage(Message msg) { 86101fe661ae5da3739215d93922412df4b24c859a2RoboErik switch (msg.what) { 8628ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik case MSG_EVENT: 86379fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik mCallback.onSessionEvent((String) msg.obj, msg.getData()); 86401fe661ae5da3739215d93922412df4b24c859a2RoboErik break; 865c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik case MSG_UPDATE_PLAYBACK_STATE: 866c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mCallback.onPlaybackStateChanged((PlaybackState) msg.obj); 867c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik break; 868c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik case MSG_UPDATE_METADATA: 869c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mCallback.onMetadataChanged((MediaMetadata) msg.obj); 870c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik break; 871f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal case MSG_UPDATE_QUEUE: 872f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal mCallback.onQueueChanged((List<MediaSession.Track>) msg.obj); 873f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal break; 874f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal case MSG_UPDATE_QUEUE_TITLE: 875f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal mCallback.onQueueTitleChanged((CharSequence) msg.obj); 876f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal break; 877f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal case MSG_UPDATE_EXTRAS: 878f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal mCallback.onExtrasChanged((Bundle) msg.obj); 879f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal break; 88019c9518f6a817d53d5234de0020313cab6950b2fRoboErik case MSG_UPDATE_VOLUME: 88119c9518f6a817d53d5234de0020313cab6950b2fRoboErik mCallback.onVolumeInfoChanged((VolumeInfo) msg.obj); 88219c9518f6a817d53d5234de0020313cab6950b2fRoboErik break; 88301fe661ae5da3739215d93922412df4b24c859a2RoboErik } 88401fe661ae5da3739215d93922412df4b24c859a2RoboErik } 8858ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik 8868ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik public void post(int what, Object obj, Bundle data) { 8878ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik obtainMessage(what, obj).sendToTarget(); 8888ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 88901fe661ae5da3739215d93922412df4b24c859a2RoboErik } 89001fe661ae5da3739215d93922412df4b24c859a2RoboErik 89101fe661ae5da3739215d93922412df4b24c859a2RoboErik} 892