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
1701fe661ae5da3739215d93922412df4b24c859a2RoboErikpackage com.android.server.media;
1801fe661ae5da3739215d93922412df4b24c859a2RoboErik
19e34c09daf89fb888fe2638e71758573462d85173RoboErikimport android.app.PendingIntent;
206f0e4ddd66fcdcc13944d8970d0b560e2626508bRoboErikimport android.content.ComponentName;
21ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErikimport android.content.Context;
2201fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.content.Intent;
23f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Pealimport android.content.pm.ParceledListSlice;
24f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Pealimport android.media.AudioManager;
250dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErikimport android.media.AudioManagerInternal;
26165809b33198cd3926cc11e8cbc96b671d4c87d3RoboErikimport android.media.AudioSystem;
273625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErikimport android.media.MediaDescription;
28f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Pealimport android.media.MediaMetadata;
29f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Pealimport android.media.Rating;
30f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Pealimport android.media.VolumeProvider;
3107c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErikimport android.media.session.ISession;
3207c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErikimport android.media.session.ISessionCallback;
33f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Pealimport android.media.session.ISessionController;
34f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Pealimport android.media.session.ISessionControllerCallback;
3542ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErikimport android.media.session.MediaController;
36d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErikimport android.media.session.MediaController.PlaybackInfo;
3742ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErikimport android.media.session.MediaSession;
387c82ced4fc5b66c09a19eed9a5499039530142fbRoboErikimport android.media.session.MediaSessionManager;
39ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErikimport android.media.session.ParcelableVolumeInfo;
40f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Pealimport android.media.session.PlaybackState;
419db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErikimport android.media.AudioAttributes;
42f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Pealimport android.net.Uri;
43f77b99f08afed6f6b8d8f5bc72978f2ff7b8db55RoboErikimport android.os.Binder;
4401fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.os.Bundle;
45d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErikimport android.os.DeadObjectException;
468ae0f34db936a649ddaf9cdd086c224f6514efebRoboErikimport android.os.Handler;
4701fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.os.IBinder;
488ae0f34db936a649ddaf9cdd086c224f6514efebRoboErikimport android.os.Looper;
498ae0f34db936a649ddaf9cdd086c224f6514efebRoboErikimport android.os.Message;
5001fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.os.RemoteException;
518ae0f34db936a649ddaf9cdd086c224f6514efebRoboErikimport android.os.ResultReceiver;
52f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErikimport android.os.SystemClock;
5301fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.util.Log;
548ae0f34db936a649ddaf9cdd086c224f6514efebRoboErikimport android.util.Slog;
5501fe661ae5da3739215d93922412df4b24c859a2RoboErikimport android.view.KeyEvent;
5601fe661ae5da3739215d93922412df4b24c859a2RoboErik
570dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErikimport com.android.server.LocalServices;
580dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik
59a278ea7cecb59a73586e5dd74ec05e85caa370c5RoboErikimport java.io.PrintWriter;
6001fe661ae5da3739215d93922412df4b24c859a2RoboErikimport java.util.ArrayList;
6107c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErikimport java.util.UUID;
6201fe661ae5da3739215d93922412df4b24c859a2RoboErik
6301fe661ae5da3739215d93922412df4b24c859a2RoboErik/**
6401fe661ae5da3739215d93922412df4b24c859a2RoboErik * This is the system implementation of a Session. Apps will interact with the
6501fe661ae5da3739215d93922412df4b24c859a2RoboErik * MediaSession wrapper class instead.
6601fe661ae5da3739215d93922412df4b24c859a2RoboErik */
6701fe661ae5da3739215d93922412df4b24c859a2RoboErikpublic class MediaSessionRecord implements IBinder.DeathRecipient {
6807c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik    private static final String TAG = "MediaSessionRecord";
69d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik    private static final boolean DEBUG = false;
7001fe661ae5da3739215d93922412df4b24c859a2RoboErik
71a8f951462791a16f47e8c07e552232f31dcefac5RoboErik    /**
72a8f951462791a16f47e8c07e552232f31dcefac5RoboErik     * The length of time a session will still be considered active after
73a8f951462791a16f47e8c07e552232f31dcefac5RoboErik     * pausing in ms.
74a8f951462791a16f47e8c07e552232f31dcefac5RoboErik     */
75a8f951462791a16f47e8c07e552232f31dcefac5RoboErik    private static final int ACTIVE_BUFFER = 30000;
76a8f951462791a16f47e8c07e552232f31dcefac5RoboErik
7719c9518f6a817d53d5234de0020313cab6950b2fRoboErik    /**
7819c9518f6a817d53d5234de0020313cab6950b2fRoboErik     * The amount of time we'll send an assumed volume after the last volume
7919c9518f6a817d53d5234de0020313cab6950b2fRoboErik     * command before reverting to the last reported volume.
8019c9518f6a817d53d5234de0020313cab6950b2fRoboErik     */
8119c9518f6a817d53d5234de0020313cab6950b2fRoboErik    private static final int OPTIMISTIC_VOLUME_TIMEOUT = 1000;
8219c9518f6a817d53d5234de0020313cab6950b2fRoboErik
838ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik    private final MessageHandler mHandler;
848ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
85a5b02329209be355eafadbdf9ee685ffa58d3148RoboErik    private final int mOwnerPid;
86a5b02329209be355eafadbdf9ee685ffa58d3148RoboErik    private final int mOwnerUid;
87a5b02329209be355eafadbdf9ee685ffa58d3148RoboErik    private final int mUserId;
88aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik    private final String mPackageName;
8901fe661ae5da3739215d93922412df4b24c859a2RoboErik    private final String mTag;
9001fe661ae5da3739215d93922412df4b24c859a2RoboErik    private final ControllerStub mController;
9101fe661ae5da3739215d93922412df4b24c859a2RoboErik    private final SessionStub mSession;
9201fe661ae5da3739215d93922412df4b24c859a2RoboErik    private final SessionCb mSessionCb;
9301fe661ae5da3739215d93922412df4b24c859a2RoboErik    private final MediaSessionService mService;
94519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik    private final boolean mUseMasterVolume;
9501fe661ae5da3739215d93922412df4b24c859a2RoboErik
9607c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik    private final Object mLock = new Object();
9707c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik    private final ArrayList<ISessionControllerCallback> mControllerCallbacks =
9807c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik            new ArrayList<ISessionControllerCallback>();
998ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
100e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik    private long mFlags;
101b214efbb9170a9f6a4991684a63ca59680074cc7RoboErik    private PendingIntent mMediaButtonReceiver;
102e34c09daf89fb888fe2638e71758573462d85173RoboErik    private PendingIntent mLaunchIntent;
1038ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
1048ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik    // TransportPerformer fields
10501fe661ae5da3739215d93922412df4b24c859a2RoboErik
106f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal    private Bundle mExtras;
1078ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik    private MediaMetadata mMetadata;
1088ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik    private PlaybackState mPlaybackState;
109f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal    private ParceledListSlice mQueue;
110f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal    private CharSequence mQueueTitle;
1118ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik    private int mRatingType;
112a8f951462791a16f47e8c07e552232f31dcefac5RoboErik    private long mLastActiveTime;
1138ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik    // End TransportPerformer fields
1148ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
115b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik    // Volume handling fields
1169db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik    private AudioAttributes mAudioAttrs;
117ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik    private AudioManager mAudioManager;
1180dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik    private AudioManagerInternal mAudioManagerInternal;
119d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik    private int mVolumeType = PlaybackInfo.PLAYBACK_TYPE_LOCAL;
120ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik    private int mVolumeControlType = VolumeProvider.VOLUME_CONTROL_ABSOLUTE;
121b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik    private int mMaxVolume = 0;
122b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik    private int mCurrentVolume = 0;
12319c9518f6a817d53d5234de0020313cab6950b2fRoboErik    private int mOptimisticVolume = -1;
124b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik    // End volume handling fields
125b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik
126a8f951462791a16f47e8c07e552232f31dcefac5RoboErik    private boolean mIsActive = false;
1274646d288821d62fdfe481be67d8b7fed7d7eabd8RoboErik    private boolean mDestroyed = false;
12801fe661ae5da3739215d93922412df4b24c859a2RoboErik
129a5b02329209be355eafadbdf9ee685ffa58d3148RoboErik    public MediaSessionRecord(int ownerPid, int ownerUid, int userId, String ownerPackageName,
130a5b02329209be355eafadbdf9ee685ffa58d3148RoboErik            ISessionCallback cb, String tag, MediaSessionService service, Handler handler) {
131a5b02329209be355eafadbdf9ee685ffa58d3148RoboErik        mOwnerPid = ownerPid;
132a5b02329209be355eafadbdf9ee685ffa58d3148RoboErik        mOwnerUid = ownerUid;
133a5b02329209be355eafadbdf9ee685ffa58d3148RoboErik        mUserId = userId;
134aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik        mPackageName = ownerPackageName;
13501fe661ae5da3739215d93922412df4b24c859a2RoboErik        mTag = tag;
13601fe661ae5da3739215d93922412df4b24c859a2RoboErik        mController = new ControllerStub();
13701fe661ae5da3739215d93922412df4b24c859a2RoboErik        mSession = new SessionStub();
13801fe661ae5da3739215d93922412df4b24c859a2RoboErik        mSessionCb = new SessionCb(cb);
13901fe661ae5da3739215d93922412df4b24c859a2RoboErik        mService = service;
1408ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        mHandler = new MessageHandler(handler.getLooper());
141ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik        mAudioManager = (AudioManager) service.getContext().getSystemService(Context.AUDIO_SERVICE);
1420dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik        mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class);
1439db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik        mAudioAttrs = new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build();
144519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik        mUseMasterVolume = service.getContext().getResources().getBoolean(
145519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik                com.android.internal.R.bool.config_useMasterVolume);
14601fe661ae5da3739215d93922412df4b24c859a2RoboErik    }
14701fe661ae5da3739215d93922412df4b24c859a2RoboErik
14807c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik    /**
14942ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik     * Get the binder for the {@link MediaSession}.
15007c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik     *
15107c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik     * @return The session binder apps talk to.
15207c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik     */
15307c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik    public ISession getSessionBinder() {
15401fe661ae5da3739215d93922412df4b24c859a2RoboErik        return mSession;
15501fe661ae5da3739215d93922412df4b24c859a2RoboErik    }
15601fe661ae5da3739215d93922412df4b24c859a2RoboErik
15707c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik    /**
15842ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik     * Get the binder for the {@link MediaController}.
15907c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik     *
16007c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik     * @return The controller binder apps talk to.
16107c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik     */
16207c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik    public ISessionController getControllerBinder() {
16301fe661ae5da3739215d93922412df4b24c859a2RoboErik        return mController;
16401fe661ae5da3739215d93922412df4b24c859a2RoboErik    }
16501fe661ae5da3739215d93922412df4b24c859a2RoboErik
16607c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik    /**
16707c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik     * Get the info for this session.
16807c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik     *
16907c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik     * @return Info that identifies this session.
17007c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik     */
171aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik    public String getPackageName() {
172aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik        return mPackageName;
173aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik    }
174aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik
175aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik    /**
176aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik     * Get the tag for the session.
177aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik     *
178aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik     * @return The session's tag.
179aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik     */
180aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik    public String getTag() {
181aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik        return mTag;
18207c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik    }
18307c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik
184b214efbb9170a9f6a4991684a63ca59680074cc7RoboErik    /**
185b214efbb9170a9f6a4991684a63ca59680074cc7RoboErik     * Get the intent the app set for their media button receiver.
186b214efbb9170a9f6a4991684a63ca59680074cc7RoboErik     *
187b214efbb9170a9f6a4991684a63ca59680074cc7RoboErik     * @return The pending intent set by the app or null.
188b214efbb9170a9f6a4991684a63ca59680074cc7RoboErik     */
189b214efbb9170a9f6a4991684a63ca59680074cc7RoboErik    public PendingIntent getMediaButtonReceiver() {
1906f0e4ddd66fcdcc13944d8970d0b560e2626508bRoboErik        return mMediaButtonReceiver;
1916f0e4ddd66fcdcc13944d8970d0b560e2626508bRoboErik    }
1926f0e4ddd66fcdcc13944d8970d0b560e2626508bRoboErik
19307c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik    /**
194e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik     * Get this session's flags.
195e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik     *
196e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik     * @return The flags for this session.
197e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik     */
198e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik    public long getFlags() {
199e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik        return mFlags;
200e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik    }
201e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik
202e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik    /**
203a8f951462791a16f47e8c07e552232f31dcefac5RoboErik     * Check if this session has the specified flag.
204a8f951462791a16f47e8c07e552232f31dcefac5RoboErik     *
205a8f951462791a16f47e8c07e552232f31dcefac5RoboErik     * @param flag The flag to check.
206a8f951462791a16f47e8c07e552232f31dcefac5RoboErik     * @return True if this session has that flag set, false otherwise.
207a8f951462791a16f47e8c07e552232f31dcefac5RoboErik     */
208a8f951462791a16f47e8c07e552232f31dcefac5RoboErik    public boolean hasFlag(int flag) {
209a8f951462791a16f47e8c07e552232f31dcefac5RoboErik        return (mFlags & flag) != 0;
210a8f951462791a16f47e8c07e552232f31dcefac5RoboErik    }
211a8f951462791a16f47e8c07e552232f31dcefac5RoboErik
212a8f951462791a16f47e8c07e552232f31dcefac5RoboErik    /**
213a5b02329209be355eafadbdf9ee685ffa58d3148RoboErik     * Get the user id this session was created for.
214a5b02329209be355eafadbdf9ee685ffa58d3148RoboErik     *
215a5b02329209be355eafadbdf9ee685ffa58d3148RoboErik     * @return The user id for this session.
216a5b02329209be355eafadbdf9ee685ffa58d3148RoboErik     */
217a5b02329209be355eafadbdf9ee685ffa58d3148RoboErik    public int getUserId() {
218a5b02329209be355eafadbdf9ee685ffa58d3148RoboErik        return mUserId;
219a5b02329209be355eafadbdf9ee685ffa58d3148RoboErik    }
220a5b02329209be355eafadbdf9ee685ffa58d3148RoboErik
221a5b02329209be355eafadbdf9ee685ffa58d3148RoboErik    /**
222e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik     * Check if this session has system priorty and should receive media buttons
223e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik     * before any other sessions.
224e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik     *
225e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik     * @return True if this is a system priority session, false otherwise
226e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik     */
227e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik    public boolean isSystemPriority() {
22842ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik        return (mFlags & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0;
229e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik    }
230e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik
231e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik    /**
2321ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik     * Send a volume adjustment to the session owner. Direction must be one of
2331ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik     * {@link AudioManager#ADJUST_LOWER}, {@link AudioManager#ADJUST_RAISE},
2341ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik     * {@link AudioManager#ADJUST_SAME}.
235b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik     *
2361ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik     * @param direction The direction to adjust volume in.
237272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik     * @param flags Any of the flags from {@link AudioManager}.
238272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik     * @param packageName The package that made the original volume request.
239272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik     * @param uid The uid that made the original volume request.
240272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik     * @param useSuggested True to use adjustSuggestedStreamVolume instead of
241272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik     *            adjustStreamVolume.
242b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik     */
243272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik    public void adjustVolume(int direction, int flags, String packageName, int uid,
244272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik            boolean useSuggested) {
245165809b33198cd3926cc11e8cbc96b671d4c87d3RoboErik        int previousFlagPlaySound = flags & AudioManager.FLAG_PLAY_SOUND;
2467a18cb5672127bf12c8edac8a327f9b706b79ff7RoboErik        if (isPlaybackActive(false) || hasFlag(MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY)) {
247e9466805e55595ce72c070c73e2fcae46e857850RoboErik            flags &= ~AudioManager.FLAG_PLAY_SOUND;
248e9466805e55595ce72c070c73e2fcae46e857850RoboErik        }
2497c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik        boolean isMute = direction == MediaSessionManager.DIRECTION_MUTE;
2501ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik        if (direction > 1) {
2511ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik            direction = 1;
2521ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik        } else if (direction < -1) {
2531ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik            direction = -1;
2541ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik        }
255d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik        if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
256519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik            if (mUseMasterVolume) {
257519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik                // If this device only uses master volume and playback is local
258519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik                // just adjust the master volume and return.
2592b5208c3583b5fd82564523bfd9e85b4bf44afa0Eric Laurent                boolean isMasterMute = mAudioManager.isMasterMute();
2607c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik                if (isMute) {
2612b5208c3583b5fd82564523bfd9e85b4bf44afa0Eric Laurent                    mAudioManagerInternal.setMasterMuteForUid(!isMasterMute,
2622610d71251e3e376e2514f20986c81e5d55f1b55RoboErik                            flags, packageName, mService.mICallback, uid);
2637c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik                } else {
2647c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik                    mAudioManagerInternal.adjustMasterVolumeForUid(direction, flags, packageName,
2657c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik                            uid);
2662b5208c3583b5fd82564523bfd9e85b4bf44afa0Eric Laurent                    if (isMasterMute) {
2672b5208c3583b5fd82564523bfd9e85b4bf44afa0Eric Laurent                        mAudioManagerInternal.setMasterMuteForUid(false,
2682610d71251e3e376e2514f20986c81e5d55f1b55RoboErik                                flags, packageName, mService.mICallback, uid);
2692b5208c3583b5fd82564523bfd9e85b4bf44afa0Eric Laurent                    }
2707c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik                }
271519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik                return;
272519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik            }
2739db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik            int stream = AudioAttributes.toLegacyStreamType(mAudioAttrs);
2742b5208c3583b5fd82564523bfd9e85b4bf44afa0Eric Laurent            boolean isStreamMute = mAudioManager.isStreamMute(stream);
275272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik            if (useSuggested) {
276165809b33198cd3926cc11e8cbc96b671d4c87d3RoboErik                if (AudioSystem.isStreamActive(stream, 0)) {
2777c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik                    if (isMute) {
2782b5208c3583b5fd82564523bfd9e85b4bf44afa0Eric Laurent                        mAudioManager.setStreamMute(stream, !isStreamMute);
2797c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik                    } else {
2807c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik                        mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(stream, direction,
2817c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik                                flags, packageName, uid);
2822610d71251e3e376e2514f20986c81e5d55f1b55RoboErik                        if (isStreamMute && direction != 0) {
2832b5208c3583b5fd82564523bfd9e85b4bf44afa0Eric Laurent                            mAudioManager.setStreamMute(stream, false);
2842b5208c3583b5fd82564523bfd9e85b4bf44afa0Eric Laurent                        }
2857c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik                    }
286165809b33198cd3926cc11e8cbc96b671d4c87d3RoboErik                } else {
287165809b33198cd3926cc11e8cbc96b671d4c87d3RoboErik                    flags |= previousFlagPlaySound;
2882b5208c3583b5fd82564523bfd9e85b4bf44afa0Eric Laurent                    isStreamMute =
2892b5208c3583b5fd82564523bfd9e85b4bf44afa0Eric Laurent                            mAudioManager.isStreamMute(AudioManager.USE_DEFAULT_STREAM_TYPE);
2907c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik                    if (isMute) {
2917c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik                        mAudioManager.setStreamMute(AudioManager.USE_DEFAULT_STREAM_TYPE,
2922b5208c3583b5fd82564523bfd9e85b4bf44afa0Eric Laurent                                !isStreamMute);
2937c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik                    } else {
2947c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik                        mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(
2957c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik                                AudioManager.USE_DEFAULT_STREAM_TYPE, direction, flags, packageName,
2967c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik                                uid);
2972610d71251e3e376e2514f20986c81e5d55f1b55RoboErik                        if (isStreamMute && direction != 0) {
2982b5208c3583b5fd82564523bfd9e85b4bf44afa0Eric Laurent                            mAudioManager.setStreamMute(AudioManager.USE_DEFAULT_STREAM_TYPE,
2992b5208c3583b5fd82564523bfd9e85b4bf44afa0Eric Laurent                                    false);
3002b5208c3583b5fd82564523bfd9e85b4bf44afa0Eric Laurent                        }
3017c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik                    }
302165809b33198cd3926cc11e8cbc96b671d4c87d3RoboErik                }
303272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik            } else {
3047c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik                if (isMute) {
3052b5208c3583b5fd82564523bfd9e85b4bf44afa0Eric Laurent                    mAudioManager.setStreamMute(stream, !isStreamMute);
3067c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik                } else {
3077c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik                    mAudioManagerInternal.adjustStreamVolumeForUid(stream, direction, flags,
3087c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik                            packageName, uid);
3092610d71251e3e376e2514f20986c81e5d55f1b55RoboErik                    if (isStreamMute && direction != 0) {
3102b5208c3583b5fd82564523bfd9e85b4bf44afa0Eric Laurent                        mAudioManager.setStreamMute(stream, false);
3112b5208c3583b5fd82564523bfd9e85b4bf44afa0Eric Laurent                    }
3127c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik                }
313272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik            }
314ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik        } else {
315ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik            if (mVolumeControlType == VolumeProvider.VOLUME_CONTROL_FIXED) {
316ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik                // Nothing to do, the volume cannot be changed
317ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik                return;
318ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik            }
3197c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik            if (isMute) {
3207c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik                Log.w(TAG, "Muting remote playback is not supported");
3217c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik                return;
3227c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik            }
3231ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik            mSessionCb.adjustVolume(direction);
32419c9518f6a817d53d5234de0020313cab6950b2fRoboErik
32519c9518f6a817d53d5234de0020313cab6950b2fRoboErik            int volumeBefore = (mOptimisticVolume < 0 ? mCurrentVolume : mOptimisticVolume);
3261ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik            mOptimisticVolume = volumeBefore + direction;
32719c9518f6a817d53d5234de0020313cab6950b2fRoboErik            mOptimisticVolume = Math.max(0, Math.min(mOptimisticVolume, mMaxVolume));
32819c9518f6a817d53d5234de0020313cab6950b2fRoboErik            mHandler.removeCallbacks(mClearOptimisticVolumeRunnable);
32919c9518f6a817d53d5234de0020313cab6950b2fRoboErik            mHandler.postDelayed(mClearOptimisticVolumeRunnable, OPTIMISTIC_VOLUME_TIMEOUT);
33019c9518f6a817d53d5234de0020313cab6950b2fRoboErik            if (volumeBefore != mOptimisticVolume) {
33119c9518f6a817d53d5234de0020313cab6950b2fRoboErik                pushVolumeUpdate();
33219c9518f6a817d53d5234de0020313cab6950b2fRoboErik            }
3339c5b7cb048699237b35dad7a2a634ed6efb997c7RoboErik            mService.notifyRemoteVolumeChanged(flags, this);
33419c9518f6a817d53d5234de0020313cab6950b2fRoboErik
33519c9518f6a817d53d5234de0020313cab6950b2fRoboErik            if (DEBUG) {
33619c9518f6a817d53d5234de0020313cab6950b2fRoboErik                Log.d(TAG, "Adjusted optimistic volume to " + mOptimisticVolume + " max is "
33719c9518f6a817d53d5234de0020313cab6950b2fRoboErik                        + mMaxVolume);
33819c9518f6a817d53d5234de0020313cab6950b2fRoboErik            }
339b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik        }
340b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik    }
341b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik
3420dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik    public void setVolumeTo(int value, int flags, String packageName, int uid) {
343d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik        if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
3449db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik            int stream = AudioAttributes.toLegacyStreamType(mAudioAttrs);
3450dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik            mAudioManagerInternal.setStreamVolumeForUid(stream, value, flags, packageName, uid);
346ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik        } else {
347ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik            if (mVolumeControlType != VolumeProvider.VOLUME_CONTROL_ABSOLUTE) {
348ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik                // Nothing to do. The volume can't be set directly.
349ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik                return;
350ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik            }
35119c9518f6a817d53d5234de0020313cab6950b2fRoboErik            value = Math.max(0, Math.min(value, mMaxVolume));
352ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik            mSessionCb.setVolumeTo(value);
35319c9518f6a817d53d5234de0020313cab6950b2fRoboErik
35419c9518f6a817d53d5234de0020313cab6950b2fRoboErik            int volumeBefore = (mOptimisticVolume < 0 ? mCurrentVolume : mOptimisticVolume);
35519c9518f6a817d53d5234de0020313cab6950b2fRoboErik            mOptimisticVolume = Math.max(0, Math.min(value, mMaxVolume));
35619c9518f6a817d53d5234de0020313cab6950b2fRoboErik            mHandler.removeCallbacks(mClearOptimisticVolumeRunnable);
35719c9518f6a817d53d5234de0020313cab6950b2fRoboErik            mHandler.postDelayed(mClearOptimisticVolumeRunnable, OPTIMISTIC_VOLUME_TIMEOUT);
35819c9518f6a817d53d5234de0020313cab6950b2fRoboErik            if (volumeBefore != mOptimisticVolume) {
35919c9518f6a817d53d5234de0020313cab6950b2fRoboErik                pushVolumeUpdate();
36019c9518f6a817d53d5234de0020313cab6950b2fRoboErik            }
3619c5b7cb048699237b35dad7a2a634ed6efb997c7RoboErik            mService.notifyRemoteVolumeChanged(flags, this);
36219c9518f6a817d53d5234de0020313cab6950b2fRoboErik
36319c9518f6a817d53d5234de0020313cab6950b2fRoboErik            if (DEBUG) {
36419c9518f6a817d53d5234de0020313cab6950b2fRoboErik                Log.d(TAG, "Set optimistic volume to " + mOptimisticVolume + " max is "
36519c9518f6a817d53d5234de0020313cab6950b2fRoboErik                        + mMaxVolume);
36619c9518f6a817d53d5234de0020313cab6950b2fRoboErik            }
367b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik        }
368b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik    }
369b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik
370b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik    /**
371a8f951462791a16f47e8c07e552232f31dcefac5RoboErik     * Check if this session has been set to active by the app.
372a8f951462791a16f47e8c07e552232f31dcefac5RoboErik     *
373a8f951462791a16f47e8c07e552232f31dcefac5RoboErik     * @return True if the session is active, false otherwise.
374a8f951462791a16f47e8c07e552232f31dcefac5RoboErik     */
375a8f951462791a16f47e8c07e552232f31dcefac5RoboErik    public boolean isActive() {
3764646d288821d62fdfe481be67d8b7fed7d7eabd8RoboErik        return mIsActive && !mDestroyed;
377a8f951462791a16f47e8c07e552232f31dcefac5RoboErik    }
378a8f951462791a16f47e8c07e552232f31dcefac5RoboErik
379a8f951462791a16f47e8c07e552232f31dcefac5RoboErik    /**
380a8f951462791a16f47e8c07e552232f31dcefac5RoboErik     * Check if the session is currently performing playback. This will also
381a8f951462791a16f47e8c07e552232f31dcefac5RoboErik     * return true if the session was recently paused.
38207c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik     *
383b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik     * @param includeRecentlyActive True if playback that was recently paused
384b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik     *            should count, false if it shouldn't.
385a8f951462791a16f47e8c07e552232f31dcefac5RoboErik     * @return True if the session is performing playback, false otherwise.
38607c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik     */
387b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik    public boolean isPlaybackActive(boolean includeRecentlyActive) {
388a8f951462791a16f47e8c07e552232f31dcefac5RoboErik        int state = mPlaybackState == null ? 0 : mPlaybackState.getState();
3893c45c29109d23981d8b707c809b3b43ce2e20fc3RoboErik        if (MediaSession.isActiveState(state)) {
390a8f951462791a16f47e8c07e552232f31dcefac5RoboErik            return true;
391a8f951462791a16f47e8c07e552232f31dcefac5RoboErik        }
392b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik        if (includeRecentlyActive && state == mPlaybackState.STATE_PAUSED) {
393a8f951462791a16f47e8c07e552232f31dcefac5RoboErik            long inactiveTime = SystemClock.uptimeMillis() - mLastActiveTime;
394a8f951462791a16f47e8c07e552232f31dcefac5RoboErik            if (inactiveTime < ACTIVE_BUFFER) {
395a8f951462791a16f47e8c07e552232f31dcefac5RoboErik                return true;
396a8f951462791a16f47e8c07e552232f31dcefac5RoboErik            }
397a8f951462791a16f47e8c07e552232f31dcefac5RoboErik        }
398a8f951462791a16f47e8c07e552232f31dcefac5RoboErik        return false;
399a8f951462791a16f47e8c07e552232f31dcefac5RoboErik    }
400a8f951462791a16f47e8c07e552232f31dcefac5RoboErik
4014646d288821d62fdfe481be67d8b7fed7d7eabd8RoboErik    /**
402b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik     * Get the type of playback, either local or remote.
403b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik     *
404b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik     * @return The current type of playback.
405b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik     */
406b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik    public int getPlaybackType() {
407ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik        return mVolumeType;
408b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik    }
409b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik
410b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik    /**
411b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik     * Get the local audio stream being used. Only valid if playback type is
412b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik     * local.
413b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik     *
414b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik     * @return The audio stream the session is using.
415b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik     */
4169db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik    public AudioAttributes getAudioAttributes() {
4179db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik        return mAudioAttrs;
418b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik    }
419b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik
420b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik    /**
421b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik     * Get the type of volume control. Only valid if playback type is remote.
422b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik     *
423b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik     * @return The volume control type being used.
424b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik     */
425b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik    public int getVolumeControl() {
426b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik        return mVolumeControlType;
427b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik    }
428b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik
429b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik    /**
430b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik     * Get the max volume that can be set. Only valid if playback type is
431b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik     * remote.
432b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik     *
433b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik     * @return The max volume that can be set.
434b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik     */
435b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik    public int getMaxVolume() {
436b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik        return mMaxVolume;
437b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik    }
438b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik
439b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik    /**
440b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik     * Get the current volume for this session. Only valid if playback type is
441b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik     * remote.
442b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik     *
443b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik     * @return The current volume of the remote playback.
444b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik     */
445b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik    public int getCurrentVolume() {
446b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik        return mCurrentVolume;
447b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik    }
448b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik
449b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik    /**
45019c9518f6a817d53d5234de0020313cab6950b2fRoboErik     * Get the volume we'd like it to be set to. This is only valid for a short
45119c9518f6a817d53d5234de0020313cab6950b2fRoboErik     * while after a call to adjust or set volume.
45219c9518f6a817d53d5234de0020313cab6950b2fRoboErik     *
45319c9518f6a817d53d5234de0020313cab6950b2fRoboErik     * @return The current optimistic volume or -1.
45419c9518f6a817d53d5234de0020313cab6950b2fRoboErik     */
45519c9518f6a817d53d5234de0020313cab6950b2fRoboErik    public int getOptimisticVolume() {
45619c9518f6a817d53d5234de0020313cab6950b2fRoboErik        return mOptimisticVolume;
45719c9518f6a817d53d5234de0020313cab6950b2fRoboErik    }
45819c9518f6a817d53d5234de0020313cab6950b2fRoboErik
459a8f951462791a16f47e8c07e552232f31dcefac5RoboErik    public boolean isTransportControlEnabled() {
46042ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik        return hasFlag(MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);
4618ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik    }
4628ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
46307c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik    @Override
46407c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik    public void binderDied() {
46507c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        mService.sessionDied(this);
46607c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik    }
46707c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik
4684646d288821d62fdfe481be67d8b7fed7d7eabd8RoboErik    /**
4694646d288821d62fdfe481be67d8b7fed7d7eabd8RoboErik     * Finish cleaning up this session, including disconnecting if connected and
4704646d288821d62fdfe481be67d8b7fed7d7eabd8RoboErik     * removing the death observer from the callback binder.
4714646d288821d62fdfe481be67d8b7fed7d7eabd8RoboErik     */
4724646d288821d62fdfe481be67d8b7fed7d7eabd8RoboErik    public void onDestroy() {
4734646d288821d62fdfe481be67d8b7fed7d7eabd8RoboErik        synchronized (mLock) {
4744646d288821d62fdfe481be67d8b7fed7d7eabd8RoboErik            if (mDestroyed) {
4754646d288821d62fdfe481be67d8b7fed7d7eabd8RoboErik                return;
4764646d288821d62fdfe481be67d8b7fed7d7eabd8RoboErik            }
4774646d288821d62fdfe481be67d8b7fed7d7eabd8RoboErik            mDestroyed = true;
47824762bffc3358762666079cd802040a316b3260dRoboErik            mHandler.post(MessageHandler.MSG_DESTROYED);
4794646d288821d62fdfe481be67d8b7fed7d7eabd8RoboErik        }
4804646d288821d62fdfe481be67d8b7fed7d7eabd8RoboErik    }
4814646d288821d62fdfe481be67d8b7fed7d7eabd8RoboErik
4824646d288821d62fdfe481be67d8b7fed7d7eabd8RoboErik    public ISessionCallback getCallback() {
4834646d288821d62fdfe481be67d8b7fed7d7eabd8RoboErik        return mSessionCb.mCb;
4844646d288821d62fdfe481be67d8b7fed7d7eabd8RoboErik    }
4854646d288821d62fdfe481be67d8b7fed7d7eabd8RoboErik
486418c10ca9df1505509afeffd558cd92fc97bc635RoboErik    public void sendMediaButton(KeyEvent ke, int sequenceId, ResultReceiver cb) {
487418c10ca9df1505509afeffd558cd92fc97bc635RoboErik        mSessionCb.sendMediaButton(ke, sequenceId, cb);
4888a2cfc309ab9126e90022916967c65a793c034f0RoboErik    }
4898a2cfc309ab9126e90022916967c65a793c034f0RoboErik
490a278ea7cecb59a73586e5dd74ec05e85caa370c5RoboErik    public void dump(PrintWriter pw, String prefix) {
491a278ea7cecb59a73586e5dd74ec05e85caa370c5RoboErik        pw.println(prefix + mTag + " " + this);
492a278ea7cecb59a73586e5dd74ec05e85caa370c5RoboErik
493a278ea7cecb59a73586e5dd74ec05e85caa370c5RoboErik        final String indent = prefix + "  ";
494a5b02329209be355eafadbdf9ee685ffa58d3148RoboErik        pw.println(indent + "ownerPid=" + mOwnerPid + ", ownerUid=" + mOwnerUid
495a5b02329209be355eafadbdf9ee685ffa58d3148RoboErik                + ", userId=" + mUserId);
496aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik        pw.println(indent + "package=" + mPackageName);
4977aef77bbf5b983b9f949936ed6cd174251697ca8RoboErik        pw.println(indent + "launchIntent=" + mLaunchIntent);
4987aef77bbf5b983b9f949936ed6cd174251697ca8RoboErik        pw.println(indent + "mediaButtonReceiver=" + mMediaButtonReceiver);
4994646d288821d62fdfe481be67d8b7fed7d7eabd8RoboErik        pw.println(indent + "active=" + mIsActive);
500a8f951462791a16f47e8c07e552232f31dcefac5RoboErik        pw.println(indent + "flags=" + mFlags);
501a278ea7cecb59a73586e5dd74ec05e85caa370c5RoboErik        pw.println(indent + "rating type=" + mRatingType);
502a278ea7cecb59a73586e5dd74ec05e85caa370c5RoboErik        pw.println(indent + "controllers: " + mControllerCallbacks.size());
503a8f951462791a16f47e8c07e552232f31dcefac5RoboErik        pw.println(indent + "state=" + (mPlaybackState == null ? null : mPlaybackState.toString()));
5047aef77bbf5b983b9f949936ed6cd174251697ca8RoboErik        pw.println(indent + "audioAttrs=" + mAudioAttrs);
5057aef77bbf5b983b9f949936ed6cd174251697ca8RoboErik        pw.println(indent + "volumeType=" + mVolumeType + ", controlType=" + mVolumeControlType
5067aef77bbf5b983b9f949936ed6cd174251697ca8RoboErik                + ", max=" + mMaxVolume + ", current=" + mCurrentVolume);
50766dea73906f24226a6f699759e79040726bde8b5RoboErik        pw.println(indent + "metadata:" + getShortMetadataString());
5087aef77bbf5b983b9f949936ed6cd174251697ca8RoboErik        pw.println(indent + "queueTitle=" + mQueueTitle + ", size="
5097aef77bbf5b983b9f949936ed6cd174251697ca8RoboErik                + (mQueue == null ? 0 : mQueue.getList().size()));
510a278ea7cecb59a73586e5dd74ec05e85caa370c5RoboErik    }
511a278ea7cecb59a73586e5dd74ec05e85caa370c5RoboErik
512aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik    @Override
513aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik    public String toString() {
514aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik        return mPackageName + "/" + mTag;
515aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik    }
516aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik
51766dea73906f24226a6f699759e79040726bde8b5RoboErik    private String getShortMetadataString() {
51866dea73906f24226a6f699759e79040726bde8b5RoboErik        int fields = mMetadata == null ? 0 : mMetadata.size();
5193625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik        MediaDescription description = mMetadata == null ? null : mMetadata
52075847b98f39e521a57042c50e69be9e142788d32RoboErik                .getDescription();
52175847b98f39e521a57042c50e69be9e142788d32RoboErik        return "size=" + fields + ", description=" + description;
52266dea73906f24226a6f699759e79040726bde8b5RoboErik    }
52366dea73906f24226a6f699759e79040726bde8b5RoboErik
5248ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik    private void pushPlaybackStateUpdate() {
52507c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        synchronized (mLock) {
5264646d288821d62fdfe481be67d8b7fed7d7eabd8RoboErik            if (mDestroyed) {
5274646d288821d62fdfe481be67d8b7fed7d7eabd8RoboErik                return;
5284646d288821d62fdfe481be67d8b7fed7d7eabd8RoboErik            }
5298ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
53007c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik                ISessionControllerCallback cb = mControllerCallbacks.get(i);
5318ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                try {
5328ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                    cb.onPlaybackStateChanged(mPlaybackState);
533d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik                } catch (DeadObjectException e) {
5348ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                    mControllerCallbacks.remove(i);
53519c9518f6a817d53d5234de0020313cab6950b2fRoboErik                    Log.w(TAG, "Removed dead callback in pushPlaybackStateUpdate.", e);
536d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik                } catch (RemoteException e) {
537d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik                    Log.w(TAG, "unexpected exception in pushPlaybackStateUpdate.", e);
5388ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                }
5398ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            }
5408ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
5418ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik    }
54201fe661ae5da3739215d93922412df4b24c859a2RoboErik
5438ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik    private void pushMetadataUpdate() {
54407c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        synchronized (mLock) {
5454646d288821d62fdfe481be67d8b7fed7d7eabd8RoboErik            if (mDestroyed) {
5464646d288821d62fdfe481be67d8b7fed7d7eabd8RoboErik                return;
5474646d288821d62fdfe481be67d8b7fed7d7eabd8RoboErik            }
5488ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
54907c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik                ISessionControllerCallback cb = mControllerCallbacks.get(i);
5508ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                try {
5518ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                    cb.onMetadataChanged(mMetadata);
552d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik                } catch (DeadObjectException e) {
55319c9518f6a817d53d5234de0020313cab6950b2fRoboErik                    Log.w(TAG, "Removing dead callback in pushMetadataUpdate. ", e);
5548ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                    mControllerCallbacks.remove(i);
555d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik                } catch (RemoteException e) {
55619c9518f6a817d53d5234de0020313cab6950b2fRoboErik                    Log.w(TAG, "unexpected exception in pushMetadataUpdate. ", e);
55719c9518f6a817d53d5234de0020313cab6950b2fRoboErik                }
55819c9518f6a817d53d5234de0020313cab6950b2fRoboErik            }
55919c9518f6a817d53d5234de0020313cab6950b2fRoboErik        }
56019c9518f6a817d53d5234de0020313cab6950b2fRoboErik    }
56119c9518f6a817d53d5234de0020313cab6950b2fRoboErik
562f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal    private void pushQueueUpdate() {
563f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        synchronized (mLock) {
564f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            if (mDestroyed) {
565f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                return;
566f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            }
567f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
568f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                ISessionControllerCallback cb = mControllerCallbacks.get(i);
569f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                try {
570f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                    cb.onQueueChanged(mQueue);
571f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                } catch (DeadObjectException e) {
572f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                    mControllerCallbacks.remove(i);
573f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                    Log.w(TAG, "Removed dead callback in pushQueueUpdate.", e);
574f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                } catch (RemoteException e) {
575f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                    Log.w(TAG, "unexpected exception in pushQueueUpdate.", e);
576f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                }
577f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            }
578f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        }
579f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal    }
580f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
581f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal    private void pushQueueTitleUpdate() {
582f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        synchronized (mLock) {
583f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            if (mDestroyed) {
584f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                return;
585f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            }
586f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
587f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                ISessionControllerCallback cb = mControllerCallbacks.get(i);
588f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                try {
589f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                    cb.onQueueTitleChanged(mQueueTitle);
590f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                } catch (DeadObjectException e) {
591f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                    mControllerCallbacks.remove(i);
592f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                    Log.w(TAG, "Removed dead callback in pushQueueTitleUpdate.", e);
593f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                } catch (RemoteException e) {
594f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                    Log.w(TAG, "unexpected exception in pushQueueTitleUpdate.", e);
595f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                }
596f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            }
597f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        }
598f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal    }
599f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
600f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal    private void pushExtrasUpdate() {
601f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        synchronized (mLock) {
602f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            if (mDestroyed) {
603f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                return;
604f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            }
605f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
606f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                ISessionControllerCallback cb = mControllerCallbacks.get(i);
607f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                try {
608f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                    cb.onExtrasChanged(mExtras);
609f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                } catch (DeadObjectException e) {
610f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                    mControllerCallbacks.remove(i);
611f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                    Log.w(TAG, "Removed dead callback in pushExtrasUpdate.", e);
612f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                } catch (RemoteException e) {
613f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                    Log.w(TAG, "unexpected exception in pushExtrasUpdate.", e);
614f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                }
615f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            }
616f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        }
617f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal    }
618f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
61919c9518f6a817d53d5234de0020313cab6950b2fRoboErik    private void pushVolumeUpdate() {
62019c9518f6a817d53d5234de0020313cab6950b2fRoboErik        synchronized (mLock) {
62119c9518f6a817d53d5234de0020313cab6950b2fRoboErik            if (mDestroyed) {
62219c9518f6a817d53d5234de0020313cab6950b2fRoboErik                return;
62319c9518f6a817d53d5234de0020313cab6950b2fRoboErik            }
62419c9518f6a817d53d5234de0020313cab6950b2fRoboErik            ParcelableVolumeInfo info = mController.getVolumeAttributes();
62519c9518f6a817d53d5234de0020313cab6950b2fRoboErik            for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
62619c9518f6a817d53d5234de0020313cab6950b2fRoboErik                ISessionControllerCallback cb = mControllerCallbacks.get(i);
62719c9518f6a817d53d5234de0020313cab6950b2fRoboErik                try {
62819c9518f6a817d53d5234de0020313cab6950b2fRoboErik                    cb.onVolumeInfoChanged(info);
62919c9518f6a817d53d5234de0020313cab6950b2fRoboErik                } catch (DeadObjectException e) {
63019c9518f6a817d53d5234de0020313cab6950b2fRoboErik                    Log.w(TAG, "Removing dead callback in pushVolumeUpdate. ", e);
63119c9518f6a817d53d5234de0020313cab6950b2fRoboErik                } catch (RemoteException e) {
63219c9518f6a817d53d5234de0020313cab6950b2fRoboErik                    Log.w(TAG, "Unexpected exception in pushVolumeUpdate. ", e);
6338ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                }
6348ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            }
63501fe661ae5da3739215d93922412df4b24c859a2RoboErik        }
6368ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik    }
6378ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
6388ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik    private void pushEvent(String event, Bundle data) {
63907c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        synchronized (mLock) {
6404646d288821d62fdfe481be67d8b7fed7d7eabd8RoboErik            if (mDestroyed) {
6414646d288821d62fdfe481be67d8b7fed7d7eabd8RoboErik                return;
6424646d288821d62fdfe481be67d8b7fed7d7eabd8RoboErik            }
6438ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
64407c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik                ISessionControllerCallback cb = mControllerCallbacks.get(i);
6458ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                try {
6468ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                    cb.onEvent(event, data);
647d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik                } catch (DeadObjectException e) {
648d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik                    Log.w(TAG, "Removing dead callback in pushEvent.", e);
649d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik                    mControllerCallbacks.remove(i);
6508ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                } catch (RemoteException e) {
651d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik                    Log.w(TAG, "unexpected exception in pushEvent.", e);
6528ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                }
6538ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            }
6548ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
6558ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik    }
6568ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
65724762bffc3358762666079cd802040a316b3260dRoboErik    private void pushSessionDestroyed() {
65824762bffc3358762666079cd802040a316b3260dRoboErik        synchronized (mLock) {
65924762bffc3358762666079cd802040a316b3260dRoboErik            // This is the only method that may be (and can only be) called
66024762bffc3358762666079cd802040a316b3260dRoboErik            // after the session is destroyed.
66124762bffc3358762666079cd802040a316b3260dRoboErik            if (!mDestroyed) {
66224762bffc3358762666079cd802040a316b3260dRoboErik                return;
66324762bffc3358762666079cd802040a316b3260dRoboErik            }
66424762bffc3358762666079cd802040a316b3260dRoboErik            for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
66524762bffc3358762666079cd802040a316b3260dRoboErik                ISessionControllerCallback cb = mControllerCallbacks.get(i);
66624762bffc3358762666079cd802040a316b3260dRoboErik                try {
66724762bffc3358762666079cd802040a316b3260dRoboErik                    cb.onSessionDestroyed();
66824762bffc3358762666079cd802040a316b3260dRoboErik                } catch (DeadObjectException e) {
66924762bffc3358762666079cd802040a316b3260dRoboErik                    Log.w(TAG, "Removing dead callback in pushEvent.", e);
67024762bffc3358762666079cd802040a316b3260dRoboErik                    mControllerCallbacks.remove(i);
67124762bffc3358762666079cd802040a316b3260dRoboErik                } catch (RemoteException e) {
67224762bffc3358762666079cd802040a316b3260dRoboErik                    Log.w(TAG, "unexpected exception in pushEvent.", e);
67324762bffc3358762666079cd802040a316b3260dRoboErik                }
67424762bffc3358762666079cd802040a316b3260dRoboErik            }
67524762bffc3358762666079cd802040a316b3260dRoboErik            // After notifying clear all listeners
67624762bffc3358762666079cd802040a316b3260dRoboErik            mControllerCallbacks.clear();
67724762bffc3358762666079cd802040a316b3260dRoboErik        }
67824762bffc3358762666079cd802040a316b3260dRoboErik    }
67924762bffc3358762666079cd802040a316b3260dRoboErik
680f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik    private PlaybackState getStateWithUpdatedPosition() {
681df382cada180033e5bbde82998b73ef19e541ed2RoboErik        PlaybackState state;
68282df2c0839876d158889ea0e28e6f3adf0d4797dRoboErik        long duration = -1;
683df382cada180033e5bbde82998b73ef19e541ed2RoboErik        synchronized (mLock) {
684df382cada180033e5bbde82998b73ef19e541ed2RoboErik            state = mPlaybackState;
68582df2c0839876d158889ea0e28e6f3adf0d4797dRoboErik            if (mMetadata != null && mMetadata.containsKey(MediaMetadata.METADATA_KEY_DURATION)) {
68682df2c0839876d158889ea0e28e6f3adf0d4797dRoboErik                duration = mMetadata.getLong(MediaMetadata.METADATA_KEY_DURATION);
68782df2c0839876d158889ea0e28e6f3adf0d4797dRoboErik            }
688f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik        }
689f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik        PlaybackState result = null;
690f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik        if (state != null) {
69179fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik            if (state.getState() == PlaybackState.STATE_PLAYING
69279fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik                    || state.getState() == PlaybackState.STATE_FAST_FORWARDING
69379fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik                    || state.getState() == PlaybackState.STATE_REWINDING) {
694f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                long updateTime = state.getLastPositionUpdateTime();
695c785a78fb483fe54012175c53d3758b2412de7b9RoboErik                long currentTime = SystemClock.elapsedRealtime();
696f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                if (updateTime > 0) {
697c785a78fb483fe54012175c53d3758b2412de7b9RoboErik                    long position = (long) (state.getPlaybackSpeed()
698c785a78fb483fe54012175c53d3758b2412de7b9RoboErik                            * (currentTime - updateTime)) + state.getPosition();
699f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                    if (duration >= 0 && position > duration) {
700f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                        position = duration;
701f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                    } else if (position < 0) {
702f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                        position = 0;
703f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                    }
704c785a78fb483fe54012175c53d3758b2412de7b9RoboErik                    PlaybackState.Builder builder = new PlaybackState.Builder(state);
705c785a78fb483fe54012175c53d3758b2412de7b9RoboErik                    builder.setState(state.getState(), position, state.getPlaybackSpeed(),
706c785a78fb483fe54012175c53d3758b2412de7b9RoboErik                            currentTime);
707c785a78fb483fe54012175c53d3758b2412de7b9RoboErik                    result = builder.build();
708f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                }
709f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik            }
710f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik        }
711f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik        return result == null ? state : result;
712f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik    }
713f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik
714d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik    private int getControllerCbIndexForCb(ISessionControllerCallback cb) {
715d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik        IBinder binder = cb.asBinder();
716d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik        for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
717d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik            if (binder.equals(mControllerCallbacks.get(i).asBinder())) {
718d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik                return i;
719d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik            }
720d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik        }
721d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik        return -1;
722d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik    }
723d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik
72419c9518f6a817d53d5234de0020313cab6950b2fRoboErik    private final Runnable mClearOptimisticVolumeRunnable = new Runnable() {
72519c9518f6a817d53d5234de0020313cab6950b2fRoboErik        @Override
72619c9518f6a817d53d5234de0020313cab6950b2fRoboErik        public void run() {
72719c9518f6a817d53d5234de0020313cab6950b2fRoboErik            boolean needUpdate = (mOptimisticVolume != mCurrentVolume);
72819c9518f6a817d53d5234de0020313cab6950b2fRoboErik            mOptimisticVolume = -1;
72919c9518f6a817d53d5234de0020313cab6950b2fRoboErik            if (needUpdate) {
73019c9518f6a817d53d5234de0020313cab6950b2fRoboErik                pushVolumeUpdate();
73119c9518f6a817d53d5234de0020313cab6950b2fRoboErik            }
73219c9518f6a817d53d5234de0020313cab6950b2fRoboErik        }
73319c9518f6a817d53d5234de0020313cab6950b2fRoboErik    };
73419c9518f6a817d53d5234de0020313cab6950b2fRoboErik
73507c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik    private final class SessionStub extends ISession.Stub {
73601fe661ae5da3739215d93922412df4b24c859a2RoboErik        @Override
73707c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        public void destroy() {
7384646d288821d62fdfe481be67d8b7fed7d7eabd8RoboErik            mService.destroySession(MediaSessionRecord.this);
73901fe661ae5da3739215d93922412df4b24c859a2RoboErik        }
74001fe661ae5da3739215d93922412df4b24c859a2RoboErik
74101fe661ae5da3739215d93922412df4b24c859a2RoboErik        @Override
74207c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        public void sendEvent(String event, Bundle data) {
743df382cada180033e5bbde82998b73ef19e541ed2RoboErik            mHandler.post(MessageHandler.MSG_SEND_EVENT, event,
744df382cada180033e5bbde82998b73ef19e541ed2RoboErik                    data == null ? null : new Bundle(data));
7458ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
7468ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
7478ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        @Override
74807c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        public ISessionController getController() {
74907c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik            return mController;
7508ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
7518ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
7528ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        @Override
753a8f951462791a16f47e8c07e552232f31dcefac5RoboErik        public void setActive(boolean active) {
754a8f951462791a16f47e8c07e552232f31dcefac5RoboErik            mIsActive = active;
755a8f951462791a16f47e8c07e552232f31dcefac5RoboErik            mService.updateSession(MediaSessionRecord.this);
756a8f951462791a16f47e8c07e552232f31dcefac5RoboErik            mHandler.post(MessageHandler.MSG_UPDATE_SESSION_STATE);
75701fe661ae5da3739215d93922412df4b24c859a2RoboErik        }
75801fe661ae5da3739215d93922412df4b24c859a2RoboErik
75901fe661ae5da3739215d93922412df4b24c859a2RoboErik        @Override
760a8f951462791a16f47e8c07e552232f31dcefac5RoboErik        public void setFlags(int flags) {
76142ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik            if ((flags & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) {
762e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik                int pid = getCallingPid();
763e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik                int uid = getCallingUid();
764e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik                mService.enforcePhoneStatePermission(pid, uid);
765e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik            }
766e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik            mFlags = flags;
767a8f951462791a16f47e8c07e552232f31dcefac5RoboErik            mHandler.post(MessageHandler.MSG_UPDATE_SESSION_STATE);
768e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik        }
769e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik
770e7880d8eb1903d42e4e2a90c99b58e2240e01e82RoboErik        @Override
771b214efbb9170a9f6a4991684a63ca59680074cc7RoboErik        public void setMediaButtonReceiver(PendingIntent pi) {
772b214efbb9170a9f6a4991684a63ca59680074cc7RoboErik            mMediaButtonReceiver = pi;
7736f0e4ddd66fcdcc13944d8970d0b560e2626508bRoboErik        }
7746f0e4ddd66fcdcc13944d8970d0b560e2626508bRoboErik
7756f0e4ddd66fcdcc13944d8970d0b560e2626508bRoboErik        @Override
776e34c09daf89fb888fe2638e71758573462d85173RoboErik        public void setLaunchPendingIntent(PendingIntent pi) {
777e34c09daf89fb888fe2638e71758573462d85173RoboErik            mLaunchIntent = pi;
778e34c09daf89fb888fe2638e71758573462d85173RoboErik        }
779e34c09daf89fb888fe2638e71758573462d85173RoboErik
780e34c09daf89fb888fe2638e71758573462d85173RoboErik        @Override
7818ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public void setMetadata(MediaMetadata metadata) {
782df382cada180033e5bbde82998b73ef19e541ed2RoboErik            synchronized (mLock) {
78382df2c0839876d158889ea0e28e6f3adf0d4797dRoboErik                MediaMetadata temp = metadata == null ? null : new MediaMetadata.Builder(metadata)
78482df2c0839876d158889ea0e28e6f3adf0d4797dRoboErik                        .build();
78582df2c0839876d158889ea0e28e6f3adf0d4797dRoboErik                // This is to guarantee that the underlying bundle is unparceled
78682df2c0839876d158889ea0e28e6f3adf0d4797dRoboErik                // before we set it to prevent concurrent reads from throwing an
78782df2c0839876d158889ea0e28e6f3adf0d4797dRoboErik                // exception
788421c9df7ff52f8c43fd5356a59702931f39dc029RoboErik                if (temp != null) {
789421c9df7ff52f8c43fd5356a59702931f39dc029RoboErik                    temp.size();
790421c9df7ff52f8c43fd5356a59702931f39dc029RoboErik                }
79182df2c0839876d158889ea0e28e6f3adf0d4797dRoboErik                mMetadata = temp;
792df382cada180033e5bbde82998b73ef19e541ed2RoboErik            }
7938ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            mHandler.post(MessageHandler.MSG_UPDATE_METADATA);
79401fe661ae5da3739215d93922412df4b24c859a2RoboErik        }
79501fe661ae5da3739215d93922412df4b24c859a2RoboErik
7968ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        @Override
7978ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public void setPlaybackState(PlaybackState state) {
798a8f951462791a16f47e8c07e552232f31dcefac5RoboErik            int oldState = mPlaybackState == null ? 0 : mPlaybackState.getState();
799a8f951462791a16f47e8c07e552232f31dcefac5RoboErik            int newState = state == null ? 0 : state.getState();
8003c45c29109d23981d8b707c809b3b43ce2e20fc3RoboErik            if (MediaSession.isActiveState(oldState) && newState == PlaybackState.STATE_PAUSED) {
801a8f951462791a16f47e8c07e552232f31dcefac5RoboErik                mLastActiveTime = SystemClock.elapsedRealtime();
802a8f951462791a16f47e8c07e552232f31dcefac5RoboErik            }
803df382cada180033e5bbde82998b73ef19e541ed2RoboErik            synchronized (mLock) {
804df382cada180033e5bbde82998b73ef19e541ed2RoboErik                mPlaybackState = state;
805df382cada180033e5bbde82998b73ef19e541ed2RoboErik            }
806a8f951462791a16f47e8c07e552232f31dcefac5RoboErik            mService.onSessionPlaystateChange(MediaSessionRecord.this, oldState, newState);
8078ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            mHandler.post(MessageHandler.MSG_UPDATE_PLAYBACK_STATE);
8088ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
8098ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
8108ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        @Override
811f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        public void setQueue(ParceledListSlice queue) {
812df382cada180033e5bbde82998b73ef19e541ed2RoboErik            synchronized (mLock) {
813df382cada180033e5bbde82998b73ef19e541ed2RoboErik                mQueue = queue;
814df382cada180033e5bbde82998b73ef19e541ed2RoboErik            }
815f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            mHandler.post(MessageHandler.MSG_UPDATE_QUEUE);
816f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        }
817f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
818f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        @Override
819f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        public void setQueueTitle(CharSequence title) {
820f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            mQueueTitle = title;
821f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            mHandler.post(MessageHandler.MSG_UPDATE_QUEUE_TITLE);
822f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        }
823f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
824f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        @Override
825f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        public void setExtras(Bundle extras) {
826df382cada180033e5bbde82998b73ef19e541ed2RoboErik            synchronized (mLock) {
827df382cada180033e5bbde82998b73ef19e541ed2RoboErik                mExtras = extras == null ? null : new Bundle(extras);
828df382cada180033e5bbde82998b73ef19e541ed2RoboErik            }
829f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            mHandler.post(MessageHandler.MSG_UPDATE_EXTRAS);
830f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        }
831f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
832f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        @Override
8338ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public void setRatingType(int type) {
8348ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            mRatingType = type;
8358ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
83607c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik
83707c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        @Override
838b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik        public void setCurrentVolume(int volume) {
839b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik            mCurrentVolume = volume;
84019c9518f6a817d53d5234de0020313cab6950b2fRoboErik            mHandler.post(MessageHandler.MSG_UPDATE_VOLUME);
841b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik        }
842b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik
843b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik        @Override
8449db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik        public void setPlaybackToLocal(AudioAttributes attributes) {
8459db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik            boolean typeChanged;
8469db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik            synchronized (mLock) {
847d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik                typeChanged = mVolumeType == PlaybackInfo.PLAYBACK_TYPE_REMOTE;
848d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik                mVolumeType = PlaybackInfo.PLAYBACK_TYPE_LOCAL;
8499db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik                if (attributes != null) {
8509db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik                    mAudioAttrs = attributes;
8519db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik                } else {
8529db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik                    Log.e(TAG, "Received null audio attributes, using existing attributes");
8539db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik                }
854b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik            }
85519c9518f6a817d53d5234de0020313cab6950b2fRoboErik            if (typeChanged) {
85619c9518f6a817d53d5234de0020313cab6950b2fRoboErik                mService.onSessionPlaybackTypeChanged(MediaSessionRecord.this);
85719c9518f6a817d53d5234de0020313cab6950b2fRoboErik            }
858b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik        }
859b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik
8609db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik        @Override
8619db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik        public void setPlaybackToRemote(int control, int max) {
8629db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik            boolean typeChanged;
8639db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik            synchronized (mLock) {
864d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik                typeChanged = mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL;
865d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik                mVolumeType = PlaybackInfo.PLAYBACK_TYPE_REMOTE;
8669db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik                mVolumeControlType = control;
8679db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik                mMaxVolume = max;
8689db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik            }
8699db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik            if (typeChanged) {
8709db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik                mService.onSessionPlaybackTypeChanged(MediaSessionRecord.this);
8719db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik            }
872b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik        }
87301fe661ae5da3739215d93922412df4b24c859a2RoboErik    }
87401fe661ae5da3739215d93922412df4b24c859a2RoboErik
87501fe661ae5da3739215d93922412df4b24c859a2RoboErik    class SessionCb {
87607c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        private final ISessionCallback mCb;
87701fe661ae5da3739215d93922412df4b24c859a2RoboErik
87807c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        public SessionCb(ISessionCallback cb) {
87901fe661ae5da3739215d93922412df4b24c859a2RoboErik            mCb = cb;
88001fe661ae5da3739215d93922412df4b24c859a2RoboErik        }
88101fe661ae5da3739215d93922412df4b24c859a2RoboErik
88279fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik        public boolean sendMediaButton(KeyEvent keyEvent, int sequenceId, ResultReceiver cb) {
88301fe661ae5da3739215d93922412df4b24c859a2RoboErik            Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
88401fe661ae5da3739215d93922412df4b24c859a2RoboErik            mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
88501fe661ae5da3739215d93922412df4b24c859a2RoboErik            try {
886418c10ca9df1505509afeffd558cd92fc97bc635RoboErik                mCb.onMediaButton(mediaButtonIntent, sequenceId, cb);
88779fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik                return true;
88801fe661ae5da3739215d93922412df4b24c859a2RoboErik            } catch (RemoteException e) {
8898ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                Slog.e(TAG, "Remote failure in sendMediaRequest.", e);
8908ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            }
89179fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik            return false;
8928ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
8938ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
894f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal        public void sendCommand(String command, Bundle args, ResultReceiver cb) {
8958ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            try {
896f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal                mCb.onCommand(command, args, cb);
8978ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            } catch (RemoteException e) {
8988ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                Slog.e(TAG, "Remote failure in sendCommand.", e);
8998ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            }
9008ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
9018ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
902f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal        public void sendCustomAction(String action, Bundle args) {
903f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal            try {
904f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal                mCb.onCustomAction(action, args);
905f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal            } catch (RemoteException e) {
906f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal                Slog.e(TAG, "Remote failure in sendCustomAction.", e);
907f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal            }
908f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal        }
909f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal
9108ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public void play() {
9118ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            try {
9128ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                mCb.onPlay();
9138ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            } catch (RemoteException e) {
9148ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                Slog.e(TAG, "Remote failure in play.", e);
91501fe661ae5da3739215d93922412df4b24c859a2RoboErik            }
91601fe661ae5da3739215d93922412df4b24c859a2RoboErik        }
91701fe661ae5da3739215d93922412df4b24c859a2RoboErik
9183625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik        public void playFromMediaId(String mediaId, Bundle extras) {
919f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            try {
9203625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik                mCb.onPlayFromMediaId(mediaId, extras);
921f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            } catch (RemoteException e) {
922f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                Slog.e(TAG, "Remote failure in playUri.", e);
923f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            }
924f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        }
925f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
926f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        public void playFromSearch(String query, Bundle extras) {
927f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            try {
928f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                mCb.onPlayFromSearch(query, extras);
929f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            } catch (RemoteException e) {
930f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                Slog.e(TAG, "Remote failure in playFromSearch.", e);
931f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            }
932f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        }
933f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
934f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        public void skipToTrack(long id) {
935f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            try {
936f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                mCb.onSkipToTrack(id);
937f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            } catch (RemoteException e) {
938f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                Slog.e(TAG, "Remote failure in skipToTrack", e);
939f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            }
940f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        }
941f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
9428ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public void pause() {
94301fe661ae5da3739215d93922412df4b24c859a2RoboErik            try {
9448ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                mCb.onPause();
94501fe661ae5da3739215d93922412df4b24c859a2RoboErik            } catch (RemoteException e) {
9468ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                Slog.e(TAG, "Remote failure in pause.", e);
94701fe661ae5da3739215d93922412df4b24c859a2RoboErik            }
94801fe661ae5da3739215d93922412df4b24c859a2RoboErik        }
94901fe661ae5da3739215d93922412df4b24c859a2RoboErik
9508ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public void stop() {
9518ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            try {
9528ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                mCb.onStop();
9538ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            } catch (RemoteException e) {
9548ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                Slog.e(TAG, "Remote failure in stop.", e);
9558ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            }
9568ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
95701fe661ae5da3739215d93922412df4b24c859a2RoboErik
9588ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public void next() {
9598ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            try {
9608ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                mCb.onNext();
9618ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            } catch (RemoteException e) {
9628ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                Slog.e(TAG, "Remote failure in next.", e);
9638ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            }
96401fe661ae5da3739215d93922412df4b24c859a2RoboErik        }
96501fe661ae5da3739215d93922412df4b24c859a2RoboErik
9668ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public void previous() {
9678ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            try {
9688ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                mCb.onPrevious();
9698ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            } catch (RemoteException e) {
9708ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                Slog.e(TAG, "Remote failure in previous.", e);
9718ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            }
9728ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
9738ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
9748ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public void fastForward() {
9758ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            try {
9768ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                mCb.onFastForward();
9778ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            } catch (RemoteException e) {
9788ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                Slog.e(TAG, "Remote failure in fastForward.", e);
9798ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            }
9808ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
9818ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
9828ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public void rewind() {
9838ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            try {
9848ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                mCb.onRewind();
9858ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            } catch (RemoteException e) {
9868ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                Slog.e(TAG, "Remote failure in rewind.", e);
9878ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            }
9888ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
9898ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
9908ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public void seekTo(long pos) {
9918ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            try {
9928ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                mCb.onSeekTo(pos);
9938ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            } catch (RemoteException e) {
9948ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                Slog.e(TAG, "Remote failure in seekTo.", e);
9958ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            }
9968ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
9978ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
9988ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public void rate(Rating rating) {
9998ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            try {
10008ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                mCb.onRate(rating);
10018ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            } catch (RemoteException e) {
10028ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                Slog.e(TAG, "Remote failure in rate.", e);
10038ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            }
10048ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
1005b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik
10061ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik        public void adjustVolume(int direction) {
1007b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik            try {
10081ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik                mCb.onAdjustVolume(direction);
1009b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik            } catch (RemoteException e) {
10101ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik                Slog.e(TAG, "Remote failure in adjustVolume.", e);
1011b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik            }
1012b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik        }
1013b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik
1014b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik        public void setVolumeTo(int value) {
1015b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik            try {
1016b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik                mCb.onSetVolumeTo(value);
1017b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik            } catch (RemoteException e) {
10181ff5b1648a051e9650614f0c0f1b3f449777db81RoboErik                Slog.e(TAG, "Remote failure in setVolumeTo.", e);
1019b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik            }
1020b69ffd4dc2c8fa85e0064151141ebeee90de471eRoboErik        }
102101fe661ae5da3739215d93922412df4b24c859a2RoboErik    }
102201fe661ae5da3739215d93922412df4b24c859a2RoboErik
102307c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik    class ControllerStub extends ISessionController.Stub {
102401fe661ae5da3739215d93922412df4b24c859a2RoboErik        @Override
1025f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal        public void sendCommand(String command, Bundle args, ResultReceiver cb)
10268ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                throws RemoteException {
1027f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal            mSessionCb.sendCommand(command, args, cb);
102801fe661ae5da3739215d93922412df4b24c859a2RoboErik        }
102901fe661ae5da3739215d93922412df4b24c859a2RoboErik
103001fe661ae5da3739215d93922412df4b24c859a2RoboErik        @Override
103179fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik        public boolean sendMediaButton(KeyEvent mediaButtonIntent) {
103279fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik            return mSessionCb.sendMediaButton(mediaButtonIntent, 0, null);
103301fe661ae5da3739215d93922412df4b24c859a2RoboErik        }
103401fe661ae5da3739215d93922412df4b24c859a2RoboErik
103501fe661ae5da3739215d93922412df4b24c859a2RoboErik        @Override
103607c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        public void registerCallbackListener(ISessionControllerCallback cb) {
103707c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik            synchronized (mLock) {
103824762bffc3358762666079cd802040a316b3260dRoboErik                // If this session is already destroyed tell the caller and
103924762bffc3358762666079cd802040a316b3260dRoboErik                // don't add them.
104024762bffc3358762666079cd802040a316b3260dRoboErik                if (mDestroyed) {
104124762bffc3358762666079cd802040a316b3260dRoboErik                    try {
104224762bffc3358762666079cd802040a316b3260dRoboErik                        cb.onSessionDestroyed();
104324762bffc3358762666079cd802040a316b3260dRoboErik                    } catch (Exception e) {
104424762bffc3358762666079cd802040a316b3260dRoboErik                        // ignored
104524762bffc3358762666079cd802040a316b3260dRoboErik                    }
104624762bffc3358762666079cd802040a316b3260dRoboErik                    return;
104724762bffc3358762666079cd802040a316b3260dRoboErik                }
1048d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik                if (getControllerCbIndexForCb(cb) < 0) {
10498ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                    mControllerCallbacks.add(cb);
1050d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik                    if (DEBUG) {
1051d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik                        Log.d(TAG, "registering controller callback " + cb);
1052d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik                    }
10538ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                }
105401fe661ae5da3739215d93922412df4b24c859a2RoboErik            }
105501fe661ae5da3739215d93922412df4b24c859a2RoboErik        }
105601fe661ae5da3739215d93922412df4b24c859a2RoboErik
105701fe661ae5da3739215d93922412df4b24c859a2RoboErik        @Override
105807c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        public void unregisterCallbackListener(ISessionControllerCallback cb)
105901fe661ae5da3739215d93922412df4b24c859a2RoboErik                throws RemoteException {
106007c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik            synchronized (mLock) {
1061d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik                int index = getControllerCbIndexForCb(cb);
1062d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik                if (index != -1) {
1063d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik                    mControllerCallbacks.remove(index);
1064d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik                }
1065d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik                if (DEBUG) {
1066d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik                    Log.d(TAG, "unregistering callback " + cb + ". index=" + index);
1067d3c8642dae9a1f6db60e2f8e5c7b32cd1b3169dfRoboErik                }
10688ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            }
106901fe661ae5da3739215d93922412df4b24c859a2RoboErik        }
107001fe661ae5da3739215d93922412df4b24c859a2RoboErik
107101fe661ae5da3739215d93922412df4b24c859a2RoboErik        @Override
1072aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik        public String getPackageName() {
1073aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik            return mPackageName;
1074aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik        }
1075aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik
1076aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik        @Override
1077aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik        public String getTag() {
1078aa4e23bbb36994708ba72c5f4c83255025d99e07RoboErik            return mTag;
1079fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik        }
1080fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik
1081fb442b03840245c7e52cf2a540a77c5fc6c54587RoboErik        @Override
1082e34c09daf89fb888fe2638e71758573462d85173RoboErik        public PendingIntent getLaunchPendingIntent() {
1083e34c09daf89fb888fe2638e71758573462d85173RoboErik            return mLaunchIntent;
1084e34c09daf89fb888fe2638e71758573462d85173RoboErik        }
1085e34c09daf89fb888fe2638e71758573462d85173RoboErik
1086e34c09daf89fb888fe2638e71758573462d85173RoboErik        @Override
108773e23e229dd1a2d25687b1c6a63c708665378e41RoboErik        public long getFlags() {
108873e23e229dd1a2d25687b1c6a63c708665378e41RoboErik            return mFlags;
108973e23e229dd1a2d25687b1c6a63c708665378e41RoboErik        }
109073e23e229dd1a2d25687b1c6a63c708665378e41RoboErik
109173e23e229dd1a2d25687b1c6a63c708665378e41RoboErik        @Override
1092ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik        public ParcelableVolumeInfo getVolumeAttributes() {
1093ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik            synchronized (mLock) {
1094ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik                int type;
1095ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik                int max;
1096ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik                int current;
1097d2b8c947ddfc6349a3ae6c3968b422b9cf50d7edRoboErik                if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_REMOTE) {
1098ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik                    type = mVolumeControlType;
1099ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik                    max = mMaxVolume;
110019c9518f6a817d53d5234de0020313cab6950b2fRoboErik                    current = mOptimisticVolume != -1 ? mOptimisticVolume
110119c9518f6a817d53d5234de0020313cab6950b2fRoboErik                            : mCurrentVolume;
1102ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik                } else {
11039db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik                    int stream = AudioAttributes.toLegacyStreamType(mAudioAttrs);
1104ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik                    type = VolumeProvider.VOLUME_CONTROL_ABSOLUTE;
11059db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik                    max = mAudioManager.getStreamMaxVolume(stream);
11069db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik                    current = mAudioManager.getStreamVolume(stream);
1107ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik                }
11089db9bf7034d7dcdf596dc22d521b18975d0dd2b9RoboErik                return new ParcelableVolumeInfo(mVolumeType, mAudioAttrs, type, max, current);
1109ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik            }
1110ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik        }
1111ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik
1112ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik        @Override
11130dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik        public void adjustVolume(int direction, int flags, String packageName) {
11140dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik            int uid = Binder.getCallingUid();
1115f77b99f08afed6f6b8d8f5bc72978f2ff7b8db55RoboErik            final long token = Binder.clearCallingIdentity();
1116f77b99f08afed6f6b8d8f5bc72978f2ff7b8db55RoboErik            try {
1117272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik                MediaSessionRecord.this.adjustVolume(direction, flags, packageName, uid, false);
1118f77b99f08afed6f6b8d8f5bc72978f2ff7b8db55RoboErik            } finally {
1119f77b99f08afed6f6b8d8f5bc72978f2ff7b8db55RoboErik                Binder.restoreCallingIdentity(token);
1120f77b99f08afed6f6b8d8f5bc72978f2ff7b8db55RoboErik            }
1121ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik        }
1122ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik
1123ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik        @Override
11240dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik        public void setVolumeTo(int value, int flags, String packageName) {
11250dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik            int uid = Binder.getCallingUid();
1126f77b99f08afed6f6b8d8f5bc72978f2ff7b8db55RoboErik            final long token = Binder.clearCallingIdentity();
1127f77b99f08afed6f6b8d8f5bc72978f2ff7b8db55RoboErik            try {
11280dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik                MediaSessionRecord.this.setVolumeTo(value, flags, packageName, uid);
1129f77b99f08afed6f6b8d8f5bc72978f2ff7b8db55RoboErik            } finally {
1130f77b99f08afed6f6b8d8f5bc72978f2ff7b8db55RoboErik                Binder.restoreCallingIdentity(token);
1131f77b99f08afed6f6b8d8f5bc72978f2ff7b8db55RoboErik            }
1132ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik        }
1133ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik
1134ef3c9e9b057a5aac2d0d012e8e6385660478e203RoboErik        @Override
11358ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public void play() throws RemoteException {
11368ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            mSessionCb.play();
11378ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
11388ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
11398ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        @Override
11403625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik        public void playFromMediaId(String mediaId, Bundle extras) throws RemoteException {
11413625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik            mSessionCb.playFromMediaId(mediaId, extras);
1142f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        }
1143f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
1144f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        @Override
1145f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        public void playFromSearch(String query, Bundle extras) throws RemoteException {
1146f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            mSessionCb.playFromSearch(query, extras);
1147f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        }
1148f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
1149f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        @Override
11503625bf72cb8bcf3c7f8f8cd8d708d7206824cc62RoboErik        public void skipToQueueItem(long id) {
1151f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            mSessionCb.skipToTrack(id);
1152f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        }
1153f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
1154f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
1155f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        @Override
11568ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public void pause() throws RemoteException {
11578ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            mSessionCb.pause();
11588ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
11598ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
11608ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        @Override
11618ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public void stop() throws RemoteException {
11628ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            mSessionCb.stop();
11638ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
11648ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
11658ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        @Override
11668ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public void next() throws RemoteException {
11678ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            mSessionCb.next();
11688ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
11698ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
11708ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        @Override
11718ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public void previous() throws RemoteException {
11728ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            mSessionCb.previous();
11738ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
11748ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
11758ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        @Override
11768ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public void fastForward() throws RemoteException {
11778ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            mSessionCb.fastForward();
11788ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
11798ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
11808ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        @Override
11818ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public void rewind() throws RemoteException {
11828ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            mSessionCb.rewind();
11838ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
11848ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
11858ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        @Override
11868ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public void seekTo(long pos) throws RemoteException {
11878ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            mSessionCb.seekTo(pos);
11888ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
11898ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
11908ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        @Override
11918ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public void rate(Rating rating) throws RemoteException {
11928ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            mSessionCb.rate(rating);
11938ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
11948ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
1195f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal        @Override
1196f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal        public void sendCustomAction(String action, Bundle args)
1197f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal                throws RemoteException {
1198f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal            mSessionCb.sendCustomAction(action, args);
1199f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal        }
1200f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal
12018ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
12028ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        @Override
12038ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public MediaMetadata getMetadata() {
1204df382cada180033e5bbde82998b73ef19e541ed2RoboErik            synchronized (mLock) {
1205df382cada180033e5bbde82998b73ef19e541ed2RoboErik                return mMetadata;
1206df382cada180033e5bbde82998b73ef19e541ed2RoboErik            }
12078ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
12088ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
12098ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        @Override
12108ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public PlaybackState getPlaybackState() {
1211f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik            return getStateWithUpdatedPosition();
121201fe661ae5da3739215d93922412df4b24c859a2RoboErik        }
12138ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
12148ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        @Override
1215f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        public ParceledListSlice getQueue() {
1216df382cada180033e5bbde82998b73ef19e541ed2RoboErik            synchronized (mLock) {
1217df382cada180033e5bbde82998b73ef19e541ed2RoboErik                return mQueue;
1218df382cada180033e5bbde82998b73ef19e541ed2RoboErik            }
1219f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        }
1220f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
1221f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        @Override
1222f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        public CharSequence getQueueTitle() {
1223f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal            return mQueueTitle;
1224f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        }
1225f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
1226f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        @Override
1227f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        public Bundle getExtras() {
1228df382cada180033e5bbde82998b73ef19e541ed2RoboErik            synchronized (mLock) {
1229df382cada180033e5bbde82998b73ef19e541ed2RoboErik                return mExtras;
1230df382cada180033e5bbde82998b73ef19e541ed2RoboErik            }
1231f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        }
1232f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal
1233f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        @Override
12348ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public int getRatingType() {
12358ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            return mRatingType;
12368ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
12378ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
12388ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        @Override
123907c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        public boolean isTransportControlEnabled() {
1240a8f951462791a16f47e8c07e552232f31dcefac5RoboErik            return MediaSessionRecord.this.isTransportControlEnabled();
12418ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
12428ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik    }
12438ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
12448ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik    private class MessageHandler extends Handler {
12458ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        private static final int MSG_UPDATE_METADATA = 1;
12468ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        private static final int MSG_UPDATE_PLAYBACK_STATE = 2;
1247f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        private static final int MSG_UPDATE_QUEUE = 3;
1248f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        private static final int MSG_UPDATE_QUEUE_TITLE = 4;
1249f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        private static final int MSG_UPDATE_EXTRAS = 5;
1250f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        private static final int MSG_SEND_EVENT = 6;
1251f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        private static final int MSG_UPDATE_SESSION_STATE = 7;
1252f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal        private static final int MSG_UPDATE_VOLUME = 8;
125324762bffc3358762666079cd802040a316b3260dRoboErik        private static final int MSG_DESTROYED = 9;
12548ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
12558ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public MessageHandler(Looper looper) {
12568ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            super(looper);
12578ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
12588ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        @Override
12598ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public void handleMessage(Message msg) {
12608ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            switch (msg.what) {
12618ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                case MSG_UPDATE_METADATA:
12628ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                    pushMetadataUpdate();
12638ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                    break;
12648ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                case MSG_UPDATE_PLAYBACK_STATE:
12658ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                    pushPlaybackStateUpdate();
12668ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                    break;
1267f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                case MSG_UPDATE_QUEUE:
1268f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                    pushQueueUpdate();
1269f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                    break;
1270f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                case MSG_UPDATE_QUEUE_TITLE:
1271f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                    pushQueueTitleUpdate();
1272f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                    break;
1273f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                case MSG_UPDATE_EXTRAS:
1274f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                    pushExtrasUpdate();
1275f0593bc17b61c872ae2d7705fb598c5e5056e679Gabriel Peal                    break;
12768ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                case MSG_SEND_EVENT:
12778ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                    pushEvent((String) msg.obj, msg.getData());
12788ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                    break;
1279a8f951462791a16f47e8c07e552232f31dcefac5RoboErik                case MSG_UPDATE_SESSION_STATE:
1280a8f951462791a16f47e8c07e552232f31dcefac5RoboErik                    // TODO add session state
1281a8f951462791a16f47e8c07e552232f31dcefac5RoboErik                    break;
128219c9518f6a817d53d5234de0020313cab6950b2fRoboErik                case MSG_UPDATE_VOLUME:
128319c9518f6a817d53d5234de0020313cab6950b2fRoboErik                    pushVolumeUpdate();
128419c9518f6a817d53d5234de0020313cab6950b2fRoboErik                    break;
128524762bffc3358762666079cd802040a316b3260dRoboErik                case MSG_DESTROYED:
128624762bffc3358762666079cd802040a316b3260dRoboErik                    pushSessionDestroyed();
12878ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            }
12888ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
12898ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
12908ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public void post(int what) {
12918ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            post(what, null);
12928ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
12938ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
12948ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public void post(int what, Object obj) {
12958ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            obtainMessage(what, obj).sendToTarget();
12968ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
12978ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
12988ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public void post(int what, Object obj, Bundle data) {
12998ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            Message msg = obtainMessage(what, obj);
13008ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            msg.setData(data);
13018ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            msg.sendToTarget();
13028ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
130301fe661ae5da3739215d93922412df4b24c859a2RoboErik    }
130401fe661ae5da3739215d93922412df4b24c859a2RoboErik
130501fe661ae5da3739215d93922412df4b24c859a2RoboErik}
1306