MediaController.java revision ef3c9e9b057a5aac2d0d012e8e6385660478e203
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 1942ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErikimport android.media.MediaMetadata; 20c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErikimport android.media.Rating; 21ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErikimport android.media.VolumeProvider; 2201fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.os.Bundle; 2301fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.os.Handler; 2401fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.os.Looper; 2501fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.os.Message; 2601fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.os.RemoteException; 278ae0f34db936a649ddaf9cdd086c224f6514efebRoboErikimport android.os.ResultReceiver; 2801fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.text.TextUtils; 2901fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.util.Log; 3001fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.view.KeyEvent; 3101fe661ae5da3739215d93922412df4b24c859a2RoboErik 328ae0f34db936a649ddaf9cdd086c224f6514efebRoboErikimport java.lang.ref.WeakReference; 3301fe661ae5da3739215d93922412df4b24c859a2RoboErikimport java.util.ArrayList; 3401fe661ae5da3739215d93922412df4b24c859a2RoboErik 3501fe661ae5da3739215d93922412df4b24c859a2RoboErik/** 3601fe661ae5da3739215d93922412df4b24c859a2RoboErik * Allows an app to interact with an ongoing media session. Media buttons and 3701fe661ae5da3739215d93922412df4b24c859a2RoboErik * other commands can be sent to the session. A callback may be registered to 3801fe661ae5da3739215d93922412df4b24c859a2RoboErik * receive updates from the session, such as metadata and play state changes. 3901fe661ae5da3739215d93922412df4b24c859a2RoboErik * <p> 4042ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik * A MediaController can be created through {@link MediaSessionManager} if you 4101fe661ae5da3739215d93922412df4b24c859a2RoboErik * hold the "android.permission.MEDIA_CONTENT_CONTROL" permission or directly if 4242ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik * you have a {@link MediaSessionToken} from the session owner. 4301fe661ae5da3739215d93922412df4b24c859a2RoboErik * <p> 4401fe661ae5da3739215d93922412df4b24c859a2RoboErik * MediaController objects are thread-safe. 4501fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 4642ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErikpublic final class MediaController { 4707c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik private static final String TAG = "SessionController"; 4801fe661ae5da3739215d93922412df4b24c859a2RoboErik 498ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik private static final int MSG_EVENT = 1; 50c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik private static final int MSG_UPDATE_PLAYBACK_STATE = 2; 51c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik private static final int MSG_UPDATE_METADATA = 3; 528ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik private static final int MSG_ROUTE = 4; 5301fe661ae5da3739215d93922412df4b24c859a2RoboErik 5407c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik private final ISessionController mSessionBinder; 5501fe661ae5da3739215d93922412df4b24c859a2RoboErik 568ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik private final CallbackStub mCbStub = new CallbackStub(this); 578ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik private final ArrayList<MessageHandler> mCallbacks = new ArrayList<MessageHandler>(); 5801fe661ae5da3739215d93922412df4b24c859a2RoboErik private final Object mLock = new Object(); 5901fe661ae5da3739215d93922412df4b24c859a2RoboErik 6001fe661ae5da3739215d93922412df4b24c859a2RoboErik private boolean mCbRegistered = false; 6173e23e229dd1a2d25687b1c6a63c708665378e41RoboErik private MediaSessionInfo mInfo; 6201fe661ae5da3739215d93922412df4b24c859a2RoboErik 63c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik private TransportControls mTransportController; 648ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik 6542ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik private MediaController(ISessionController sessionBinder) { 668ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik mSessionBinder = sessionBinder; 67c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mTransportController = new TransportControls(); 688ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 698ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik 7001fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 718ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * @hide 7201fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 7342ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik public static MediaController fromBinder(ISessionController sessionBinder) { 74d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik return new MediaController(sessionBinder); 7501fe661ae5da3739215d93922412df4b24c859a2RoboErik } 7601fe661ae5da3739215d93922412df4b24c859a2RoboErik 7701fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 788ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * Get a new MediaController for a MediaSessionToken. If successful the 798ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * controller returned will be connected to the session that generated the 808ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * token. 818ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * 828ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * @param token The session token to use 838ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * @return A controller for the session or null 8401fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 8542ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik public static MediaController fromToken(MediaSessionToken token) { 868ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik return fromBinder(token.getBinder()); 8701fe661ae5da3739215d93922412df4b24c859a2RoboErik } 8801fe661ae5da3739215d93922412df4b24c859a2RoboErik 8901fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 90c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Get a {@link TransportControls} instance for this session. 9101fe661ae5da3739215d93922412df4b24c859a2RoboErik * 92c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @return A controls instance 9301fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 94c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public TransportControls getTransportControls() { 958ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik return mTransportController; 9601fe661ae5da3739215d93922412df4b24c859a2RoboErik } 9701fe661ae5da3739215d93922412df4b24c859a2RoboErik 9801fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 9979fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik * Send the specified media button event to the session. Only media keys can 10079fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik * be sent by this method, other keys will be ignored. 10101fe661ae5da3739215d93922412df4b24c859a2RoboErik * 10279fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik * @param keyEvent The media button event to dispatch. 10379fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik * @return true if the event was sent to the session, false otherwise. 10401fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 10579fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik public boolean dispatchMediaButtonEvent(KeyEvent keyEvent) { 10679fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik if (keyEvent == null) { 10779fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik throw new IllegalArgumentException("KeyEvent may not be null"); 10879fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik } 10979fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik if (!KeyEvent.isMediaKey(keyEvent.getKeyCode())) { 11079fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik return false; 11101fe661ae5da3739215d93922412df4b24c859a2RoboErik } 11201fe661ae5da3739215d93922412df4b24c859a2RoboErik try { 11379fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik return mSessionBinder.sendMediaButton(keyEvent); 11401fe661ae5da3739215d93922412df4b24c859a2RoboErik } catch (RemoteException e) { 115c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik // System is dead. =( 11601fe661ae5da3739215d93922412df4b24c859a2RoboErik } 11779fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik return false; 11801fe661ae5da3739215d93922412df4b24c859a2RoboErik } 11901fe661ae5da3739215d93922412df4b24c859a2RoboErik 12001fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 121c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Get the current playback state for this session. 122c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 123c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @return The current PlaybackState or null 124c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 125c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public PlaybackState getPlaybackState() { 126c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 127c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return mSessionBinder.getPlaybackState(); 128c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 129c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling getPlaybackState.", e); 130c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return null; 131c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 132c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 133c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 134c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 135c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Get the current metadata for this session. 136c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 137c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @return The current MediaMetadata or null. 138c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 139c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public MediaMetadata getMetadata() { 140c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 141c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return mSessionBinder.getMetadata(); 142c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 143c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling getMetadata.", e); 144c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return null; 145c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 146c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 147c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 148c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 149c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Get the rating type supported by the session. One of: 150c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <ul> 151c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_NONE}</li> 152c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_HEART}</li> 153c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_THUMB_UP_DOWN}</li> 154c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_3_STARS}</li> 155c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_4_STARS}</li> 156c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_5_STARS}</li> 157c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * <li>{@link Rating#RATING_PERCENTAGE}</li> 158c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * </ul> 159c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 160c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @return The supported rating type 161c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 162c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public int getRatingType() { 163c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 164c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return mSessionBinder.getRatingType(); 165c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 166c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling getRatingType.", e); 167c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik return Rating.RATING_NONE; 168c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 169c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 170c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 171c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 17273e23e229dd1a2d25687b1c6a63c708665378e41RoboErik * Get the flags for this session. 17373e23e229dd1a2d25687b1c6a63c708665378e41RoboErik * 17473e23e229dd1a2d25687b1c6a63c708665378e41RoboErik * @return The current set of flags for the session. 17573e23e229dd1a2d25687b1c6a63c708665378e41RoboErik * @hide 17673e23e229dd1a2d25687b1c6a63c708665378e41RoboErik */ 17773e23e229dd1a2d25687b1c6a63c708665378e41RoboErik public long getFlags() { 17873e23e229dd1a2d25687b1c6a63c708665378e41RoboErik try { 17973e23e229dd1a2d25687b1c6a63c708665378e41RoboErik return mSessionBinder.getFlags(); 18073e23e229dd1a2d25687b1c6a63c708665378e41RoboErik } catch (RemoteException e) { 18173e23e229dd1a2d25687b1c6a63c708665378e41RoboErik Log.wtf(TAG, "Error calling getFlags.", e); 18273e23e229dd1a2d25687b1c6a63c708665378e41RoboErik } 18373e23e229dd1a2d25687b1c6a63c708665378e41RoboErik return 0; 18473e23e229dd1a2d25687b1c6a63c708665378e41RoboErik } 18573e23e229dd1a2d25687b1c6a63c708665378e41RoboErik 18673e23e229dd1a2d25687b1c6a63c708665378e41RoboErik /** 187ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Get the current volume info for this session. 188ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 189ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @return The current volume info or null. 190ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 191ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik public VolumeInfo getVolumeInfo() { 192ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik try { 193ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik ParcelableVolumeInfo result = mSessionBinder.getVolumeAttributes(); 194ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return new VolumeInfo(result.volumeType, result.audioStream, result.controlType, 195ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik result.maxVolume, result.currentVolume); 196ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 197ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } catch (RemoteException e) { 198ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik Log.wtf(TAG, "Error calling getVolumeInfo.", e); 199ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 200ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return null; 201ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 202ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 203ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 20401fe661ae5da3739215d93922412df4b24c859a2RoboErik * Adds a callback to receive updates from the Session. Updates will be 20501fe661ae5da3739215d93922412df4b24c859a2RoboErik * posted on the caller's thread. 20601fe661ae5da3739215d93922412df4b24c859a2RoboErik * 20701fe661ae5da3739215d93922412df4b24c859a2RoboErik * @param cb The callback object, must not be null 20801fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 20901fe661ae5da3739215d93922412df4b24c859a2RoboErik public void addCallback(Callback cb) { 21001fe661ae5da3739215d93922412df4b24c859a2RoboErik addCallback(cb, null); 21101fe661ae5da3739215d93922412df4b24c859a2RoboErik } 21201fe661ae5da3739215d93922412df4b24c859a2RoboErik 21301fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 21401fe661ae5da3739215d93922412df4b24c859a2RoboErik * Adds a callback to receive updates from the session. Updates will be 2158ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * posted on the specified handler's thread. 21601fe661ae5da3739215d93922412df4b24c859a2RoboErik * 21701fe661ae5da3739215d93922412df4b24c859a2RoboErik * @param cb Cannot be null. 2188ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * @param handler The handler to post updates on. If null the callers thread 21901fe661ae5da3739215d93922412df4b24c859a2RoboErik * will be used 22001fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 22101fe661ae5da3739215d93922412df4b24c859a2RoboErik public void addCallback(Callback cb, Handler handler) { 22201fe661ae5da3739215d93922412df4b24c859a2RoboErik if (handler == null) { 22301fe661ae5da3739215d93922412df4b24c859a2RoboErik handler = new Handler(); 22401fe661ae5da3739215d93922412df4b24c859a2RoboErik } 22501fe661ae5da3739215d93922412df4b24c859a2RoboErik synchronized (mLock) { 22601fe661ae5da3739215d93922412df4b24c859a2RoboErik addCallbackLocked(cb, handler); 22701fe661ae5da3739215d93922412df4b24c859a2RoboErik } 22801fe661ae5da3739215d93922412df4b24c859a2RoboErik } 22901fe661ae5da3739215d93922412df4b24c859a2RoboErik 23001fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 23101fe661ae5da3739215d93922412df4b24c859a2RoboErik * Stop receiving updates on the specified callback. If an update has 23201fe661ae5da3739215d93922412df4b24c859a2RoboErik * already been posted you may still receive it after calling this method. 23301fe661ae5da3739215d93922412df4b24c859a2RoboErik * 23401fe661ae5da3739215d93922412df4b24c859a2RoboErik * @param cb The callback to remove 23501fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 23601fe661ae5da3739215d93922412df4b24c859a2RoboErik public void removeCallback(Callback cb) { 23701fe661ae5da3739215d93922412df4b24c859a2RoboErik synchronized (mLock) { 23801fe661ae5da3739215d93922412df4b24c859a2RoboErik removeCallbackLocked(cb); 23901fe661ae5da3739215d93922412df4b24c859a2RoboErik } 24001fe661ae5da3739215d93922412df4b24c859a2RoboErik } 24101fe661ae5da3739215d93922412df4b24c859a2RoboErik 2428ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik /** 2438ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * Sends a generic command to the session. It is up to the session creator 2448ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * to decide what commands and parameters they will support. As such, 2458ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * commands should only be sent to sessions that the controller owns. 2468ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * 2478ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * @param command The command to send 2488ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * @param params Any parameters to include with the command 2498ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * @param cb The callback to receive the result on 2508ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik */ 25179fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik public void sendControlCommand(String command, Bundle params, ResultReceiver cb) { 2528ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (TextUtils.isEmpty(command)) { 2538ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik throw new IllegalArgumentException("command cannot be null or empty"); 2548ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 2558ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik try { 2568ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik mSessionBinder.sendCommand(command, params, cb); 2578ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } catch (RemoteException e) { 2588ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik Log.d(TAG, "Dead object in sendCommand.", e); 2598ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 2608ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 2618ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik 26207c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik /** 26307c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik * Request that the route picker be shown for this session. This should 26407c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik * generally be called in response to a user action. 26542ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik * 26642ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik * @hide 26707c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik */ 26807c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik public void showRoutePicker() { 26907c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik try { 27007c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik mSessionBinder.showRoutePicker(); 27107c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik } catch (RemoteException e) { 27207c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik Log.d(TAG, "Dead object in showRoutePicker", e); 27307c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik } 27407c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik } 27507c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik 276fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik /** 277fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik * Get the info for the session this controller is connected to. 278fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik * 279fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik * @return The session info for the connected session. 280fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik * @hide 281fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik */ 282fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik public MediaSessionInfo getSessionInfo() { 28373e23e229dd1a2d25687b1c6a63c708665378e41RoboErik if (mInfo == null) { 28473e23e229dd1a2d25687b1c6a63c708665378e41RoboErik try { 28573e23e229dd1a2d25687b1c6a63c708665378e41RoboErik mInfo = mSessionBinder.getSessionInfo(); 28673e23e229dd1a2d25687b1c6a63c708665378e41RoboErik } catch (RemoteException e) { 28773e23e229dd1a2d25687b1c6a63c708665378e41RoboErik Log.e(TAG, "Error in getSessionInfo.", e); 28873e23e229dd1a2d25687b1c6a63c708665378e41RoboErik } 289fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik } 29073e23e229dd1a2d25687b1c6a63c708665378e41RoboErik return mInfo; 291fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik } 292fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik 29301fe661ae5da3739215d93922412df4b24c859a2RoboErik /* 29401fe661ae5da3739215d93922412df4b24c859a2RoboErik * @hide 29501fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 29607c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik ISessionController getSessionBinder() { 29701fe661ae5da3739215d93922412df4b24c859a2RoboErik return mSessionBinder; 29801fe661ae5da3739215d93922412df4b24c859a2RoboErik } 29901fe661ae5da3739215d93922412df4b24c859a2RoboErik 30001fe661ae5da3739215d93922412df4b24c859a2RoboErik private void addCallbackLocked(Callback cb, Handler handler) { 30101fe661ae5da3739215d93922412df4b24c859a2RoboErik if (cb == null) { 30201fe661ae5da3739215d93922412df4b24c859a2RoboErik throw new IllegalArgumentException("Callback cannot be null"); 30301fe661ae5da3739215d93922412df4b24c859a2RoboErik } 30401fe661ae5da3739215d93922412df4b24c859a2RoboErik if (handler == null) { 30501fe661ae5da3739215d93922412df4b24c859a2RoboErik throw new IllegalArgumentException("Handler cannot be null"); 30601fe661ae5da3739215d93922412df4b24c859a2RoboErik } 3078ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (getHandlerForCallbackLocked(cb) != null) { 30801fe661ae5da3739215d93922412df4b24c859a2RoboErik Log.w(TAG, "Callback is already added, ignoring"); 30901fe661ae5da3739215d93922412df4b24c859a2RoboErik return; 31001fe661ae5da3739215d93922412df4b24c859a2RoboErik } 3118ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik MessageHandler holder = new MessageHandler(handler.getLooper(), cb); 3128ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik mCallbacks.add(holder); 31301fe661ae5da3739215d93922412df4b24c859a2RoboErik 31401fe661ae5da3739215d93922412df4b24c859a2RoboErik if (!mCbRegistered) { 31501fe661ae5da3739215d93922412df4b24c859a2RoboErik try { 31601fe661ae5da3739215d93922412df4b24c859a2RoboErik mSessionBinder.registerCallbackListener(mCbStub); 31701fe661ae5da3739215d93922412df4b24c859a2RoboErik mCbRegistered = true; 31801fe661ae5da3739215d93922412df4b24c859a2RoboErik } catch (RemoteException e) { 319d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik Log.e(TAG, "Dead object in registerCallback", e); 32001fe661ae5da3739215d93922412df4b24c859a2RoboErik } 32101fe661ae5da3739215d93922412df4b24c859a2RoboErik } 32201fe661ae5da3739215d93922412df4b24c859a2RoboErik } 32301fe661ae5da3739215d93922412df4b24c859a2RoboErik 3248ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik private boolean removeCallbackLocked(Callback cb) { 32501fe661ae5da3739215d93922412df4b24c859a2RoboErik if (cb == null) { 32601fe661ae5da3739215d93922412df4b24c859a2RoboErik throw new IllegalArgumentException("Callback cannot be null"); 32701fe661ae5da3739215d93922412df4b24c859a2RoboErik } 328d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik boolean success = false; 3298ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik for (int i = mCallbacks.size() - 1; i >= 0; i--) { 3308ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik MessageHandler handler = mCallbacks.get(i); 3318ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (cb == handler.mCallback) { 3328ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik mCallbacks.remove(i); 333d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik success = true; 33401fe661ae5da3739215d93922412df4b24c859a2RoboErik } 33501fe661ae5da3739215d93922412df4b24c859a2RoboErik } 336d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik if (mCbRegistered && mCallbacks.size() == 0) { 337d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik try { 338d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik mSessionBinder.unregisterCallbackListener(mCbStub); 339d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik } catch (RemoteException e) { 340d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik Log.e(TAG, "Dead object in removeCallbackLocked"); 341d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik } 342d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik mCbRegistered = false; 343d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik } 344d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik return success; 34501fe661ae5da3739215d93922412df4b24c859a2RoboErik } 34601fe661ae5da3739215d93922412df4b24c859a2RoboErik 3478ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik private MessageHandler getHandlerForCallbackLocked(Callback cb) { 3488ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (cb == null) { 3498ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik throw new IllegalArgumentException("Callback cannot be null"); 35001fe661ae5da3739215d93922412df4b24c859a2RoboErik } 3518ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik for (int i = mCallbacks.size() - 1; i >= 0; i--) { 3528ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik MessageHandler handler = mCallbacks.get(i); 3538ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (cb == handler.mCallback) { 3548ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik return handler; 3558ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 35601fe661ae5da3739215d93922412df4b24c859a2RoboErik } 3578ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik return null; 35801fe661ae5da3739215d93922412df4b24c859a2RoboErik } 35901fe661ae5da3739215d93922412df4b24c859a2RoboErik 360c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik private final void postMessage(int what, Object obj, Bundle data) { 3618ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik synchronized (mLock) { 3628ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik for (int i = mCallbacks.size() - 1; i >= 0; i--) { 363c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mCallbacks.get(i).post(what, obj, data); 3648ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 36501fe661ae5da3739215d93922412df4b24c859a2RoboErik } 36601fe661ae5da3739215d93922412df4b24c859a2RoboErik } 36701fe661ae5da3739215d93922412df4b24c859a2RoboErik 36801fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 3698ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * Callback for receiving updates on from the session. A Callback can be 3708ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * registered using {@link #addCallback} 37101fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 37201fe661ae5da3739215d93922412df4b24c859a2RoboErik public static abstract class Callback { 37301fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 3748ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * Override to handle custom events sent by the session owner without a 3758ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * specified interface. Controllers should only handle these for 3768ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * sessions they own. 37701fe661ae5da3739215d93922412df4b24c859a2RoboErik * 37801fe661ae5da3739215d93922412df4b24c859a2RoboErik * @param event 37901fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 38079fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik public void onSessionEvent(String event, Bundle extras) { 38101fe661ae5da3739215d93922412df4b24c859a2RoboErik } 38201fe661ae5da3739215d93922412df4b24c859a2RoboErik 38301fe661ae5da3739215d93922412df4b24c859a2RoboErik /** 38401fe661ae5da3739215d93922412df4b24c859a2RoboErik * Override to handle route changes for this session. 38501fe661ae5da3739215d93922412df4b24c859a2RoboErik * 38642ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik * @param route The new route 38742ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik * @hide 38801fe661ae5da3739215d93922412df4b24c859a2RoboErik */ 38907c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik public void onRouteChanged(RouteInfo route) { 39001fe661ae5da3739215d93922412df4b24c859a2RoboErik } 391c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 392c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 393c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Override to handle changes in playback state. 394c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 395c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @param state The new playback state of the session 396c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 397c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void onPlaybackStateChanged(PlaybackState state) { 398c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 399c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 400c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 401c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Override to handle changes to the current metadata. 402c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 403c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @see MediaMetadata 404c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @param metadata The current metadata for the session or null 405c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 406c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void onMetadataChanged(MediaMetadata metadata) { 407c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 408c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 409c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 410c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 411c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Interface for controlling media playback on a session. This allows an app 412c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * to send media transport commands to the session. 413c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 414c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public final class TransportControls { 415c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik private static final String TAG = "TransportController"; 416c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 417c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik private TransportControls() { 418c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 419c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 420c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 421c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Request that the player start its playback at its current position. 422c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 423c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void play() { 424c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 425c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.play(); 426c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 427c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling play.", e); 428c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 429c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 430c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 431c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 432c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Request that the player pause its playback and stay at its current 433c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * position. 434c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 435c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void pause() { 436c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 437c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.pause(); 438c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 439c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling pause.", e); 440c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 441c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 442c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 443c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 444c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Request that the player stop its playback; it may clear its state in 445c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * whatever way is appropriate. 446c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 447c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void stop() { 448c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 449c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.stop(); 450c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 451c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling stop.", e); 452c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 453c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 454c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 455c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 456c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Move to a new location in the media stream. 457c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 458c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @param pos Position to move to, in milliseconds. 459c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 460c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void seekTo(long pos) { 461c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 462c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.seekTo(pos); 463c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 464c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling seekTo.", e); 465c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 466c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 467c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 468c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 469c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Start fast forwarding. If playback is already fast forwarding this 470c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * may increase the rate. 471c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 472c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void fastForward() { 473c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 474c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.fastForward(); 475c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 476c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling fastForward.", e); 477c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 478c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 479c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 480c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 481c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Skip to the next item. 482c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 483c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void skipToNext() { 484c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 485c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.next(); 486c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 487c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling next.", e); 488c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 489c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 490c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 491c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 492c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Start rewinding. If playback is already rewinding this may increase 493c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * the rate. 494c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 495c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void rewind() { 496c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 497c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.rewind(); 498c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 499c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling rewind.", e); 500c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 501c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 502c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 503c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 504c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Skip to the previous item. 505c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 506c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void skipToPrevious() { 507c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 508c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.previous(); 509c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 510c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling previous.", e); 511c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 512c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 513c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik 514c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik /** 515c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * Rate the current content. This will cause the rating to be set for 516c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * the current user. The Rating type must match the type returned by 517c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * {@link #getRatingType()}. 518c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * 519c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik * @param rating The rating to set for the current content 520c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik */ 521c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik public void setRating(Rating rating) { 522c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik try { 523c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mSessionBinder.rate(rating); 524c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } catch (RemoteException e) { 525c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik Log.wtf(TAG, "Error calling rate.", e); 526c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 527c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik } 5288ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 52901fe661ae5da3739215d93922412df4b24c859a2RoboErik 530ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 531ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Holds information about the way volume is handled for this session. 532ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 533ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik public static final class VolumeInfo { 534ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik private final int mVolumeType; 535ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik private final int mAudioStream; 536ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik private final int mVolumeControl; 537ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik private final int mMaxVolume; 538ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik private final int mCurrentVolume; 539ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 540ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 541ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @hide 542ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 543ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik public VolumeInfo(int type, int stream, int control, int max, int current) { 544ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik mVolumeType = type; 545ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik mAudioStream = stream; 546ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik mVolumeControl = control; 547ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik mMaxVolume = max; 548ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik mCurrentVolume = current; 549ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 550ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 551ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 552ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Get the type of volume handling, either local or remote. One of: 553ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * <ul> 554ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * <li>{@link MediaSession#VOLUME_TYPE_LOCAL}</li> 555ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * <li>{@link MediaSession#VOLUME_TYPE_REMOTE}</li> 556ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * </ul> 557ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 558ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @return The type of volume handling this session is using. 559ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 560ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik public int getVolumeType() { 561ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return mVolumeType; 562ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 563ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 564ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 565ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Get the stream this is currently controlling volume on. When the volume 566ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * type is {@link MediaSession#VOLUME_TYPE_REMOTE} this value does not 567ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * have meaning and should be ignored. 568ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 569ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @return The stream this session is playing on. 570ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 571ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik public int getAudioStream() { 572ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return mAudioStream; 573ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 574ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 575ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 576ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Get the type of volume control that can be used. One of: 577ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * <ul> 578ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * <li>{@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}</li> 579ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * <li>{@link VolumeProvider#VOLUME_CONTROL_RELATIVE}</li> 580ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * <li>{@link VolumeProvider#VOLUME_CONTROL_FIXED}</li> 581ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * </ul> 582ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 583ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @return The type of volume control that may be used with this 584ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * session. 585ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 586ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik public int getVolumeControl() { 587ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return mVolumeControl; 588ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 589ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 590ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 591ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Get the maximum volume that may be set for this session. 592ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 593ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @return The maximum allowed volume where this session is playing. 594ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 595ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik public int getMaxVolume() { 596ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return mMaxVolume; 597ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 598ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 599ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik /** 600ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * Get the current volume for this session. 601ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * 602ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik * @return The current volume where this session is playing. 603ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik */ 604ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik public int getCurrentVolume() { 605ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik return mCurrentVolume; 606ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 607ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik } 608ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik 60907c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik private final static class CallbackStub extends ISessionControllerCallback.Stub { 61042ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik private final WeakReference<MediaController> mController; 61101fe661ae5da3739215d93922412df4b24c859a2RoboErik 61242ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik public CallbackStub(MediaController controller) { 61342ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik mController = new WeakReference<MediaController>(controller); 61401fe661ae5da3739215d93922412df4b24c859a2RoboErik } 61501fe661ae5da3739215d93922412df4b24c859a2RoboErik 61601fe661ae5da3739215d93922412df4b24c859a2RoboErik @Override 6178ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik public void onEvent(String event, Bundle extras) { 61842ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik MediaController controller = mController.get(); 6198ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (controller != null) { 620c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik controller.postMessage(MSG_EVENT, event, extras); 62101fe661ae5da3739215d93922412df4b24c859a2RoboErik } 62201fe661ae5da3739215d93922412df4b24c859a2RoboErik } 62301fe661ae5da3739215d93922412df4b24c859a2RoboErik 62401fe661ae5da3739215d93922412df4b24c859a2RoboErik @Override 62507c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik public void onRouteChanged(RouteInfo route) { 62642ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik MediaController controller = mController.get(); 6278ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (controller != null) { 628c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik controller.postMessage(MSG_ROUTE, route, null); 62901fe661ae5da3739215d93922412df4b24c859a2RoboErik } 63001fe661ae5da3739215d93922412df4b24c859a2RoboErik } 63101fe661ae5da3739215d93922412df4b24c859a2RoboErik 63201fe661ae5da3739215d93922412df4b24c859a2RoboErik @Override 6338ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik public void onPlaybackStateChanged(PlaybackState state) { 63442ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik MediaController controller = mController.get(); 6358ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (controller != null) { 636c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik controller.postMessage(MSG_UPDATE_PLAYBACK_STATE, state, null); 63701fe661ae5da3739215d93922412df4b24c859a2RoboErik } 63801fe661ae5da3739215d93922412df4b24c859a2RoboErik } 63901fe661ae5da3739215d93922412df4b24c859a2RoboErik 64001fe661ae5da3739215d93922412df4b24c859a2RoboErik @Override 6418ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik public void onMetadataChanged(MediaMetadata metadata) { 64242ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik MediaController controller = mController.get(); 6438ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (controller != null) { 644c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik controller.postMessage(MSG_UPDATE_METADATA, metadata, null); 64501fe661ae5da3739215d93922412df4b24c859a2RoboErik } 64601fe661ae5da3739215d93922412df4b24c859a2RoboErik } 64701fe661ae5da3739215d93922412df4b24c859a2RoboErik 64801fe661ae5da3739215d93922412df4b24c859a2RoboErik } 64901fe661ae5da3739215d93922412df4b24c859a2RoboErik 65001fe661ae5da3739215d93922412df4b24c859a2RoboErik private final static class MessageHandler extends Handler { 65142ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik private final MediaController.Callback mCallback; 65201fe661ae5da3739215d93922412df4b24c859a2RoboErik 65342ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik public MessageHandler(Looper looper, MediaController.Callback cb) { 6548ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik super(looper, null, true); 6558ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik mCallback = cb; 65601fe661ae5da3739215d93922412df4b24c859a2RoboErik } 65701fe661ae5da3739215d93922412df4b24c859a2RoboErik 65801fe661ae5da3739215d93922412df4b24c859a2RoboErik @Override 65901fe661ae5da3739215d93922412df4b24c859a2RoboErik public void handleMessage(Message msg) { 66001fe661ae5da3739215d93922412df4b24c859a2RoboErik switch (msg.what) { 6618ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik case MSG_EVENT: 66279fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik mCallback.onSessionEvent((String) msg.obj, msg.getData()); 66301fe661ae5da3739215d93922412df4b24c859a2RoboErik break; 6648ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik case MSG_ROUTE: 66507c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik mCallback.onRouteChanged((RouteInfo) msg.obj); 666c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik break; 667c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik case MSG_UPDATE_PLAYBACK_STATE: 668c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mCallback.onPlaybackStateChanged((PlaybackState) msg.obj); 669c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik break; 670c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik case MSG_UPDATE_METADATA: 671c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mCallback.onMetadataChanged((MediaMetadata) msg.obj); 672c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik break; 67301fe661ae5da3739215d93922412df4b24c859a2RoboErik } 67401fe661ae5da3739215d93922412df4b24c859a2RoboErik } 6758ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik 6768ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik public void post(int what, Object obj, Bundle data) { 6778ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik obtainMessage(what, obj).sendToTarget(); 6788ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 67901fe661ae5da3739215d93922412df4b24c859a2RoboErik } 68001fe661ae5da3739215d93922412df4b24c859a2RoboErik 68101fe661ae5da3739215d93922412df4b24c859a2RoboErik} 682