101fe661ae5da3739215d93922412df4b24c859a2RoboErik/* 201fe661ae5da3739215d93922412df4b24c859a2RoboErik * Copyright (C) 2014 The Android Open Source Project 301fe661ae5da3739215d93922412df4b24c859a2RoboErik * 401fe661ae5da3739215d93922412df4b24c859a2RoboErik * Licensed under the Apache License, Version 2.0 (the "License"); 501fe661ae5da3739215d93922412df4b24c859a2RoboErik * you may not use this file except in compliance with the License. 601fe661ae5da3739215d93922412df4b24c859a2RoboErik * You may obtain a copy of the License at 701fe661ae5da3739215d93922412df4b24c859a2RoboErik * 801fe661ae5da3739215d93922412df4b24c859a2RoboErik * http://www.apache.org/licenses/LICENSE-2.0 901fe661ae5da3739215d93922412df4b24c859a2RoboErik * 1001fe661ae5da3739215d93922412df4b24c859a2RoboErik * Unless required by applicable law or agreed to in writing, software 1101fe661ae5da3739215d93922412df4b24c859a2RoboErik * distributed under the License is distributed on an "AS IS" BASIS, 1201fe661ae5da3739215d93922412df4b24c859a2RoboErik * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1301fe661ae5da3739215d93922412df4b24c859a2RoboErik * See the License for the specific language governing permissions and 1401fe661ae5da3739215d93922412df4b24c859a2RoboErik * limitations under the License. 1501fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 1601fe661ae5da3739215d93922412df4b24c859a2RoboErik 172f5b057da7d05d5d699a272aa24fd7c97cdda820RoboErikpackage android.media.session; 1801fe661ae5da3739215d93922412df4b24c859a2RoboErik 19bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brownimport android.annotation.NonNull; 20bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brownimport android.annotation.Nullable; 21e34c09daf89fb888fe2638e71758573462d85173RoboErikimport android.app.PendingIntent; 22031149cd5f22bd858142633c7a763450f42793f7RoboErikimport android.content.Context; 23f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Pealimport android.content.pm.ParceledListSlice; 249db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErikimport android.media.AudioAttributes; 2519c9518f6a817d53d5234de0020313cab6950b2fRoboErikimport android.media.AudioManager; 2642ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErikimport android.media.MediaMetadata; 27c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErikimport android.media.Rating; 28ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErikimport android.media.VolumeProvider; 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 50f2133474afce7808541c92a1e5c78eb8b0950329RoboErik * hold the "android.permission.MEDIA_CONTENT_CONTROL" permission or are an 51f2133474afce7808541c92a1e5c78eb8b0950329RoboErik * enabled notification listener or by getting a {@link MediaSession.Token} 52f2133474afce7808541c92a1e5c78eb8b0950329RoboErik * directly from the session owner. 5301fe661ae5da3739215d93922412df4b24c859a2RoboErik * <p> 5401fe661ae5da3739215d93922412df4b24c859a2RoboErik * MediaController objects are thread-safe. 5501fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 5642ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErikpublic final class MediaController { 57bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown private static final String TAG = "MediaController"; 5801fe661ae5da3739215d93922412df4b24c859a2RoboErik 598ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik private static final int MSG_EVENT = 1; 60c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik private static final int MSG_UPDATE_PLAYBACK_STATE = 2; 61c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik private static final int MSG_UPDATE_METADATA = 3; 6201a500ed1c6ae3fff66678144ae637aa8cad0eccJeff Brown private static final int MSG_UPDATE_VOLUME = 4; 63f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal private static final int MSG_UPDATE_QUEUE = 5; 64f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal private static final int MSG_UPDATE_QUEUE_TITLE = 6; 65f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal private static final int MSG_UPDATE_EXTRAS = 7; 6624762bffc3358762666079cd802040a316b3260dRoboErik private static final int MSG_DESTROYED = 8; 6701fe661ae5da3739215d93922412df4b24c859a2RoboErik 6807c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik private final ISessionController mSessionBinder; 6901fe661ae5da3739215d93922412df4b24c859a2RoboErik 7076fca4e177e18b591439fdff64b8f5242a5122d0RoboErik private final MediaSession.Token mToken; 71031149cd5f22bd858142633c7a763450f42793f7RoboErik private final Context mContext; 728ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik private final CallbackStub mCbStub = new CallbackStub(this); 738ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik private final ArrayList<MessageHandler> mCallbacks = new ArrayList<MessageHandler>(); 7401fe661ae5da3739215d93922412df4b24c859a2RoboErik private final Object mLock = new Object(); 7501fe661ae5da3739215d93922412df4b24c859a2RoboErik 7601fe661ae5da3739215d93922412df4b24c859a2RoboErik private boolean mCbRegistered = false; 77aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik private String mPackageName; 78aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik private String mTag; 7901fe661ae5da3739215d93922412df4b24c859a2RoboErik 801a937b04e63539cb1fab1bde601031d415c7156fJeff Brown private final TransportControls mTransportControls; 818ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik 8201fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 838b4bffcac996b4083e720310a09d315ca1c4a000RoboErik * Call for creating a MediaController directly from a binder. Should only 848b4bffcac996b4083e720310a09d315ca1c4a000RoboErik * be used by framework code. 858b4bffcac996b4083e720310a09d315ca1c4a000RoboErik * 868ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * @hide 8701fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 88031149cd5f22bd858142633c7a763450f42793f7RoboErik public MediaController(Context context, ISessionController sessionBinder) { 898b4bffcac996b4083e720310a09d315ca1c4a000RoboErik if (sessionBinder == null) { 908b4bffcac996b4083e720310a09d315ca1c4a000RoboErik throw new IllegalArgumentException("Session token cannot be null"); 918b4bffcac996b4083e720310a09d315ca1c4a000RoboErik } 92031149cd5f22bd858142633c7a763450f42793f7RoboErik if (context == null) { 93031149cd5f22bd858142633c7a763450f42793f7RoboErik throw new IllegalArgumentException("Context cannot be null"); 94031149cd5f22bd858142633c7a763450f42793f7RoboErik } 958b4bffcac996b4083e720310a09d315ca1c4a000RoboErik mSessionBinder = sessionBinder; 968b4bffcac996b4083e720310a09d315ca1c4a000RoboErik mTransportControls = new TransportControls(); 9776fca4e177e18b591439fdff64b8f5242a5122d0RoboErik mToken = new MediaSession.Token(sessionBinder); 98031149cd5f22bd858142633c7a763450f42793f7RoboErik mContext = context; 9901fe661ae5da3739215d93922412df4b24c859a2RoboErik } 10001fe661ae5da3739215d93922412df4b24c859a2RoboErik 10101fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 1028b4bffcac996b4083e720310a09d315ca1c4a000RoboErik * Create a new MediaController from a session's token. 1038ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * 104031149cd5f22bd858142633c7a763450f42793f7RoboErik * @param context The caller's context. 1058b4bffcac996b4083e720310a09d315ca1c4a000RoboErik * @param token The token for the session. 10601fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 107031149cd5f22bd858142633c7a763450f42793f7RoboErik public MediaController(@NonNull Context context, @NonNull MediaSession.Token token) { 108031149cd5f22bd858142633c7a763450f42793f7RoboErik this(context, token.getBinder()); 10901fe661ae5da3739215d93922412df4b24c859a2RoboErik } 11001fe661ae5da3739215d93922412df4b24c859a2RoboErik 11101fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 1121a937b04e63539cb1fab1bde601031d415c7156fJeff Brown * Get a {@link TransportControls} instance to send transport actions to 1131a937b04e63539cb1fab1bde601031d415c7156fJeff Brown * the associated session. 11401fe661ae5da3739215d93922412df4b24c859a2RoboErik * 1151a937b04e63539cb1fab1bde601031d415c7156fJeff Brown * @return A transport controls instance. 11601fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 117bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public @NonNull TransportControls getTransportControls() { 1181a937b04e63539cb1fab1bde601031d415c7156fJeff Brown return mTransportControls; 1191a937b04e63539cb1fab1bde601031d415c7156fJeff Brown } 1201a937b04e63539cb1fab1bde601031d415c7156fJeff Brown 1211a937b04e63539cb1fab1bde601031d415c7156fJeff Brown /** 12279fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik * Send the specified media button event to the session. Only media keys can 12379fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik * be sent by this method, other keys will be ignored. 12401fe661ae5da3739215d93922412df4b24c859a2RoboErik * 12579fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik * @param keyEvent The media button event to dispatch. 12679fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik * @return true if the event was sent to the session, false otherwise. 12701fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 128bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public boolean dispatchMediaButtonEvent(@NonNull KeyEvent keyEvent) { 12979fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik if (keyEvent == null) { 13079fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik throw new IllegalArgumentException("KeyEvent may not be null"); 13179fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik } 13279fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik if (!KeyEvent.isMediaKey(keyEvent.getKeyCode())) { 13379fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik return false; 13401fe661ae5da3739215d93922412df4b24c859a2RoboErik } 13501fe661ae5da3739215d93922412df4b24c859a2RoboErik try { 13679fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik return mSessionBinder.sendMediaButton(keyEvent); 13701fe661ae5da3739215d93922412df4b24c859a2RoboErik } catch (RemoteException e) { 138c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik // System is dead. =( 13901fe661ae5da3739215d93922412df4b24c859a2RoboErik } 14079fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik return false; 14101fe661ae5da3739215d93922412df4b24c859a2RoboErik } 14201fe661ae5da3739215d93922412df4b24c859a2RoboErik 14301fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 144c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Get the current playback state for this session. 145c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 146c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @return The current PlaybackState or null 147c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 148bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public @Nullable PlaybackState getPlaybackState() { 149c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 150c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return mSessionBinder.getPlaybackState(); 151c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 152c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling getPlaybackState.", e); 153c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return null; 154c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 155c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 156c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 157c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 158c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Get the current metadata for this session. 159c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 160c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @return The current MediaMetadata or null. 161c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 162bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public @Nullable MediaMetadata getMetadata() { 163c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 164c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return mSessionBinder.getMetadata(); 165c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 166c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling getMetadata.", e); 167c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return null; 168c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 169c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 170c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 171c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 172477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik * Get the current play queue for this session if one is set. If you only 173477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik * care about the current item {@link #getMetadata()} should be used. 174f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * 175f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * @return The current play queue or null. 176f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal */ 1773625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik public @Nullable List<MediaSession.QueueItem> getQueue() { 178f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal try { 179f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal ParceledListSlice queue = mSessionBinder.getQueue(); 180f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal if (queue != null) { 181f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal return queue.getList(); 182f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 183f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } catch (RemoteException e) { 184f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal Log.wtf(TAG, "Error calling getQueue.", e); 185f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 186f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal return null; 187f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 188f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 189f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal /** 19051fdfa273e036d0e4f5e5c624988b33873fa3ec7Yao Chen * Get the queue title for this session. 19151fdfa273e036d0e4f5e5c624988b33873fa3ec7Yao Chen */ 19251fdfa273e036d0e4f5e5c624988b33873fa3ec7Yao Chen public @Nullable CharSequence getQueueTitle() { 19351fdfa273e036d0e4f5e5c624988b33873fa3ec7Yao Chen try { 19451fdfa273e036d0e4f5e5c624988b33873fa3ec7Yao Chen return mSessionBinder.getQueueTitle(); 19551fdfa273e036d0e4f5e5c624988b33873fa3ec7Yao Chen } catch (RemoteException e) { 19651fdfa273e036d0e4f5e5c624988b33873fa3ec7Yao Chen Log.wtf(TAG, "Error calling getQueueTitle", e); 19751fdfa273e036d0e4f5e5c624988b33873fa3ec7Yao Chen } 19851fdfa273e036d0e4f5e5c624988b33873fa3ec7Yao Chen return null; 19951fdfa273e036d0e4f5e5c624988b33873fa3ec7Yao Chen } 20051fdfa273e036d0e4f5e5c624988b33873fa3ec7Yao Chen 20151fdfa273e036d0e4f5e5c624988b33873fa3ec7Yao Chen /** 20251fdfa273e036d0e4f5e5c624988b33873fa3ec7Yao Chen * Get the extras for this session. 20351fdfa273e036d0e4f5e5c624988b33873fa3ec7Yao Chen */ 20451fdfa273e036d0e4f5e5c624988b33873fa3ec7Yao Chen public @Nullable Bundle getExtras() { 20551fdfa273e036d0e4f5e5c624988b33873fa3ec7Yao Chen try { 20651fdfa273e036d0e4f5e5c624988b33873fa3ec7Yao Chen return mSessionBinder.getExtras(); 20751fdfa273e036d0e4f5e5c624988b33873fa3ec7Yao Chen } catch (RemoteException e) { 20851fdfa273e036d0e4f5e5c624988b33873fa3ec7Yao Chen Log.wtf(TAG, "Error calling getExtras", e); 20951fdfa273e036d0e4f5e5c624988b33873fa3ec7Yao Chen } 21051fdfa273e036d0e4f5e5c624988b33873fa3ec7Yao Chen return null; 21151fdfa273e036d0e4f5e5c624988b33873fa3ec7Yao Chen } 21251fdfa273e036d0e4f5e5c624988b33873fa3ec7Yao Chen 21351fdfa273e036d0e4f5e5c624988b33873fa3ec7Yao Chen /** 214c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Get the rating type supported by the session. One of: 215c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <ul> 216c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_NONE}</li> 217c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_HEART}</li> 218c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_THUMB_UP_DOWN}</li> 219c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_3_STARS}</li> 220c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_4_STARS}</li> 221c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_5_STARS}</li> 222c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_PERCENTAGE}</li> 223c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * </ul> 224c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 225c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @return The supported rating type 226c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 227c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public int getRatingType() { 228c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 229c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return mSessionBinder.getRatingType(); 230c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 231c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling getRatingType.", e); 232c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return Rating.RATING_NONE; 233c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 234c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 235c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 236c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 23776fca4e177e18b591439fdff64b8f5242a5122d0RoboErik * Get the flags for this session. Flags are defined in {@link MediaSession}. 23873e23e229dd1a2d25687b1c6a63c708665378e41RoboErik * 23973e23e229dd1a2d25687b1c6a63c708665378e41RoboErik * @return The current set of flags for the session. 24073e23e229dd1a2d25687b1c6a63c708665378e41RoboErik */ 24176fca4e177e18b591439fdff64b8f5242a5122d0RoboErik public @MediaSession.SessionFlags long getFlags() { 24273e23e229dd1a2d25687b1c6a63c708665378e41RoboErik try { 24373e23e229dd1a2d25687b1c6a63c708665378e41RoboErik return mSessionBinder.getFlags(); 24473e23e229dd1a2d25687b1c6a63c708665378e41RoboErik } catch (RemoteException e) { 24573e23e229dd1a2d25687b1c6a63c708665378e41RoboErik Log.wtf(TAG, "Error calling getFlags.", e); 24673e23e229dd1a2d25687b1c6a63c708665378e41RoboErik } 24773e23e229dd1a2d25687b1c6a63c708665378e41RoboErik return 0; 24873e23e229dd1a2d25687b1c6a63c708665378e41RoboErik } 24973e23e229dd1a2d25687b1c6a63c708665378e41RoboErik 25073e23e229dd1a2d25687b1c6a63c708665378e41RoboErik /** 251d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik * Get the current playback info for this session. 252ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 253d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik * @return The current playback info or null. 254ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 255d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik public @Nullable PlaybackInfo getPlaybackInfo() { 256ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik try { 257ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik ParcelableVolumeInfo result = mSessionBinder.getVolumeAttributes(); 258d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik return new PlaybackInfo(result.volumeType, result.audioAttrs, result.controlType, 259ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik result.maxVolume, result.currentVolume); 260ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 261ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } catch (RemoteException e) { 262a66c40bf6e0fb79ead6d8a9fc29c5671fa7b1206RoboErik Log.wtf(TAG, "Error calling getAudioInfo.", e); 263ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 264ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return null; 265ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 266ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 267ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 268e34c09daf89fb888fe2638e71758573462d85173RoboErik * Get an intent for launching UI associated with this session if one 269e34c09daf89fb888fe2638e71758573462d85173RoboErik * exists. 270e34c09daf89fb888fe2638e71758573462d85173RoboErik * 271e34c09daf89fb888fe2638e71758573462d85173RoboErik * @return A {@link PendingIntent} to launch UI or null. 272e34c09daf89fb888fe2638e71758573462d85173RoboErik */ 273d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik public @Nullable PendingIntent getSessionActivity() { 274e34c09daf89fb888fe2638e71758573462d85173RoboErik try { 275e34c09daf89fb888fe2638e71758573462d85173RoboErik return mSessionBinder.getLaunchPendingIntent(); 276e34c09daf89fb888fe2638e71758573462d85173RoboErik } catch (RemoteException e) { 277e34c09daf89fb888fe2638e71758573462d85173RoboErik Log.wtf(TAG, "Error calling getPendingIntent.", e); 278e34c09daf89fb888fe2638e71758573462d85173RoboErik } 279e34c09daf89fb888fe2638e71758573462d85173RoboErik return null; 280e34c09daf89fb888fe2638e71758573462d85173RoboErik } 281e34c09daf89fb888fe2638e71758573462d85173RoboErik 282e34c09daf89fb888fe2638e71758573462d85173RoboErik /** 28376fca4e177e18b591439fdff64b8f5242a5122d0RoboErik * Get the token for the session this is connected to. 28476fca4e177e18b591439fdff64b8f5242a5122d0RoboErik * 28576fca4e177e18b591439fdff64b8f5242a5122d0RoboErik * @return The token for the connected session. 28676fca4e177e18b591439fdff64b8f5242a5122d0RoboErik */ 28776fca4e177e18b591439fdff64b8f5242a5122d0RoboErik public @NonNull MediaSession.Token getSessionToken() { 28876fca4e177e18b591439fdff64b8f5242a5122d0RoboErik return mToken; 28976fca4e177e18b591439fdff64b8f5242a5122d0RoboErik } 29076fca4e177e18b591439fdff64b8f5242a5122d0RoboErik 29176fca4e177e18b591439fdff64b8f5242a5122d0RoboErik /** 2929db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * Set the volume of the output this session is playing on. The command will 2939db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * be ignored if it does not support 29419c9518f6a817d53d5234de0020313cab6950b2fRoboErik * {@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}. The flags in 29519c9518f6a817d53d5234de0020313cab6950b2fRoboErik * {@link AudioManager} may be used to affect the handling. 29619c9518f6a817d53d5234de0020313cab6950b2fRoboErik * 297d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik * @see #getPlaybackInfo() 29819c9518f6a817d53d5234de0020313cab6950b2fRoboErik * @param value The value to set it to, between 0 and the reported max. 299d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik * @param flags Flags from {@link AudioManager} to include with the volume 300d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik * request. 30119c9518f6a817d53d5234de0020313cab6950b2fRoboErik */ 30219c9518f6a817d53d5234de0020313cab6950b2fRoboErik public void setVolumeTo(int value, int flags) { 30319c9518f6a817d53d5234de0020313cab6950b2fRoboErik try { 3040dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik mSessionBinder.setVolumeTo(value, flags, mContext.getPackageName()); 30519c9518f6a817d53d5234de0020313cab6950b2fRoboErik } catch (RemoteException e) { 30619c9518f6a817d53d5234de0020313cab6950b2fRoboErik Log.wtf(TAG, "Error calling setVolumeTo.", e); 30719c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 30819c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 30919c9518f6a817d53d5234de0020313cab6950b2fRoboErik 31019c9518f6a817d53d5234de0020313cab6950b2fRoboErik /** 3119db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * Adjust the volume of the output this session is playing on. The direction 3129db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * must be one of {@link AudioManager#ADJUST_LOWER}, 3131ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik * {@link AudioManager#ADJUST_RAISE}, or {@link AudioManager#ADJUST_SAME}. 3141ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik * The command will be ignored if the session does not support 3151ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik * {@link VolumeProvider#VOLUME_CONTROL_RELATIVE} or 31619c9518f6a817d53d5234de0020313cab6950b2fRoboErik * {@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}. The flags in 31719c9518f6a817d53d5234de0020313cab6950b2fRoboErik * {@link AudioManager} may be used to affect the handling. 31819c9518f6a817d53d5234de0020313cab6950b2fRoboErik * 319d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik * @see #getPlaybackInfo() 3201ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik * @param direction The direction to adjust the volume in. 32119c9518f6a817d53d5234de0020313cab6950b2fRoboErik * @param flags Any flags to pass with the command. 32219c9518f6a817d53d5234de0020313cab6950b2fRoboErik */ 3231ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik public void adjustVolume(int direction, int flags) { 32419c9518f6a817d53d5234de0020313cab6950b2fRoboErik try { 3250dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik mSessionBinder.adjustVolume(direction, flags, mContext.getPackageName()); 32619c9518f6a817d53d5234de0020313cab6950b2fRoboErik } catch (RemoteException e) { 32719c9518f6a817d53d5234de0020313cab6950b2fRoboErik Log.wtf(TAG, "Error calling adjustVolumeBy.", e); 32819c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 32919c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 33019c9518f6a817d53d5234de0020313cab6950b2fRoboErik 33119c9518f6a817d53d5234de0020313cab6950b2fRoboErik /** 33214f717a506a0d22facbec07386b06634e0c6a8eeRoboErik * Registers a callback to receive updates from the Session. Updates will be 33301fe661ae5da3739215d93922412df4b24c859a2RoboErik * posted on the caller's thread. 33401fe661ae5da3739215d93922412df4b24c859a2RoboErik * 335bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * @param callback The callback object, must not be null. 33601fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 33714f717a506a0d22facbec07386b06634e0c6a8eeRoboErik public void registerCallback(@NonNull Callback callback) { 33814f717a506a0d22facbec07386b06634e0c6a8eeRoboErik registerCallback(callback, null); 33901fe661ae5da3739215d93922412df4b24c859a2RoboErik } 34001fe661ae5da3739215d93922412df4b24c859a2RoboErik 34101fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 34214f717a506a0d22facbec07386b06634e0c6a8eeRoboErik * Registers a callback to receive updates from the session. Updates will be 3438ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * posted on the specified handler's thread. 34401fe661ae5da3739215d93922412df4b24c859a2RoboErik * 345bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * @param callback The callback object, must not be null. 3468ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * @param handler The handler to post updates on. If null the callers thread 347bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * will be used. 34801fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 34914f717a506a0d22facbec07386b06634e0c6a8eeRoboErik public void registerCallback(@NonNull Callback callback, @Nullable Handler handler) { 350bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown if (callback == null) { 351bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown throw new IllegalArgumentException("callback must not be null"); 352bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown } 35301fe661ae5da3739215d93922412df4b24c859a2RoboErik if (handler == null) { 35401fe661ae5da3739215d93922412df4b24c859a2RoboErik handler = new Handler(); 35501fe661ae5da3739215d93922412df4b24c859a2RoboErik } 35601fe661ae5da3739215d93922412df4b24c859a2RoboErik synchronized (mLock) { 357bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown addCallbackLocked(callback, handler); 35801fe661ae5da3739215d93922412df4b24c859a2RoboErik } 35901fe661ae5da3739215d93922412df4b24c859a2RoboErik } 36001fe661ae5da3739215d93922412df4b24c859a2RoboErik 36101fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 36214f717a506a0d22facbec07386b06634e0c6a8eeRoboErik * Unregisters the specified callback. If an update has already been posted 36314f717a506a0d22facbec07386b06634e0c6a8eeRoboErik * you may still receive it after calling this method. 36401fe661ae5da3739215d93922412df4b24c859a2RoboErik * 365bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * @param callback The callback to remove. 36601fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 36714f717a506a0d22facbec07386b06634e0c6a8eeRoboErik public void unregisterCallback(@NonNull Callback callback) { 368bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown if (callback == null) { 369bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown throw new IllegalArgumentException("callback must not be null"); 370bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown } 37101fe661ae5da3739215d93922412df4b24c859a2RoboErik synchronized (mLock) { 372bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown removeCallbackLocked(callback); 37301fe661ae5da3739215d93922412df4b24c859a2RoboErik } 37401fe661ae5da3739215d93922412df4b24c859a2RoboErik } 37501fe661ae5da3739215d93922412df4b24c859a2RoboErik 3768ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik /** 3778ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * Sends a generic command to the session. It is up to the session creator 3788ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * to decide what commands and parameters they will support. As such, 3798ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * commands should only be sent to sessions that the controller owns. 3808ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * 3818ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * @param command The command to send 382f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * @param args Any parameters to include with the command 3838ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * @param cb The callback to receive the result on 3848ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik */ 385f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal public void sendCommand(@NonNull String command, @Nullable Bundle args, 386bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown @Nullable ResultReceiver cb) { 3878ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (TextUtils.isEmpty(command)) { 3888ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik throw new IllegalArgumentException("command cannot be null or empty"); 3898ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 3908ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik try { 391f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal mSessionBinder.sendCommand(command, args, cb); 3928ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } catch (RemoteException e) { 3938ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik Log.d(TAG, "Dead object in sendCommand.", e); 3948ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 3958ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 3968ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik 39707c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik /** 398aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik * Get the session owner's package name. 399fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik * 400aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik * @return The package name of of the session owner. 401aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik */ 402aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik public String getPackageName() { 403aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik if (mPackageName == null) { 404aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik try { 405aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik mPackageName = mSessionBinder.getPackageName(); 406aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik } catch (RemoteException e) { 407aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik Log.d(TAG, "Dead object in getPackageName.", e); 408aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik } 409aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik } 410aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik return mPackageName; 411aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik } 412aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik 413aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik /** 414aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik * Get the session's tag for debugging purposes. 415aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik * 416aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik * @return The session's tag. 417fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik * @hide 418fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik */ 419aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik public String getTag() { 420aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik if (mTag == null) { 42173e23e229dd1a2d25687b1c6a63c708665378e41RoboErik try { 422aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik mTag = mSessionBinder.getTag(); 42373e23e229dd1a2d25687b1c6a63c708665378e41RoboErik } catch (RemoteException e) { 424aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik Log.d(TAG, "Dead object in getTag.", e); 42573e23e229dd1a2d25687b1c6a63c708665378e41RoboErik } 426fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik } 427aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik return mTag; 428fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik } 429fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik 43001fe661ae5da3739215d93922412df4b24c859a2RoboErik /* 43101fe661ae5da3739215d93922412df4b24c859a2RoboErik * @hide 43201fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 43307c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik ISessionController getSessionBinder() { 43401fe661ae5da3739215d93922412df4b24c859a2RoboErik return mSessionBinder; 43501fe661ae5da3739215d93922412df4b24c859a2RoboErik } 43601fe661ae5da3739215d93922412df4b24c859a2RoboErik 437b5245d8904160917942fe91fc8db7f1dfa098fc0Christoph Studer /** 438b5245d8904160917942fe91fc8db7f1dfa098fc0Christoph Studer * @hide 439b5245d8904160917942fe91fc8db7f1dfa098fc0Christoph Studer */ 440b5245d8904160917942fe91fc8db7f1dfa098fc0Christoph Studer public boolean controlsSameSession(MediaController other) { 441b5245d8904160917942fe91fc8db7f1dfa098fc0Christoph Studer if (other == null) return false; 442b5245d8904160917942fe91fc8db7f1dfa098fc0Christoph Studer return mSessionBinder.asBinder() == other.getSessionBinder().asBinder(); 443b5245d8904160917942fe91fc8db7f1dfa098fc0Christoph Studer } 444b5245d8904160917942fe91fc8db7f1dfa098fc0Christoph Studer 44501fe661ae5da3739215d93922412df4b24c859a2RoboErik private void addCallbackLocked(Callback cb, Handler handler) { 4468ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (getHandlerForCallbackLocked(cb) != null) { 44701fe661ae5da3739215d93922412df4b24c859a2RoboErik Log.w(TAG, "Callback is already added, ignoring"); 44801fe661ae5da3739215d93922412df4b24c859a2RoboErik return; 44901fe661ae5da3739215d93922412df4b24c859a2RoboErik } 4508ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik MessageHandler holder = new MessageHandler(handler.getLooper(), cb); 4518ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik mCallbacks.add(holder); 4523e0cfcda31301e53c92cb2f91ed8be1cd6efd8bcRoboErik holder.mRegistered = true; 45301fe661ae5da3739215d93922412df4b24c859a2RoboErik 45401fe661ae5da3739215d93922412df4b24c859a2RoboErik if (!mCbRegistered) { 45501fe661ae5da3739215d93922412df4b24c859a2RoboErik try { 45601fe661ae5da3739215d93922412df4b24c859a2RoboErik mSessionBinder.registerCallbackListener(mCbStub); 45701fe661ae5da3739215d93922412df4b24c859a2RoboErik mCbRegistered = true; 45801fe661ae5da3739215d93922412df4b24c859a2RoboErik } catch (RemoteException e) { 459d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik Log.e(TAG, "Dead object in registerCallback", e); 46001fe661ae5da3739215d93922412df4b24c859a2RoboErik } 46101fe661ae5da3739215d93922412df4b24c859a2RoboErik } 46201fe661ae5da3739215d93922412df4b24c859a2RoboErik } 46301fe661ae5da3739215d93922412df4b24c859a2RoboErik 4648ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik private boolean removeCallbackLocked(Callback cb) { 465d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik boolean success = false; 4668ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik for (int i = mCallbacks.size() - 1; i >= 0; i--) { 4678ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik MessageHandler handler = mCallbacks.get(i); 4688ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (cb == handler.mCallback) { 4698ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik mCallbacks.remove(i); 470d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik success = true; 4713e0cfcda31301e53c92cb2f91ed8be1cd6efd8bcRoboErik handler.mRegistered = false; 47201fe661ae5da3739215d93922412df4b24c859a2RoboErik } 47301fe661ae5da3739215d93922412df4b24c859a2RoboErik } 474d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik if (mCbRegistered && mCallbacks.size() == 0) { 475d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik try { 476d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik mSessionBinder.unregisterCallbackListener(mCbStub); 477d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik } catch (RemoteException e) { 478d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik Log.e(TAG, "Dead object in removeCallbackLocked"); 479d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik } 480d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik mCbRegistered = false; 481d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik } 482d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik return success; 48301fe661ae5da3739215d93922412df4b24c859a2RoboErik } 48401fe661ae5da3739215d93922412df4b24c859a2RoboErik 4858ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik private MessageHandler getHandlerForCallbackLocked(Callback cb) { 4868ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (cb == null) { 4878ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik throw new IllegalArgumentException("Callback cannot be null"); 48801fe661ae5da3739215d93922412df4b24c859a2RoboErik } 4898ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik for (int i = mCallbacks.size() - 1; i >= 0; i--) { 4908ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik MessageHandler handler = mCallbacks.get(i); 4918ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (cb == handler.mCallback) { 4928ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik return handler; 4938ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 49401fe661ae5da3739215d93922412df4b24c859a2RoboErik } 4958ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik return null; 49601fe661ae5da3739215d93922412df4b24c859a2RoboErik } 49701fe661ae5da3739215d93922412df4b24c859a2RoboErik 498c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik private final void postMessage(int what, Object obj, Bundle data) { 4998ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik synchronized (mLock) { 5008ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik for (int i = mCallbacks.size() - 1; i >= 0; i--) { 501c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mCallbacks.get(i).post(what, obj, data); 5028ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 50301fe661ae5da3739215d93922412df4b24c859a2RoboErik } 50401fe661ae5da3739215d93922412df4b24c859a2RoboErik } 50501fe661ae5da3739215d93922412df4b24c859a2RoboErik 50601fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 507bc4cf00dc5bf6e0e3c01206d5c46e64306df260aJohn Spurlock * Callback for receiving updates from the session. A Callback can be 508bc4cf00dc5bf6e0e3c01206d5c46e64306df260aJohn Spurlock * registered using {@link #registerCallback}. 50901fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 51001fe661ae5da3739215d93922412df4b24c859a2RoboErik public static abstract class Callback { 51101fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 51224762bffc3358762666079cd802040a316b3260dRoboErik * Override to handle the session being destroyed. The session is no 51324762bffc3358762666079cd802040a316b3260dRoboErik * longer valid after this call and calls to it will be ignored. 51424762bffc3358762666079cd802040a316b3260dRoboErik */ 51524762bffc3358762666079cd802040a316b3260dRoboErik public void onSessionDestroyed() { 51624762bffc3358762666079cd802040a316b3260dRoboErik } 51724762bffc3358762666079cd802040a316b3260dRoboErik 51824762bffc3358762666079cd802040a316b3260dRoboErik /** 5198ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * Override to handle custom events sent by the session owner without a 5208ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * specified interface. Controllers should only handle these for 5218ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * sessions they own. 52201fe661ae5da3739215d93922412df4b24c859a2RoboErik * 523bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * @param event The event from the session. 524bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * @param extras Optional parameters for the event, may be null. 52501fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 526bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public void onSessionEvent(@NonNull String event, @Nullable Bundle extras) { 52701fe661ae5da3739215d93922412df4b24c859a2RoboErik } 52801fe661ae5da3739215d93922412df4b24c859a2RoboErik 52901fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 530c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Override to handle changes in playback state. 531c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 532c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @param state The new playback state of the session 533c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 534bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public void onPlaybackStateChanged(@NonNull PlaybackState state) { 535c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 536c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 537c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 538c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Override to handle changes to the current metadata. 539c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 540bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * @param metadata The current metadata for the session or null if none. 541c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @see MediaMetadata 542c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 543bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public void onMetadataChanged(@Nullable MediaMetadata metadata) { 544c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 54519c9518f6a817d53d5234de0020313cab6950b2fRoboErik 54619c9518f6a817d53d5234de0020313cab6950b2fRoboErik /** 547a66c40bf6e0fb79ead6d8a9fc29c5671fa7b1206RoboErik * Override to handle changes to items in the queue. 548f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * 549a66c40bf6e0fb79ead6d8a9fc29c5671fa7b1206RoboErik * @param queue A list of items in the current play queue. It should 550a66c40bf6e0fb79ead6d8a9fc29c5671fa7b1206RoboErik * include the currently playing item as well as previous and 551a66c40bf6e0fb79ead6d8a9fc29c5671fa7b1206RoboErik * upcoming items if applicable. 5523625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik * @see MediaSession.QueueItem 553f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal */ 5543625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik public void onQueueChanged(@Nullable List<MediaSession.QueueItem> queue) { 555f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 556f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 557f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal /** 558f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * Override to handle changes to the queue title. 559f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * 560f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * @param title The title that should be displayed along with the play queue such as 561f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * "Now Playing". May be null if there is no such title. 562f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal */ 563f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public void onQueueTitleChanged(@Nullable CharSequence title) { 564f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 565f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 566f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal /** 567f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * Override to handle changes to the {@link MediaSession} extras. 568f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * 569f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * @param extras The extras that can include other information associated with the 570f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * {@link MediaSession}. 571f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal */ 572f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public void onExtrasChanged(@Nullable Bundle extras) { 573f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 574f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 575f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal /** 576a66c40bf6e0fb79ead6d8a9fc29c5671fa7b1206RoboErik * Override to handle changes to the audio info. 57719c9518f6a817d53d5234de0020313cab6950b2fRoboErik * 578a66c40bf6e0fb79ead6d8a9fc29c5671fa7b1206RoboErik * @param info The current audio info for this session. 57919c9518f6a817d53d5234de0020313cab6950b2fRoboErik */ 580d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik public void onAudioInfoChanged(PlaybackInfo info) { 58119c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 582c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 583c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 584c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 585c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Interface for controlling media playback on a session. This allows an app 586c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * to send media transport commands to the session. 587c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 588c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public final class TransportControls { 589c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik private static final String TAG = "TransportController"; 590c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 591c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik private TransportControls() { 592c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 593c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 594c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 595c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Request that the player start its playback at its current position. 596c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 597c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void play() { 598c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 599c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.play(); 600c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 601c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling play.", e); 602c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 603c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 604c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 605c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 606c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand * Request that the player start playback for a specific media id. 607f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * 608c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand * @param mediaId The id of the requested media. 609f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * @param extras Optional extras that can include extra information about the media item 610f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * to be played. 611f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal */ 6123625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik public void playFromMediaId(String mediaId, Bundle extras) { 6133625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik if (TextUtils.isEmpty(mediaId)) { 6143625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik throw new IllegalArgumentException( 6153625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik "You must specify a non-empty String for playFromMediaId."); 616f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 617f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal try { 6183625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik mSessionBinder.playFromMediaId(mediaId, extras); 619f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } catch (RemoteException e) { 6203625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik Log.wtf(TAG, "Error calling play(" + mediaId + ").", e); 621f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 622f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 623f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 624f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal /** 625f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * Request that the player start playback for a specific search query. 6264b253d2bcd62ea2a9afb067c1f1363fa7b752185RoboErik * An empty or null query should be treated as a request to play any 6274b253d2bcd62ea2a9afb067c1f1363fa7b752185RoboErik * music. 628f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * 629f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal * @param query The search query. 6304b253d2bcd62ea2a9afb067c1f1363fa7b752185RoboErik * @param extras Optional extras that can include extra information 6314b253d2bcd62ea2a9afb067c1f1363fa7b752185RoboErik * about the query. 632f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal */ 633f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public void playFromSearch(String query, Bundle extras) { 6344b253d2bcd62ea2a9afb067c1f1363fa7b752185RoboErik if (query == null) { 6354b253d2bcd62ea2a9afb067c1f1363fa7b752185RoboErik // This is to remain compatible with 6364b253d2bcd62ea2a9afb067c1f1363fa7b752185RoboErik // INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH 6374b253d2bcd62ea2a9afb067c1f1363fa7b752185RoboErik query = ""; 638f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 639f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal try { 640f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal mSessionBinder.playFromSearch(query, extras); 641f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } catch (RemoteException e) { 642f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal Log.wtf(TAG, "Error calling play(" + query + ").", e); 643f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 644f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 645f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 646f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal /** 647c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand * Request that the player start playback for a specific {@link Uri}. 648c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand * 649c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand * @param uri The URI of the requested media. 650c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand * @param extras Optional extras that can include extra information about the media item 651c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand * to be played. 652c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand */ 653c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand public void playFromUri(Uri uri, Bundle extras) { 654c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand if (uri == null || Uri.EMPTY.equals(uri)) { 655c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand throw new IllegalArgumentException( 656c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand "You must specify a non-empty Uri for playFromUri."); 657c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand } 658c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand try { 659c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand mSessionBinder.playFromUri(uri, extras); 660c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand } catch (RemoteException e) { 661c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand Log.wtf(TAG, "Error calling play(" + uri + ").", e); 662c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand } 663c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand } 664c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand 665c2045470a343923b0d74ddbd6a6b80fcf6652d66P.Y. Laligand /** 666a66c40bf6e0fb79ead6d8a9fc29c5671fa7b1206RoboErik * Play an item with a specific id in the play queue. If you specify an 667a66c40bf6e0fb79ead6d8a9fc29c5671fa7b1206RoboErik * id that is not in the play queue, the behavior is undefined. 668f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal */ 6693625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik public void skipToQueueItem(long id) { 670f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal try { 6713625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik mSessionBinder.skipToQueueItem(id); 672f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } catch (RemoteException e) { 673a66c40bf6e0fb79ead6d8a9fc29c5671fa7b1206RoboErik Log.wtf(TAG, "Error calling skipToItem(" + id + ").", e); 674f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 675f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 676f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 677f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal /** 678c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Request that the player pause its playback and stay at its current 679c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * position. 680c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 681c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void pause() { 682c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 683c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.pause(); 684c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 685c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling pause.", e); 686c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 687c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 688c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 689c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 690c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Request that the player stop its playback; it may clear its state in 691c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * whatever way is appropriate. 692c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 693c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void stop() { 694c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 695c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.stop(); 696c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 697c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling stop.", e); 698c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 699c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 700c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 701c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 702c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Move to a new location in the media stream. 703c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 704c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @param pos Position to move to, in milliseconds. 705c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 706c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void seekTo(long pos) { 707c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 708c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.seekTo(pos); 709c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 710c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling seekTo.", e); 711c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 712c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 713c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 714c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 715c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Start fast forwarding. If playback is already fast forwarding this 716c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * may increase the rate. 717c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 718c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void fastForward() { 719c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 720c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.fastForward(); 721c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 722c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling fastForward.", e); 723c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 724c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 725c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 726c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 727c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Skip to the next item. 728c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 729c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void skipToNext() { 730c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 731c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.next(); 732c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 733c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling next.", e); 734c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 735c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 736c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 737c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 738c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Start rewinding. If playback is already rewinding this may increase 739c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * the rate. 740c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 741c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void rewind() { 742c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 743c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.rewind(); 744c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 745c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling rewind.", e); 746c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 747c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 748c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 749c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 750c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Skip to the previous item. 751c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 752c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void skipToPrevious() { 753c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 754c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.previous(); 755c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 756c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling previous.", e); 757c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 758c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 759c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 760c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 761c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Rate the current content. This will cause the rating to be set for 762c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * the current user. The Rating type must match the type returned by 763c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * {@link #getRatingType()}. 764c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 765c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @param rating The rating to set for the current content 766c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 767c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void setRating(Rating rating) { 768c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 769c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.rate(rating); 770c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 771c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling rate.", e); 772c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 773c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 774f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal 775f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal /** 776f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * Send a custom action back for the {@link MediaSession} to perform. 777f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * 778f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * @param customAction The action to perform. 779f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * @param args Optional arguments to supply to the {@link MediaSession} for this 780f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * custom action. 781f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal */ 782f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal public void sendCustomAction(@NonNull PlaybackState.CustomAction customAction, 783f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal @Nullable Bundle args) { 784f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal if (customAction == null) { 785f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal throw new IllegalArgumentException("CustomAction cannot be null."); 786f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal } 787f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal sendCustomAction(customAction.getAction(), args); 788f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal } 789f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal 790f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal /** 791f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * Send the id and args from a custom action back for the {@link MediaSession} to perform. 792f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * 793f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * @see #sendCustomAction(PlaybackState.CustomAction action, Bundle args) 794f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * @param action The action identifier of the {@link PlaybackState.CustomAction} as 795f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * specified by the {@link MediaSession}. 796f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * @param args Optional arguments to supply to the {@link MediaSession} for this 797f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal * custom action. 798f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal */ 799f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal public void sendCustomAction(@NonNull String action, @Nullable Bundle args) { 800f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal if (TextUtils.isEmpty(action)) { 801f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal throw new IllegalArgumentException("CustomAction cannot be null."); 802f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal } 803f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal try { 804f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal mSessionBinder.sendCustomAction(action, args); 805f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal } catch (RemoteException e) { 806f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal Log.d(TAG, "Dead object in sendCustomAction.", e); 807f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal } 808f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal } 8098ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 81001fe661ae5da3739215d93922412df4b24c859a2RoboErik 811ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 812d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik * Holds information about the current playback and how audio is handled for 813d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik * this session. 814ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 815d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik public static final class PlaybackInfo { 816d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik /** 817d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik * The session uses remote playback. 818d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik */ 819d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik public static final int PLAYBACK_TYPE_REMOTE = 2; 820d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik /** 821d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik * The session uses local playback. 822d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik */ 823d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik public static final int PLAYBACK_TYPE_LOCAL = 1; 824d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik 825ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik private final int mVolumeType; 826ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik private final int mVolumeControl; 827ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik private final int mMaxVolume; 828ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik private final int mCurrentVolume; 8299db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik private final AudioAttributes mAudioAttrs; 830ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 831ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 832ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @hide 833ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 834d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik public PlaybackInfo(int type, AudioAttributes attrs, int control, int max, int current) { 835ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik mVolumeType = type; 8369db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik mAudioAttrs = attrs; 837ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik mVolumeControl = control; 838ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik mMaxVolume = max; 839ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik mCurrentVolume = current; 840ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 841ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 842ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 843d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik * Get the type of playback which affects volume handling. One of: 844ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * <ul> 845d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik * <li>{@link #PLAYBACK_TYPE_LOCAL}</li> 846d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik * <li>{@link #PLAYBACK_TYPE_REMOTE}</li> 847ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * </ul> 848ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 849d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik * @return The type of playback this session is using. 850ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 851d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik public int getPlaybackType() { 852ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return mVolumeType; 853ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 854ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 855ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 8569db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * Get the audio attributes for this session. The attributes will affect 8579db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * volume handling for the session. When the volume type is 858d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik * {@link PlaybackInfo#PLAYBACK_TYPE_REMOTE} these may be ignored by the 8599db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * remote volume handler. 860ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 8619db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik * @return The attributes for this session. 862ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 8639db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik public AudioAttributes getAudioAttributes() { 8649db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik return mAudioAttrs; 865ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 866ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 867ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 868ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Get the type of volume control that can be used. One of: 869ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * <ul> 870ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * <li>{@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}</li> 871ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * <li>{@link VolumeProvider#VOLUME_CONTROL_RELATIVE}</li> 872ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * <li>{@link VolumeProvider#VOLUME_CONTROL_FIXED}</li> 873ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * </ul> 874ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 875ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @return The type of volume control that may be used with this 876ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * session. 877ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 878ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik public int getVolumeControl() { 879ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return mVolumeControl; 880ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 881ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 882ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 883ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Get the maximum volume that may be set for this session. 884ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 885ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @return The maximum allowed volume where this session is playing. 886ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 887ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik public int getMaxVolume() { 888ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return mMaxVolume; 889ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 890ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 891ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 892ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Get the current volume for this session. 893ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 894ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @return The current volume where this session is playing. 895ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 896ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik public int getCurrentVolume() { 897ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return mCurrentVolume; 898ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 899ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 900ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 90107c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik private final static class CallbackStub extends ISessionControllerCallback.Stub { 90242ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik private final WeakReference<MediaController> mController; 90301fe661ae5da3739215d93922412df4b24c859a2RoboErik 90442ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik public CallbackStub(MediaController controller) { 90542ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik mController = new WeakReference<MediaController>(controller); 90601fe661ae5da3739215d93922412df4b24c859a2RoboErik } 90701fe661ae5da3739215d93922412df4b24c859a2RoboErik 90801fe661ae5da3739215d93922412df4b24c859a2RoboErik @Override 90924762bffc3358762666079cd802040a316b3260dRoboErik public void onSessionDestroyed() { 91024762bffc3358762666079cd802040a316b3260dRoboErik MediaController controller = mController.get(); 91124762bffc3358762666079cd802040a316b3260dRoboErik if (controller != null) { 91224762bffc3358762666079cd802040a316b3260dRoboErik controller.postMessage(MSG_DESTROYED, null, null); 91324762bffc3358762666079cd802040a316b3260dRoboErik } 91424762bffc3358762666079cd802040a316b3260dRoboErik } 91524762bffc3358762666079cd802040a316b3260dRoboErik 91624762bffc3358762666079cd802040a316b3260dRoboErik @Override 9178ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik public void onEvent(String event, Bundle extras) { 91842ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik MediaController controller = mController.get(); 9198ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (controller != null) { 920c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik controller.postMessage(MSG_EVENT, event, extras); 92101fe661ae5da3739215d93922412df4b24c859a2RoboErik } 92201fe661ae5da3739215d93922412df4b24c859a2RoboErik } 92301fe661ae5da3739215d93922412df4b24c859a2RoboErik 92401fe661ae5da3739215d93922412df4b24c859a2RoboErik @Override 9258ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik public void onPlaybackStateChanged(PlaybackState state) { 92642ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik MediaController controller = mController.get(); 9278ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (controller != null) { 928c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik controller.postMessage(MSG_UPDATE_PLAYBACK_STATE, state, null); 92901fe661ae5da3739215d93922412df4b24c859a2RoboErik } 93001fe661ae5da3739215d93922412df4b24c859a2RoboErik } 93101fe661ae5da3739215d93922412df4b24c859a2RoboErik 93201fe661ae5da3739215d93922412df4b24c859a2RoboErik @Override 9338ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik public void onMetadataChanged(MediaMetadata metadata) { 93442ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik MediaController controller = mController.get(); 9358ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (controller != null) { 936c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik controller.postMessage(MSG_UPDATE_METADATA, metadata, null); 93701fe661ae5da3739215d93922412df4b24c859a2RoboErik } 93801fe661ae5da3739215d93922412df4b24c859a2RoboErik } 93901fe661ae5da3739215d93922412df4b24c859a2RoboErik 94019c9518f6a817d53d5234de0020313cab6950b2fRoboErik @Override 941f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public void onQueueChanged(ParceledListSlice parceledQueue) { 94203fce072cac092923e10a6b5f09fcde333375f9eRoboErik List<MediaSession.QueueItem> queue = parceledQueue == null ? null : parceledQueue 94303fce072cac092923e10a6b5f09fcde333375f9eRoboErik .getList(); 944f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal MediaController controller = mController.get(); 945f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal if (controller != null) { 946f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal controller.postMessage(MSG_UPDATE_QUEUE, queue, null); 947f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 948f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 949f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 950f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal @Override 951f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public void onQueueTitleChanged(CharSequence title) { 952f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal MediaController controller = mController.get(); 953f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal if (controller != null) { 954f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal controller.postMessage(MSG_UPDATE_QUEUE_TITLE, title, null); 955f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 956f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 957f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 958f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal @Override 959f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal public void onExtrasChanged(Bundle extras) { 960f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal MediaController controller = mController.get(); 961f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal if (controller != null) { 962f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal controller.postMessage(MSG_UPDATE_EXTRAS, extras, null); 963f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 964f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal } 965f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal 966f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal @Override 96719c9518f6a817d53d5234de0020313cab6950b2fRoboErik public void onVolumeInfoChanged(ParcelableVolumeInfo pvi) { 96819c9518f6a817d53d5234de0020313cab6950b2fRoboErik MediaController controller = mController.get(); 96919c9518f6a817d53d5234de0020313cab6950b2fRoboErik if (controller != null) { 970d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik PlaybackInfo info = new PlaybackInfo(pvi.volumeType, pvi.audioAttrs, pvi.controlType, 97119c9518f6a817d53d5234de0020313cab6950b2fRoboErik pvi.maxVolume, pvi.currentVolume); 97219c9518f6a817d53d5234de0020313cab6950b2fRoboErik controller.postMessage(MSG_UPDATE_VOLUME, info, null); 97319c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 97419c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 97519c9518f6a817d53d5234de0020313cab6950b2fRoboErik 97601fe661ae5da3739215d93922412df4b24c859a2RoboErik } 97701fe661ae5da3739215d93922412df4b24c859a2RoboErik 97801fe661ae5da3739215d93922412df4b24c859a2RoboErik private final static class MessageHandler extends Handler { 97942ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik private final MediaController.Callback mCallback; 9803e0cfcda31301e53c92cb2f91ed8be1cd6efd8bcRoboErik private boolean mRegistered = false; 98101fe661ae5da3739215d93922412df4b24c859a2RoboErik 98242ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik public MessageHandler(Looper looper, MediaController.Callback cb) { 9838ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik super(looper, null, true); 9848ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik mCallback = cb; 98501fe661ae5da3739215d93922412df4b24c859a2RoboErik } 98601fe661ae5da3739215d93922412df4b24c859a2RoboErik 98701fe661ae5da3739215d93922412df4b24c859a2RoboErik @Override 98801fe661ae5da3739215d93922412df4b24c859a2RoboErik public void handleMessage(Message msg) { 9893e0cfcda31301e53c92cb2f91ed8be1cd6efd8bcRoboErik if (!mRegistered) { 9903e0cfcda31301e53c92cb2f91ed8be1cd6efd8bcRoboErik return; 9913e0cfcda31301e53c92cb2f91ed8be1cd6efd8bcRoboErik } 99201fe661ae5da3739215d93922412df4b24c859a2RoboErik switch (msg.what) { 9938ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik case MSG_EVENT: 99479fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik mCallback.onSessionEvent((String) msg.obj, msg.getData()); 99501fe661ae5da3739215d93922412df4b24c859a2RoboErik break; 996c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik case MSG_UPDATE_PLAYBACK_STATE: 997c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mCallback.onPlaybackStateChanged((PlaybackState) msg.obj); 998c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik break; 999c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik case MSG_UPDATE_METADATA: 1000c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mCallback.onMetadataChanged((MediaMetadata) msg.obj); 1001c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik break; 1002f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal case MSG_UPDATE_QUEUE: 10033625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik mCallback.onQueueChanged((List<MediaSession.QueueItem>) msg.obj); 1004f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal break; 1005f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal case MSG_UPDATE_QUEUE_TITLE: 1006f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal mCallback.onQueueTitleChanged((CharSequence) msg.obj); 1007f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal break; 1008f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal case MSG_UPDATE_EXTRAS: 1009f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal mCallback.onExtrasChanged((Bundle) msg.obj); 1010f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal break; 101119c9518f6a817d53d5234de0020313cab6950b2fRoboErik case MSG_UPDATE_VOLUME: 1012d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik mCallback.onAudioInfoChanged((PlaybackInfo) msg.obj); 101319c9518f6a817d53d5234de0020313cab6950b2fRoboErik break; 101424762bffc3358762666079cd802040a316b3260dRoboErik case MSG_DESTROYED: 101524762bffc3358762666079cd802040a316b3260dRoboErik mCallback.onSessionDestroyed(); 101624762bffc3358762666079cd802040a316b3260dRoboErik break; 101701fe661ae5da3739215d93922412df4b24c859a2RoboErik } 101801fe661ae5da3739215d93922412df4b24c859a2RoboErik } 10198ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik 10208ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik public void post(int what, Object obj, Bundle data) { 1021060b4e1f17db00c8cfb25f4d81726c37d580f723Sungsoo Lim Message msg = obtainMessage(what, obj); 1022060b4e1f17db00c8cfb25f4d81726c37d580f723Sungsoo Lim msg.setData(data); 1023060b4e1f17db00c8cfb25f4d81726c37d580f723Sungsoo Lim msg.sendToTarget(); 10248ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 102501fe661ae5da3739215d93922412df4b24c859a2RoboErik } 102601fe661ae5da3739215d93922412df4b24c859a2RoboErik 102701fe661ae5da3739215d93922412df4b24c859a2RoboErik} 1028