MediaController.java revision dba34ba35cd2042d9a8fecfda56e2abe7a680bad
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; 2119c9518f6a817d53d5234de0020313cab6950b2fRoboErikimport android.media.AudioManager; 2242ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErikimport android.media.MediaMetadata; 23c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErikimport android.media.Rating; 24ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErikimport android.media.VolumeProvider; 2501fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.os.Bundle; 2601fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.os.Handler; 2701fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.os.Looper; 2801fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.os.Message; 2901fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.os.RemoteException; 308ae0f34db936a649ddaf9cdd086c224f6514efebRoboErikimport android.os.ResultReceiver; 3101fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.text.TextUtils; 3201fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.util.Log; 3301fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.view.KeyEvent; 3401fe661ae5da3739215d93922412df4b24c859a2RoboErik 358ae0f34db936a649ddaf9cdd086c224f6514efebRoboErikimport java.lang.ref.WeakReference; 3601fe661ae5da3739215d93922412df4b24c859a2RoboErikimport java.util.ArrayList; 3701fe661ae5da3739215d93922412df4b24c859a2RoboErik 3801fe661ae5da3739215d93922412df4b24c859a2RoboErik/** 3901fe661ae5da3739215d93922412df4b24c859a2RoboErik * Allows an app to interact with an ongoing media session. Media buttons and 4001fe661ae5da3739215d93922412df4b24c859a2RoboErik * other commands can be sent to the session. A callback may be registered to 4101fe661ae5da3739215d93922412df4b24c859a2RoboErik * receive updates from the session, such as metadata and play state changes. 4201fe661ae5da3739215d93922412df4b24c859a2RoboErik * <p> 4342ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik * A MediaController can be created through {@link MediaSessionManager} if you 4401fe661ae5da3739215d93922412df4b24c859a2RoboErik * hold the "android.permission.MEDIA_CONTENT_CONTROL" permission or directly if 45dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown * you have a {@link MediaSession.Token} from the session owner. 4601fe661ae5da3739215d93922412df4b24c859a2RoboErik * <p> 4701fe661ae5da3739215d93922412df4b24c859a2RoboErik * MediaController objects are thread-safe. 4801fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 4942ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErikpublic final class MediaController { 50bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown private static final String TAG = "MediaController"; 5101fe661ae5da3739215d93922412df4b24c859a2RoboErik 528ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik private static final int MSG_EVENT = 1; 53c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik private static final int MSG_UPDATE_PLAYBACK_STATE = 2; 54c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik private static final int MSG_UPDATE_METADATA = 3; 558ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik private static final int MSG_ROUTE = 4; 5619c9518f6a817d53d5234de0020313cab6950b2fRoboErik private static final int MSG_UPDATE_VOLUME = 5; 5701fe661ae5da3739215d93922412df4b24c859a2RoboErik 5807c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik private final ISessionController mSessionBinder; 5901fe661ae5da3739215d93922412df4b24c859a2RoboErik 608ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik private final CallbackStub mCbStub = new CallbackStub(this); 618ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik private final ArrayList<MessageHandler> mCallbacks = new ArrayList<MessageHandler>(); 6201fe661ae5da3739215d93922412df4b24c859a2RoboErik private final Object mLock = new Object(); 6301fe661ae5da3739215d93922412df4b24c859a2RoboErik 6401fe661ae5da3739215d93922412df4b24c859a2RoboErik private boolean mCbRegistered = false; 6573e23e229dd1a2d25687b1c6a63c708665378e41RoboErik private MediaSessionInfo mInfo; 6601fe661ae5da3739215d93922412df4b24c859a2RoboErik 67c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik private TransportControls mTransportController; 688ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik 6942ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik private MediaController(ISessionController sessionBinder) { 708ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik mSessionBinder = sessionBinder; 71c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mTransportController = new TransportControls(); 728ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 738ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik 7401fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 758ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * @hide 7601fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 7742ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik public static MediaController fromBinder(ISessionController sessionBinder) { 78d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik return new MediaController(sessionBinder); 7901fe661ae5da3739215d93922412df4b24c859a2RoboErik } 8001fe661ae5da3739215d93922412df4b24c859a2RoboErik 8101fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 82bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * Get a new media controller from a session token which may have 83bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * been obtained from another process. If successful the controller returned 84bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * will be connected to the session that generated the token. 858ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * 86bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * @param token The session token to control. 87bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * @return A controller for the session or null if inaccessible. 8801fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 89dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown public static MediaController fromToken(@NonNull MediaSession.Token token) { 908ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik return fromBinder(token.getBinder()); 9101fe661ae5da3739215d93922412df4b24c859a2RoboErik } 9201fe661ae5da3739215d93922412df4b24c859a2RoboErik 9301fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 94c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Get a {@link TransportControls} instance for this session. 9501fe661ae5da3739215d93922412df4b24c859a2RoboErik * 96c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @return A controls instance 9701fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 98bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public @NonNull TransportControls getTransportControls() { 998ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik return mTransportController; 10001fe661ae5da3739215d93922412df4b24c859a2RoboErik } 10101fe661ae5da3739215d93922412df4b24c859a2RoboErik 10201fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 10379fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik * Send the specified media button event to the session. Only media keys can 10479fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik * be sent by this method, other keys will be ignored. 10501fe661ae5da3739215d93922412df4b24c859a2RoboErik * 10679fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik * @param keyEvent The media button event to dispatch. 10779fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik * @return true if the event was sent to the session, false otherwise. 10801fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 109bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public boolean dispatchMediaButtonEvent(@NonNull KeyEvent keyEvent) { 11079fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik if (keyEvent == null) { 11179fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik throw new IllegalArgumentException("KeyEvent may not be null"); 11279fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik } 11379fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik if (!KeyEvent.isMediaKey(keyEvent.getKeyCode())) { 11479fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik return false; 11501fe661ae5da3739215d93922412df4b24c859a2RoboErik } 11601fe661ae5da3739215d93922412df4b24c859a2RoboErik try { 11779fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik return mSessionBinder.sendMediaButton(keyEvent); 11801fe661ae5da3739215d93922412df4b24c859a2RoboErik } catch (RemoteException e) { 119c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik // System is dead. =( 12001fe661ae5da3739215d93922412df4b24c859a2RoboErik } 12179fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik return false; 12201fe661ae5da3739215d93922412df4b24c859a2RoboErik } 12301fe661ae5da3739215d93922412df4b24c859a2RoboErik 12401fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 125c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Get the current playback state for this session. 126c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 127c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @return The current PlaybackState or null 128c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 129bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public @Nullable PlaybackState getPlaybackState() { 130c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 131c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return mSessionBinder.getPlaybackState(); 132c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 133c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling getPlaybackState.", e); 134c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return null; 135c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 136c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 137c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 138c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 139c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Get the current metadata for this session. 140c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 141c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @return The current MediaMetadata or null. 142c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 143bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public @Nullable MediaMetadata getMetadata() { 144c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 145c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return mSessionBinder.getMetadata(); 146c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 147c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling getMetadata.", e); 148c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return null; 149c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 150c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 151c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 152c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 153c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Get the rating type supported by the session. One of: 154c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <ul> 155c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_NONE}</li> 156c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_HEART}</li> 157c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_THUMB_UP_DOWN}</li> 158c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_3_STARS}</li> 159c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_4_STARS}</li> 160c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_5_STARS}</li> 161c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_PERCENTAGE}</li> 162c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * </ul> 163c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 164c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @return The supported rating type 165c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 166c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public int getRatingType() { 167c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 168c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return mSessionBinder.getRatingType(); 169c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 170c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling getRatingType.", e); 171c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return Rating.RATING_NONE; 172c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 173c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 174c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 175c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 17673e23e229dd1a2d25687b1c6a63c708665378e41RoboErik * Get the flags for this session. 17773e23e229dd1a2d25687b1c6a63c708665378e41RoboErik * 17873e23e229dd1a2d25687b1c6a63c708665378e41RoboErik * @return The current set of flags for the session. 17973e23e229dd1a2d25687b1c6a63c708665378e41RoboErik * @hide 18073e23e229dd1a2d25687b1c6a63c708665378e41RoboErik */ 18173e23e229dd1a2d25687b1c6a63c708665378e41RoboErik public long getFlags() { 18273e23e229dd1a2d25687b1c6a63c708665378e41RoboErik try { 18373e23e229dd1a2d25687b1c6a63c708665378e41RoboErik return mSessionBinder.getFlags(); 18473e23e229dd1a2d25687b1c6a63c708665378e41RoboErik } catch (RemoteException e) { 18573e23e229dd1a2d25687b1c6a63c708665378e41RoboErik Log.wtf(TAG, "Error calling getFlags.", e); 18673e23e229dd1a2d25687b1c6a63c708665378e41RoboErik } 18773e23e229dd1a2d25687b1c6a63c708665378e41RoboErik return 0; 18873e23e229dd1a2d25687b1c6a63c708665378e41RoboErik } 18973e23e229dd1a2d25687b1c6a63c708665378e41RoboErik 19073e23e229dd1a2d25687b1c6a63c708665378e41RoboErik /** 191ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Get the current volume info for this session. 192ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 193ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @return The current volume info or null. 194ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 195bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public @Nullable VolumeInfo getVolumeInfo() { 196ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik try { 197ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik ParcelableVolumeInfo result = mSessionBinder.getVolumeAttributes(); 198ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return new VolumeInfo(result.volumeType, result.audioStream, result.controlType, 199ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik result.maxVolume, result.currentVolume); 200ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 201ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } catch (RemoteException e) { 202ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik Log.wtf(TAG, "Error calling getVolumeInfo.", e); 203ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 204ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return null; 205ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 206ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 207ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 20819c9518f6a817d53d5234de0020313cab6950b2fRoboErik * Set the volume of the stream or output this session is playing on. The 20919c9518f6a817d53d5234de0020313cab6950b2fRoboErik * command will be ignored if it does not support 21019c9518f6a817d53d5234de0020313cab6950b2fRoboErik * {@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}. The flags in 21119c9518f6a817d53d5234de0020313cab6950b2fRoboErik * {@link AudioManager} may be used to affect the handling. 21219c9518f6a817d53d5234de0020313cab6950b2fRoboErik * 21319c9518f6a817d53d5234de0020313cab6950b2fRoboErik * @see #getVolumeInfo() 21419c9518f6a817d53d5234de0020313cab6950b2fRoboErik * @param value The value to set it to, between 0 and the reported max. 21519c9518f6a817d53d5234de0020313cab6950b2fRoboErik * @param flags Any flags to pass with the command. 21619c9518f6a817d53d5234de0020313cab6950b2fRoboErik */ 21719c9518f6a817d53d5234de0020313cab6950b2fRoboErik public void setVolumeTo(int value, int flags) { 21819c9518f6a817d53d5234de0020313cab6950b2fRoboErik try { 21919c9518f6a817d53d5234de0020313cab6950b2fRoboErik mSessionBinder.setVolumeTo(value, flags); 22019c9518f6a817d53d5234de0020313cab6950b2fRoboErik } catch (RemoteException e) { 22119c9518f6a817d53d5234de0020313cab6950b2fRoboErik Log.wtf(TAG, "Error calling setVolumeTo.", e); 22219c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 22319c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 22419c9518f6a817d53d5234de0020313cab6950b2fRoboErik 22519c9518f6a817d53d5234de0020313cab6950b2fRoboErik /** 22619c9518f6a817d53d5234de0020313cab6950b2fRoboErik * Adjust the volume of the stream or output this session is playing on. 22719c9518f6a817d53d5234de0020313cab6950b2fRoboErik * Negative values will lower the volume. The command will be ignored if it 22819c9518f6a817d53d5234de0020313cab6950b2fRoboErik * does not support {@link VolumeProvider#VOLUME_CONTROL_RELATIVE} or 22919c9518f6a817d53d5234de0020313cab6950b2fRoboErik * {@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}. The flags in 23019c9518f6a817d53d5234de0020313cab6950b2fRoboErik * {@link AudioManager} may be used to affect the handling. 23119c9518f6a817d53d5234de0020313cab6950b2fRoboErik * 23219c9518f6a817d53d5234de0020313cab6950b2fRoboErik * @see #getVolumeInfo() 23319c9518f6a817d53d5234de0020313cab6950b2fRoboErik * @param delta The number of steps to adjust the volume by. 23419c9518f6a817d53d5234de0020313cab6950b2fRoboErik * @param flags Any flags to pass with the command. 23519c9518f6a817d53d5234de0020313cab6950b2fRoboErik */ 23619c9518f6a817d53d5234de0020313cab6950b2fRoboErik public void adjustVolumeBy(int delta, int flags) { 23719c9518f6a817d53d5234de0020313cab6950b2fRoboErik try { 23819c9518f6a817d53d5234de0020313cab6950b2fRoboErik mSessionBinder.adjustVolumeBy(delta, flags); 23919c9518f6a817d53d5234de0020313cab6950b2fRoboErik } catch (RemoteException e) { 24019c9518f6a817d53d5234de0020313cab6950b2fRoboErik Log.wtf(TAG, "Error calling adjustVolumeBy.", e); 24119c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 24219c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 24319c9518f6a817d53d5234de0020313cab6950b2fRoboErik 24419c9518f6a817d53d5234de0020313cab6950b2fRoboErik /** 24501fe661ae5da3739215d93922412df4b24c859a2RoboErik * Adds a callback to receive updates from the Session. Updates will be 24601fe661ae5da3739215d93922412df4b24c859a2RoboErik * posted on the caller's thread. 24701fe661ae5da3739215d93922412df4b24c859a2RoboErik * 248bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * @param callback The callback object, must not be null. 24901fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 250bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public void addCallback(@NonNull Callback callback) { 251bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown addCallback(callback, null); 25201fe661ae5da3739215d93922412df4b24c859a2RoboErik } 25301fe661ae5da3739215d93922412df4b24c859a2RoboErik 25401fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 25501fe661ae5da3739215d93922412df4b24c859a2RoboErik * Adds a callback to receive updates from the session. Updates will be 2568ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * posted on the specified handler's thread. 25701fe661ae5da3739215d93922412df4b24c859a2RoboErik * 258bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * @param callback The callback object, must not be null. 2598ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * @param handler The handler to post updates on. If null the callers thread 260bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * will be used. 26101fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 262bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public void addCallback(@NonNull Callback callback, @Nullable Handler handler) { 263bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown if (callback == null) { 264bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown throw new IllegalArgumentException("callback must not be null"); 265bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown } 26601fe661ae5da3739215d93922412df4b24c859a2RoboErik if (handler == null) { 26701fe661ae5da3739215d93922412df4b24c859a2RoboErik handler = new Handler(); 26801fe661ae5da3739215d93922412df4b24c859a2RoboErik } 26901fe661ae5da3739215d93922412df4b24c859a2RoboErik synchronized (mLock) { 270bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown addCallbackLocked(callback, handler); 27101fe661ae5da3739215d93922412df4b24c859a2RoboErik } 27201fe661ae5da3739215d93922412df4b24c859a2RoboErik } 27301fe661ae5da3739215d93922412df4b24c859a2RoboErik 27401fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 27501fe661ae5da3739215d93922412df4b24c859a2RoboErik * Stop receiving updates on the specified callback. If an update has 27601fe661ae5da3739215d93922412df4b24c859a2RoboErik * already been posted you may still receive it after calling this method. 27701fe661ae5da3739215d93922412df4b24c859a2RoboErik * 278bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * @param callback The callback to remove. 27901fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 280bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public void removeCallback(@NonNull Callback callback) { 281bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown if (callback == null) { 282bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown throw new IllegalArgumentException("callback must not be null"); 283bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown } 28401fe661ae5da3739215d93922412df4b24c859a2RoboErik synchronized (mLock) { 285bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown removeCallbackLocked(callback); 28601fe661ae5da3739215d93922412df4b24c859a2RoboErik } 28701fe661ae5da3739215d93922412df4b24c859a2RoboErik } 28801fe661ae5da3739215d93922412df4b24c859a2RoboErik 2898ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik /** 2908ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * Sends a generic command to the session. It is up to the session creator 2918ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * to decide what commands and parameters they will support. As such, 2928ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * commands should only be sent to sessions that the controller owns. 2938ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * 2948ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * @param command The command to send 2958ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * @param params Any parameters to include with the command 2968ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * @param cb The callback to receive the result on 2978ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik */ 298bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public void sendControlCommand(@NonNull String command, @Nullable Bundle params, 299bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown @Nullable ResultReceiver cb) { 3008ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (TextUtils.isEmpty(command)) { 3018ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik throw new IllegalArgumentException("command cannot be null or empty"); 3028ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 3038ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik try { 3048ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik mSessionBinder.sendCommand(command, params, cb); 3058ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } catch (RemoteException e) { 3068ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik Log.d(TAG, "Dead object in sendCommand.", e); 3078ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 3088ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 3098ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik 31007c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik /** 31107c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik * Request that the route picker be shown for this session. This should 31207c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik * generally be called in response to a user action. 31342ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik * 31442ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik * @hide 31507c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik */ 31607c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik public void showRoutePicker() { 31707c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik try { 31807c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik mSessionBinder.showRoutePicker(); 31907c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik } catch (RemoteException e) { 32007c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik Log.d(TAG, "Dead object in showRoutePicker", e); 32107c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik } 32207c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik } 32307c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik 324fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik /** 325fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik * Get the info for the session this controller is connected to. 326fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik * 327fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik * @return The session info for the connected session. 328fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik * @hide 329fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik */ 330fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik public MediaSessionInfo getSessionInfo() { 33173e23e229dd1a2d25687b1c6a63c708665378e41RoboErik if (mInfo == null) { 33273e23e229dd1a2d25687b1c6a63c708665378e41RoboErik try { 33373e23e229dd1a2d25687b1c6a63c708665378e41RoboErik mInfo = mSessionBinder.getSessionInfo(); 33473e23e229dd1a2d25687b1c6a63c708665378e41RoboErik } catch (RemoteException e) { 33573e23e229dd1a2d25687b1c6a63c708665378e41RoboErik Log.e(TAG, "Error in getSessionInfo.", e); 33673e23e229dd1a2d25687b1c6a63c708665378e41RoboErik } 337fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik } 33873e23e229dd1a2d25687b1c6a63c708665378e41RoboErik return mInfo; 339fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik } 340fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik 34101fe661ae5da3739215d93922412df4b24c859a2RoboErik /* 34201fe661ae5da3739215d93922412df4b24c859a2RoboErik * @hide 34301fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 34407c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik ISessionController getSessionBinder() { 34501fe661ae5da3739215d93922412df4b24c859a2RoboErik return mSessionBinder; 34601fe661ae5da3739215d93922412df4b24c859a2RoboErik } 34701fe661ae5da3739215d93922412df4b24c859a2RoboErik 34801fe661ae5da3739215d93922412df4b24c859a2RoboErik private void addCallbackLocked(Callback cb, Handler handler) { 3498ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (getHandlerForCallbackLocked(cb) != null) { 35001fe661ae5da3739215d93922412df4b24c859a2RoboErik Log.w(TAG, "Callback is already added, ignoring"); 35101fe661ae5da3739215d93922412df4b24c859a2RoboErik return; 35201fe661ae5da3739215d93922412df4b24c859a2RoboErik } 3538ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik MessageHandler holder = new MessageHandler(handler.getLooper(), cb); 3548ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik mCallbacks.add(holder); 35501fe661ae5da3739215d93922412df4b24c859a2RoboErik 35601fe661ae5da3739215d93922412df4b24c859a2RoboErik if (!mCbRegistered) { 35701fe661ae5da3739215d93922412df4b24c859a2RoboErik try { 35801fe661ae5da3739215d93922412df4b24c859a2RoboErik mSessionBinder.registerCallbackListener(mCbStub); 35901fe661ae5da3739215d93922412df4b24c859a2RoboErik mCbRegistered = true; 36001fe661ae5da3739215d93922412df4b24c859a2RoboErik } catch (RemoteException e) { 361d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik Log.e(TAG, "Dead object in registerCallback", e); 36201fe661ae5da3739215d93922412df4b24c859a2RoboErik } 36301fe661ae5da3739215d93922412df4b24c859a2RoboErik } 36401fe661ae5da3739215d93922412df4b24c859a2RoboErik } 36501fe661ae5da3739215d93922412df4b24c859a2RoboErik 3668ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik private boolean removeCallbackLocked(Callback cb) { 367d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik boolean success = false; 3688ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik for (int i = mCallbacks.size() - 1; i >= 0; i--) { 3698ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik MessageHandler handler = mCallbacks.get(i); 3708ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (cb == handler.mCallback) { 3718ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik mCallbacks.remove(i); 372d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik success = true; 37301fe661ae5da3739215d93922412df4b24c859a2RoboErik } 37401fe661ae5da3739215d93922412df4b24c859a2RoboErik } 375d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik if (mCbRegistered && mCallbacks.size() == 0) { 376d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik try { 377d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik mSessionBinder.unregisterCallbackListener(mCbStub); 378d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik } catch (RemoteException e) { 379d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik Log.e(TAG, "Dead object in removeCallbackLocked"); 380d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik } 381d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik mCbRegistered = false; 382d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik } 383d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik return success; 38401fe661ae5da3739215d93922412df4b24c859a2RoboErik } 38501fe661ae5da3739215d93922412df4b24c859a2RoboErik 3868ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik private MessageHandler getHandlerForCallbackLocked(Callback cb) { 3878ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (cb == null) { 3888ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik throw new IllegalArgumentException("Callback cannot be null"); 38901fe661ae5da3739215d93922412df4b24c859a2RoboErik } 3908ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik for (int i = mCallbacks.size() - 1; i >= 0; i--) { 3918ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik MessageHandler handler = mCallbacks.get(i); 3928ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (cb == handler.mCallback) { 3938ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik return handler; 3948ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 39501fe661ae5da3739215d93922412df4b24c859a2RoboErik } 3968ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik return null; 39701fe661ae5da3739215d93922412df4b24c859a2RoboErik } 39801fe661ae5da3739215d93922412df4b24c859a2RoboErik 399c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik private final void postMessage(int what, Object obj, Bundle data) { 4008ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik synchronized (mLock) { 4018ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik for (int i = mCallbacks.size() - 1; i >= 0; i--) { 402c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mCallbacks.get(i).post(what, obj, data); 4038ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 40401fe661ae5da3739215d93922412df4b24c859a2RoboErik } 40501fe661ae5da3739215d93922412df4b24c859a2RoboErik } 40601fe661ae5da3739215d93922412df4b24c859a2RoboErik 40701fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 4088ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * Callback for receiving updates on from the session. A Callback can be 4098ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * registered using {@link #addCallback} 41001fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 41101fe661ae5da3739215d93922412df4b24c859a2RoboErik public static abstract class Callback { 41201fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 4138ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * Override to handle custom events sent by the session owner without a 4148ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * specified interface. Controllers should only handle these for 4158ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * sessions they own. 41601fe661ae5da3739215d93922412df4b24c859a2RoboErik * 417bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * @param event The event from the session. 418bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * @param extras Optional parameters for the event, may be null. 41901fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 420bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public void onSessionEvent(@NonNull String event, @Nullable Bundle extras) { 42101fe661ae5da3739215d93922412df4b24c859a2RoboErik } 42201fe661ae5da3739215d93922412df4b24c859a2RoboErik 42301fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 42401fe661ae5da3739215d93922412df4b24c859a2RoboErik * Override to handle route changes for this session. 42501fe661ae5da3739215d93922412df4b24c859a2RoboErik * 42642ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik * @param route The new route 42742ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik * @hide 42801fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 42907c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik public void onRouteChanged(RouteInfo route) { 43001fe661ae5da3739215d93922412df4b24c859a2RoboErik } 431c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 432c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 433c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Override to handle changes in playback state. 434c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 435c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @param state The new playback state of the session 436c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 437bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public void onPlaybackStateChanged(@NonNull PlaybackState state) { 438c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 439c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 440c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 441c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Override to handle changes to the current metadata. 442c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 443bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown * @param metadata The current metadata for the session or null if none. 444c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @see MediaMetadata 445c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 446bf58d9b727f1007c7c620f622ac1d8003b1b211bJeff Brown public void onMetadataChanged(@Nullable MediaMetadata metadata) { 447c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 44819c9518f6a817d53d5234de0020313cab6950b2fRoboErik 44919c9518f6a817d53d5234de0020313cab6950b2fRoboErik /** 45019c9518f6a817d53d5234de0020313cab6950b2fRoboErik * Override to handle changes to the volume info. 45119c9518f6a817d53d5234de0020313cab6950b2fRoboErik * 45219c9518f6a817d53d5234de0020313cab6950b2fRoboErik * @param info The current volume info for this session. 45319c9518f6a817d53d5234de0020313cab6950b2fRoboErik */ 45419c9518f6a817d53d5234de0020313cab6950b2fRoboErik public void onVolumeInfoChanged(VolumeInfo info) { 45519c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 456c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 457c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 458c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 459c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Interface for controlling media playback on a session. This allows an app 460c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * to send media transport commands to the session. 461c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 462c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public final class TransportControls { 463c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik private static final String TAG = "TransportController"; 464c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 465c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik private TransportControls() { 466c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 467c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 468c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 469c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Request that the player start its playback at its current position. 470c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 471c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void play() { 472c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 473c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.play(); 474c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 475c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling play.", e); 476c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 477c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 478c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 479c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 480c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Request that the player pause its playback and stay at its current 481c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * position. 482c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 483c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void pause() { 484c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 485c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.pause(); 486c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 487c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling pause.", e); 488c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 489c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 490c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 491c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 492c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Request that the player stop its playback; it may clear its state in 493c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * whatever way is appropriate. 494c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 495c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void stop() { 496c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 497c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.stop(); 498c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 499c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling stop.", e); 500c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 501c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 502c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 503c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 504c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Move to a new location in the media stream. 505c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 506c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @param pos Position to move to, in milliseconds. 507c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 508c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void seekTo(long pos) { 509c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 510c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.seekTo(pos); 511c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 512c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling seekTo.", e); 513c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 514c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 515c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 516c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 517c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Start fast forwarding. If playback is already fast forwarding this 518c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * may increase the rate. 519c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 520c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void fastForward() { 521c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 522c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.fastForward(); 523c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 524c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling fastForward.", e); 525c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 526c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 527c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 528c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 529c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Skip to the next item. 530c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 531c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void skipToNext() { 532c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 533c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.next(); 534c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 535c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling next.", e); 536c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 537c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 538c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 539c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 540c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Start rewinding. If playback is already rewinding this may increase 541c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * the rate. 542c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 543c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void rewind() { 544c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 545c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.rewind(); 546c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 547c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling rewind.", e); 548c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 549c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 550c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 551c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 552c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Skip to the previous item. 553c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 554c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void skipToPrevious() { 555c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 556c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.previous(); 557c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 558c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling previous.", e); 559c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 560c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 561c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 562c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 563c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Rate the current content. This will cause the rating to be set for 564c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * the current user. The Rating type must match the type returned by 565c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * {@link #getRatingType()}. 566c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 567c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @param rating The rating to set for the current content 568c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 569c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void setRating(Rating rating) { 570c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 571c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.rate(rating); 572c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 573c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling rate.", e); 574c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 575c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 5768ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 57701fe661ae5da3739215d93922412df4b24c859a2RoboErik 578ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 579ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Holds information about the way volume is handled for this session. 580ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 581ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik public static final class VolumeInfo { 582ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik private final int mVolumeType; 583ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik private final int mAudioStream; 584ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik private final int mVolumeControl; 585ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik private final int mMaxVolume; 586ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik private final int mCurrentVolume; 587ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 588ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 589ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @hide 590ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 591ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik public VolumeInfo(int type, int stream, int control, int max, int current) { 592ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik mVolumeType = type; 593ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik mAudioStream = stream; 594ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik mVolumeControl = control; 595ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik mMaxVolume = max; 596ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik mCurrentVolume = current; 597ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 598ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 599ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 600ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Get the type of volume handling, either local or remote. One of: 601ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * <ul> 60219c9518f6a817d53d5234de0020313cab6950b2fRoboErik * <li>{@link MediaSession#PLAYBACK_TYPE_LOCAL}</li> 60319c9518f6a817d53d5234de0020313cab6950b2fRoboErik * <li>{@link MediaSession#PLAYBACK_TYPE_REMOTE}</li> 604ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * </ul> 605ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 606ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @return The type of volume handling this session is using. 607ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 608ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik public int getVolumeType() { 609ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return mVolumeType; 610ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 611ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 612ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 613ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Get the stream this is currently controlling volume on. When the volume 61419c9518f6a817d53d5234de0020313cab6950b2fRoboErik * type is {@link MediaSession#PLAYBACK_TYPE_REMOTE} this value does not 615ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * have meaning and should be ignored. 616ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 617ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @return The stream this session is playing on. 618ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 619ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik public int getAudioStream() { 620ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return mAudioStream; 621ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 622ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 623ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 624ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Get the type of volume control that can be used. One of: 625ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * <ul> 626ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * <li>{@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}</li> 627ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * <li>{@link VolumeProvider#VOLUME_CONTROL_RELATIVE}</li> 628ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * <li>{@link VolumeProvider#VOLUME_CONTROL_FIXED}</li> 629ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * </ul> 630ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 631ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @return The type of volume control that may be used with this 632ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * session. 633ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 634ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik public int getVolumeControl() { 635ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return mVolumeControl; 636ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 637ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 638ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 639ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Get the maximum volume that may be set for this session. 640ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 641ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @return The maximum allowed volume where this session is playing. 642ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 643ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik public int getMaxVolume() { 644ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return mMaxVolume; 645ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 646ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 647ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 648ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Get the current volume for this session. 649ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 650ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @return The current volume where this session is playing. 651ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 652ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik public int getCurrentVolume() { 653ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return mCurrentVolume; 654ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 655ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 656ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 65707c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik private final static class CallbackStub extends ISessionControllerCallback.Stub { 65842ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik private final WeakReference<MediaController> mController; 65901fe661ae5da3739215d93922412df4b24c859a2RoboErik 66042ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik public CallbackStub(MediaController controller) { 66142ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik mController = new WeakReference<MediaController>(controller); 66201fe661ae5da3739215d93922412df4b24c859a2RoboErik } 66301fe661ae5da3739215d93922412df4b24c859a2RoboErik 66401fe661ae5da3739215d93922412df4b24c859a2RoboErik @Override 6658ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik public void onEvent(String event, Bundle extras) { 66642ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik MediaController controller = mController.get(); 6678ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (controller != null) { 668c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik controller.postMessage(MSG_EVENT, event, extras); 66901fe661ae5da3739215d93922412df4b24c859a2RoboErik } 67001fe661ae5da3739215d93922412df4b24c859a2RoboErik } 67101fe661ae5da3739215d93922412df4b24c859a2RoboErik 67201fe661ae5da3739215d93922412df4b24c859a2RoboErik @Override 67307c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik public void onRouteChanged(RouteInfo route) { 67442ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik MediaController controller = mController.get(); 6758ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (controller != null) { 676c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik controller.postMessage(MSG_ROUTE, route, null); 67701fe661ae5da3739215d93922412df4b24c859a2RoboErik } 67801fe661ae5da3739215d93922412df4b24c859a2RoboErik } 67901fe661ae5da3739215d93922412df4b24c859a2RoboErik 68001fe661ae5da3739215d93922412df4b24c859a2RoboErik @Override 6818ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik public void onPlaybackStateChanged(PlaybackState state) { 68242ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik MediaController controller = mController.get(); 6838ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (controller != null) { 684c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik controller.postMessage(MSG_UPDATE_PLAYBACK_STATE, state, null); 68501fe661ae5da3739215d93922412df4b24c859a2RoboErik } 68601fe661ae5da3739215d93922412df4b24c859a2RoboErik } 68701fe661ae5da3739215d93922412df4b24c859a2RoboErik 68801fe661ae5da3739215d93922412df4b24c859a2RoboErik @Override 6898ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik public void onMetadataChanged(MediaMetadata metadata) { 69042ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik MediaController controller = mController.get(); 6918ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (controller != null) { 692c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik controller.postMessage(MSG_UPDATE_METADATA, metadata, null); 69301fe661ae5da3739215d93922412df4b24c859a2RoboErik } 69401fe661ae5da3739215d93922412df4b24c859a2RoboErik } 69501fe661ae5da3739215d93922412df4b24c859a2RoboErik 69619c9518f6a817d53d5234de0020313cab6950b2fRoboErik @Override 69719c9518f6a817d53d5234de0020313cab6950b2fRoboErik public void onVolumeInfoChanged(ParcelableVolumeInfo pvi) { 69819c9518f6a817d53d5234de0020313cab6950b2fRoboErik MediaController controller = mController.get(); 69919c9518f6a817d53d5234de0020313cab6950b2fRoboErik if (controller != null) { 70019c9518f6a817d53d5234de0020313cab6950b2fRoboErik VolumeInfo info = new VolumeInfo(pvi.volumeType, pvi.audioStream, pvi.controlType, 70119c9518f6a817d53d5234de0020313cab6950b2fRoboErik pvi.maxVolume, pvi.currentVolume); 70219c9518f6a817d53d5234de0020313cab6950b2fRoboErik controller.postMessage(MSG_UPDATE_VOLUME, info, null); 70319c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 70419c9518f6a817d53d5234de0020313cab6950b2fRoboErik } 70519c9518f6a817d53d5234de0020313cab6950b2fRoboErik 70601fe661ae5da3739215d93922412df4b24c859a2RoboErik } 70701fe661ae5da3739215d93922412df4b24c859a2RoboErik 70801fe661ae5da3739215d93922412df4b24c859a2RoboErik private final static class MessageHandler extends Handler { 70942ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik private final MediaController.Callback mCallback; 71001fe661ae5da3739215d93922412df4b24c859a2RoboErik 71142ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik public MessageHandler(Looper looper, MediaController.Callback cb) { 7128ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik super(looper, null, true); 7138ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik mCallback = cb; 71401fe661ae5da3739215d93922412df4b24c859a2RoboErik } 71501fe661ae5da3739215d93922412df4b24c859a2RoboErik 71601fe661ae5da3739215d93922412df4b24c859a2RoboErik @Override 71701fe661ae5da3739215d93922412df4b24c859a2RoboErik public void handleMessage(Message msg) { 71801fe661ae5da3739215d93922412df4b24c859a2RoboErik switch (msg.what) { 7198ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik case MSG_EVENT: 72079fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik mCallback.onSessionEvent((String) msg.obj, msg.getData()); 72101fe661ae5da3739215d93922412df4b24c859a2RoboErik break; 7228ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik case MSG_ROUTE: 72307c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik mCallback.onRouteChanged((RouteInfo) msg.obj); 724c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik break; 725c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik case MSG_UPDATE_PLAYBACK_STATE: 726c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mCallback.onPlaybackStateChanged((PlaybackState) msg.obj); 727c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik break; 728c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik case MSG_UPDATE_METADATA: 729c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mCallback.onMetadataChanged((MediaMetadata) msg.obj); 730c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik break; 73119c9518f6a817d53d5234de0020313cab6950b2fRoboErik case MSG_UPDATE_VOLUME: 73219c9518f6a817d53d5234de0020313cab6950b2fRoboErik mCallback.onVolumeInfoChanged((VolumeInfo) msg.obj); 73319c9518f6a817d53d5234de0020313cab6950b2fRoboErik break; 73401fe661ae5da3739215d93922412df4b24c859a2RoboErik } 73501fe661ae5da3739215d93922412df4b24c859a2RoboErik } 7368ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik 7378ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik public void post(int what, Object obj, Bundle data) { 7388ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik obtainMessage(what, obj).sendToTarget(); 7398ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 74001fe661ae5da3739215d93922412df4b24c859a2RoboErik } 74101fe661ae5da3739215d93922412df4b24c859a2RoboErik 74201fe661ae5da3739215d93922412df4b24c859a2RoboErik} 743