blob: 246da2e10de5205227ac61128b5d37323b5bf9c1 [file] [log] [blame]
RoboErik01fe6612014-02-13 14:19:04 -08001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.media;
18
RoboErike34c09d2014-07-24 10:20:41 -070019import android.app.PendingIntent;
RoboErikef3c9e92014-06-19 16:07:28 -070020import android.content.Context;
RoboErik01fe6612014-02-13 14:19:04 -080021import android.content.Intent;
Gabriel Pealf0593bc2014-07-22 09:39:06 -070022import android.content.pm.ParceledListSlice;
23import android.media.AudioManager;
RoboErik0dac35a2014-08-12 15:48:49 -070024import android.media.AudioManagerInternal;
RoboErik165809b2014-09-29 14:16:45 -070025import android.media.AudioSystem;
RoboErik3625bf72014-08-27 16:03:19 -070026import android.media.MediaDescription;
Gabriel Pealf0593bc2014-07-22 09:39:06 -070027import android.media.MediaMetadata;
28import android.media.Rating;
29import android.media.VolumeProvider;
RoboErik07c70772014-03-20 13:33:52 -070030import android.media.session.ISession;
31import android.media.session.ISessionCallback;
Gabriel Pealf0593bc2014-07-22 09:39:06 -070032import android.media.session.ISessionController;
33import android.media.session.ISessionControllerCallback;
RoboErik42ea7ee2014-05-16 16:27:35 -070034import android.media.session.MediaController;
RoboErikd2b8c942014-08-19 11:23:40 -070035import android.media.session.MediaController.PlaybackInfo;
RoboErik42ea7ee2014-05-16 16:27:35 -070036import android.media.session.MediaSession;
RoboErikef3c9e92014-06-19 16:07:28 -070037import android.media.session.ParcelableVolumeInfo;
Gabriel Pealf0593bc2014-07-22 09:39:06 -070038import android.media.session.PlaybackState;
RoboErik9db9bf72014-07-21 12:44:53 -070039import android.media.AudioAttributes;
P.Y. Laligandc2045472015-03-25 14:51:50 -070040import android.net.Uri;
RoboErikf77b99f2014-06-27 11:38:59 -070041import android.os.Binder;
RoboErik01fe6612014-02-13 14:19:04 -080042import android.os.Bundle;
RoboErikd3c86422014-06-16 14:00:48 -070043import android.os.DeadObjectException;
RoboErik8ae0f342014-02-24 18:02:08 -080044import android.os.Handler;
RoboErik01fe6612014-02-13 14:19:04 -080045import android.os.IBinder;
RoboErik8ae0f342014-02-24 18:02:08 -080046import android.os.Looper;
47import android.os.Message;
RoboErik01fe6612014-02-13 14:19:04 -080048import android.os.RemoteException;
RoboErik8ae0f342014-02-24 18:02:08 -080049import android.os.ResultReceiver;
RoboErikf1372422014-04-23 14:38:17 -070050import android.os.SystemClock;
RoboErik01fe6612014-02-13 14:19:04 -080051import android.util.Log;
RoboErik8ae0f342014-02-24 18:02:08 -080052import android.util.Slog;
RoboErik01fe6612014-02-13 14:19:04 -080053import android.view.KeyEvent;
54
RoboErik0dac35a2014-08-12 15:48:49 -070055import com.android.server.LocalServices;
56
RoboErika278ea72014-04-24 14:49:01 -070057import java.io.PrintWriter;
RoboErik01fe6612014-02-13 14:19:04 -080058import java.util.ArrayList;
59
60/**
61 * This is the system implementation of a Session. Apps will interact with the
62 * MediaSession wrapper class instead.
63 */
64public class MediaSessionRecord implements IBinder.DeathRecipient {
RoboErik07c70772014-03-20 13:33:52 -070065 private static final String TAG = "MediaSessionRecord";
Insun Kang30be970a2015-11-26 15:35:44 +090066 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
RoboErik01fe6612014-02-13 14:19:04 -080067
RoboErika8f95142014-05-05 14:23:49 -070068 /**
RoboErika8f95142014-05-05 14:23:49 -070069 * The length of time a session will still be considered active after
70 * pausing in ms.
71 */
72 private static final int ACTIVE_BUFFER = 30000;
73
RoboErik19c95182014-06-23 15:38:48 -070074 /**
75 * The amount of time we'll send an assumed volume after the last volume
76 * command before reverting to the last reported volume.
77 */
78 private static final int OPTIMISTIC_VOLUME_TIMEOUT = 1000;
79
RoboErik8ae0f342014-02-24 18:02:08 -080080 private final MessageHandler mHandler;
81
RoboErika5b02322014-05-07 17:05:49 -070082 private final int mOwnerPid;
83 private final int mOwnerUid;
84 private final int mUserId;
RoboErikaa4e23b2014-07-24 18:35:11 -070085 private final String mPackageName;
RoboErik01fe6612014-02-13 14:19:04 -080086 private final String mTag;
87 private final ControllerStub mController;
88 private final SessionStub mSession;
89 private final SessionCb mSessionCb;
90 private final MediaSessionService mService;
91
RoboErik07c70772014-03-20 13:33:52 -070092 private final Object mLock = new Object();
93 private final ArrayList<ISessionControllerCallback> mControllerCallbacks =
94 new ArrayList<ISessionControllerCallback>();
RoboErik01fe6612014-02-13 14:19:04 -080095
RoboErike7880d82014-04-30 12:48:25 -070096 private long mFlags;
RoboErikb214efb2014-07-24 13:20:30 -070097 private PendingIntent mMediaButtonReceiver;
RoboErike34c09d2014-07-24 10:20:41 -070098 private PendingIntent mLaunchIntent;
RoboErik8ae0f342014-02-24 18:02:08 -080099
100 // TransportPerformer fields
101
Gabriel Pealf0593bc2014-07-22 09:39:06 -0700102 private Bundle mExtras;
RoboErik8ae0f342014-02-24 18:02:08 -0800103 private MediaMetadata mMetadata;
104 private PlaybackState mPlaybackState;
Gabriel Pealf0593bc2014-07-22 09:39:06 -0700105 private ParceledListSlice mQueue;
106 private CharSequence mQueueTitle;
RoboErik8ae0f342014-02-24 18:02:08 -0800107 private int mRatingType;
RoboErika8f95142014-05-05 14:23:49 -0700108 private long mLastActiveTime;
RoboErik8ae0f342014-02-24 18:02:08 -0800109 // End TransportPerformer fields
110
RoboErikb69ffd42014-05-30 14:57:59 -0700111 // Volume handling fields
RoboErik9db9bf72014-07-21 12:44:53 -0700112 private AudioAttributes mAudioAttrs;
RoboErikef3c9e92014-06-19 16:07:28 -0700113 private AudioManager mAudioManager;
RoboErik0dac35a2014-08-12 15:48:49 -0700114 private AudioManagerInternal mAudioManagerInternal;
RoboErikd2b8c942014-08-19 11:23:40 -0700115 private int mVolumeType = PlaybackInfo.PLAYBACK_TYPE_LOCAL;
RoboErikef3c9e92014-06-19 16:07:28 -0700116 private int mVolumeControlType = VolumeProvider.VOLUME_CONTROL_ABSOLUTE;
RoboErikb69ffd42014-05-30 14:57:59 -0700117 private int mMaxVolume = 0;
118 private int mCurrentVolume = 0;
RoboErik19c95182014-06-23 15:38:48 -0700119 private int mOptimisticVolume = -1;
RoboErikb69ffd42014-05-30 14:57:59 -0700120 // End volume handling fields
121
RoboErika8f95142014-05-05 14:23:49 -0700122 private boolean mIsActive = false;
RoboErik4646d282014-05-13 10:13:04 -0700123 private boolean mDestroyed = false;
RoboErik01fe6612014-02-13 14:19:04 -0800124
RoboErika5b02322014-05-07 17:05:49 -0700125 public MediaSessionRecord(int ownerPid, int ownerUid, int userId, String ownerPackageName,
126 ISessionCallback cb, String tag, MediaSessionService service, Handler handler) {
127 mOwnerPid = ownerPid;
128 mOwnerUid = ownerUid;
129 mUserId = userId;
RoboErikaa4e23b2014-07-24 18:35:11 -0700130 mPackageName = ownerPackageName;
RoboErik01fe6612014-02-13 14:19:04 -0800131 mTag = tag;
132 mController = new ControllerStub();
133 mSession = new SessionStub();
134 mSessionCb = new SessionCb(cb);
135 mService = service;
RoboErik8ae0f342014-02-24 18:02:08 -0800136 mHandler = new MessageHandler(handler.getLooper());
RoboErikef3c9e92014-06-19 16:07:28 -0700137 mAudioManager = (AudioManager) service.getContext().getSystemService(Context.AUDIO_SERVICE);
RoboErik0dac35a2014-08-12 15:48:49 -0700138 mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class);
RoboErik9db9bf72014-07-21 12:44:53 -0700139 mAudioAttrs = new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build();
RoboErik01fe6612014-02-13 14:19:04 -0800140 }
141
RoboErik07c70772014-03-20 13:33:52 -0700142 /**
RoboErik42ea7ee2014-05-16 16:27:35 -0700143 * Get the binder for the {@link MediaSession}.
RoboErik07c70772014-03-20 13:33:52 -0700144 *
145 * @return The session binder apps talk to.
146 */
147 public ISession getSessionBinder() {
RoboErik01fe6612014-02-13 14:19:04 -0800148 return mSession;
149 }
150
RoboErik07c70772014-03-20 13:33:52 -0700151 /**
RoboErik42ea7ee2014-05-16 16:27:35 -0700152 * Get the binder for the {@link MediaController}.
RoboErik07c70772014-03-20 13:33:52 -0700153 *
154 * @return The controller binder apps talk to.
155 */
156 public ISessionController getControllerBinder() {
RoboErik01fe6612014-02-13 14:19:04 -0800157 return mController;
158 }
159
RoboErik07c70772014-03-20 13:33:52 -0700160 /**
RoboErik07c70772014-03-20 13:33:52 -0700161 * Get the info for this session.
162 *
163 * @return Info that identifies this session.
164 */
RoboErikaa4e23b2014-07-24 18:35:11 -0700165 public String getPackageName() {
166 return mPackageName;
167 }
168
169 /**
170 * Get the tag for the session.
171 *
172 * @return The session's tag.
173 */
174 public String getTag() {
175 return mTag;
RoboErik07c70772014-03-20 13:33:52 -0700176 }
177
RoboErikb214efb2014-07-24 13:20:30 -0700178 /**
179 * Get the intent the app set for their media button receiver.
180 *
181 * @return The pending intent set by the app or null.
182 */
183 public PendingIntent getMediaButtonReceiver() {
RoboErik6f0e4dd2014-06-17 16:56:27 -0700184 return mMediaButtonReceiver;
185 }
186
RoboErik07c70772014-03-20 13:33:52 -0700187 /**
RoboErike7880d82014-04-30 12:48:25 -0700188 * Get this session's flags.
189 *
190 * @return The flags for this session.
191 */
192 public long getFlags() {
193 return mFlags;
194 }
195
196 /**
RoboErika8f95142014-05-05 14:23:49 -0700197 * Check if this session has the specified flag.
198 *
199 * @param flag The flag to check.
200 * @return True if this session has that flag set, false otherwise.
201 */
202 public boolean hasFlag(int flag) {
203 return (mFlags & flag) != 0;
204 }
205
206 /**
RoboErika5b02322014-05-07 17:05:49 -0700207 * Get the user id this session was created for.
208 *
209 * @return The user id for this session.
210 */
211 public int getUserId() {
212 return mUserId;
213 }
214
215 /**
RoboErike7880d82014-04-30 12:48:25 -0700216 * Check if this session has system priorty and should receive media buttons
217 * before any other sessions.
218 *
219 * @return True if this is a system priority session, false otherwise
220 */
221 public boolean isSystemPriority() {
RoboErik42ea7ee2014-05-16 16:27:35 -0700222 return (mFlags & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0;
RoboErike7880d82014-04-30 12:48:25 -0700223 }
224
225 /**
RoboErik1ff5b162014-07-15 17:23:18 -0700226 * Send a volume adjustment to the session owner. Direction must be one of
227 * {@link AudioManager#ADJUST_LOWER}, {@link AudioManager#ADJUST_RAISE},
228 * {@link AudioManager#ADJUST_SAME}.
RoboErikb69ffd42014-05-30 14:57:59 -0700229 *
RoboErik1ff5b162014-07-15 17:23:18 -0700230 * @param direction The direction to adjust volume in.
RoboErik272e1612014-09-05 11:39:29 -0700231 * @param flags Any of the flags from {@link AudioManager}.
232 * @param packageName The package that made the original volume request.
233 * @param uid The uid that made the original volume request.
234 * @param useSuggested True to use adjustSuggestedStreamVolume instead of
235 * adjustStreamVolume.
RoboErikb69ffd42014-05-30 14:57:59 -0700236 */
RoboErik272e1612014-09-05 11:39:29 -0700237 public void adjustVolume(int direction, int flags, String packageName, int uid,
238 boolean useSuggested) {
RoboErik165809b2014-09-29 14:16:45 -0700239 int previousFlagPlaySound = flags & AudioManager.FLAG_PLAY_SOUND;
RoboErik7a18cb52014-09-02 15:04:27 -0700240 if (isPlaybackActive(false) || hasFlag(MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY)) {
RoboErike9466802014-06-26 10:26:43 -0700241 flags &= ~AudioManager.FLAG_PLAY_SOUND;
242 }
RoboErikd2b8c942014-08-19 11:23:40 -0700243 if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
Dongwon Kanga38e1f42015-06-16 15:28:17 -0700244 // Adjust the volume with a handler not to be blocked by other system service.
Dongwon Kang500747b2015-07-20 15:59:53 -0700245 int stream = AudioAttributes.toLegacyStreamType(mAudioAttrs);
246 postAdjustLocalVolume(stream, direction, flags, packageName, uid, useSuggested,
247 previousFlagPlaySound);
RoboErikef3c9e92014-06-19 16:07:28 -0700248 } else {
249 if (mVolumeControlType == VolumeProvider.VOLUME_CONTROL_FIXED) {
250 // Nothing to do, the volume cannot be changed
251 return;
252 }
RoboErik4197cb62015-01-21 15:45:32 -0800253 if (direction == AudioManager.ADJUST_TOGGLE_MUTE
254 || direction == AudioManager.ADJUST_MUTE
255 || direction == AudioManager.ADJUST_UNMUTE) {
RoboErik7c82ced2014-12-04 17:39:08 -0800256 Log.w(TAG, "Muting remote playback is not supported");
257 return;
258 }
RoboErik1ff5b162014-07-15 17:23:18 -0700259 mSessionCb.adjustVolume(direction);
RoboErik19c95182014-06-23 15:38:48 -0700260
261 int volumeBefore = (mOptimisticVolume < 0 ? mCurrentVolume : mOptimisticVolume);
RoboErik1ff5b162014-07-15 17:23:18 -0700262 mOptimisticVolume = volumeBefore + direction;
RoboErik19c95182014-06-23 15:38:48 -0700263 mOptimisticVolume = Math.max(0, Math.min(mOptimisticVolume, mMaxVolume));
264 mHandler.removeCallbacks(mClearOptimisticVolumeRunnable);
265 mHandler.postDelayed(mClearOptimisticVolumeRunnable, OPTIMISTIC_VOLUME_TIMEOUT);
266 if (volumeBefore != mOptimisticVolume) {
267 pushVolumeUpdate();
268 }
RoboErik9c5b7cb2015-01-15 15:09:09 -0800269 mService.notifyRemoteVolumeChanged(flags, this);
RoboErik19c95182014-06-23 15:38:48 -0700270
271 if (DEBUG) {
272 Log.d(TAG, "Adjusted optimistic volume to " + mOptimisticVolume + " max is "
273 + mMaxVolume);
274 }
RoboErikb69ffd42014-05-30 14:57:59 -0700275 }
RoboErikb69ffd42014-05-30 14:57:59 -0700276 }
277
RoboErik0dac35a2014-08-12 15:48:49 -0700278 public void setVolumeTo(int value, int flags, String packageName, int uid) {
RoboErikd2b8c942014-08-19 11:23:40 -0700279 if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
RoboErik9db9bf72014-07-21 12:44:53 -0700280 int stream = AudioAttributes.toLegacyStreamType(mAudioAttrs);
RoboErik0dac35a2014-08-12 15:48:49 -0700281 mAudioManagerInternal.setStreamVolumeForUid(stream, value, flags, packageName, uid);
RoboErikef3c9e92014-06-19 16:07:28 -0700282 } else {
283 if (mVolumeControlType != VolumeProvider.VOLUME_CONTROL_ABSOLUTE) {
284 // Nothing to do. The volume can't be set directly.
285 return;
286 }
RoboErik19c95182014-06-23 15:38:48 -0700287 value = Math.max(0, Math.min(value, mMaxVolume));
RoboErikef3c9e92014-06-19 16:07:28 -0700288 mSessionCb.setVolumeTo(value);
RoboErik19c95182014-06-23 15:38:48 -0700289
290 int volumeBefore = (mOptimisticVolume < 0 ? mCurrentVolume : mOptimisticVolume);
291 mOptimisticVolume = Math.max(0, Math.min(value, mMaxVolume));
292 mHandler.removeCallbacks(mClearOptimisticVolumeRunnable);
293 mHandler.postDelayed(mClearOptimisticVolumeRunnable, OPTIMISTIC_VOLUME_TIMEOUT);
294 if (volumeBefore != mOptimisticVolume) {
295 pushVolumeUpdate();
296 }
RoboErik9c5b7cb2015-01-15 15:09:09 -0800297 mService.notifyRemoteVolumeChanged(flags, this);
RoboErik19c95182014-06-23 15:38:48 -0700298
299 if (DEBUG) {
300 Log.d(TAG, "Set optimistic volume to " + mOptimisticVolume + " max is "
301 + mMaxVolume);
302 }
RoboErikb69ffd42014-05-30 14:57:59 -0700303 }
RoboErikb69ffd42014-05-30 14:57:59 -0700304 }
305
306 /**
RoboErika8f95142014-05-05 14:23:49 -0700307 * Check if this session has been set to active by the app.
RoboErik07c70772014-03-20 13:33:52 -0700308 *
RoboErika8f95142014-05-05 14:23:49 -0700309 * @return True if the session is active, false otherwise.
RoboErik07c70772014-03-20 13:33:52 -0700310 */
RoboErika8f95142014-05-05 14:23:49 -0700311 public boolean isActive() {
RoboErik4646d282014-05-13 10:13:04 -0700312 return mIsActive && !mDestroyed;
RoboErika8f95142014-05-05 14:23:49 -0700313 }
314
315 /**
316 * Check if the session is currently performing playback. This will also
317 * return true if the session was recently paused.
318 *
RoboErikb69ffd42014-05-30 14:57:59 -0700319 * @param includeRecentlyActive True if playback that was recently paused
320 * should count, false if it shouldn't.
RoboErika8f95142014-05-05 14:23:49 -0700321 * @return True if the session is performing playback, false otherwise.
322 */
RoboErikb69ffd42014-05-30 14:57:59 -0700323 public boolean isPlaybackActive(boolean includeRecentlyActive) {
RoboErika8f95142014-05-05 14:23:49 -0700324 int state = mPlaybackState == null ? 0 : mPlaybackState.getState();
RoboErik3c45c292014-07-08 16:47:31 -0700325 if (MediaSession.isActiveState(state)) {
RoboErika8f95142014-05-05 14:23:49 -0700326 return true;
327 }
RoboErikb69ffd42014-05-30 14:57:59 -0700328 if (includeRecentlyActive && state == mPlaybackState.STATE_PAUSED) {
RoboErika8f95142014-05-05 14:23:49 -0700329 long inactiveTime = SystemClock.uptimeMillis() - mLastActiveTime;
330 if (inactiveTime < ACTIVE_BUFFER) {
331 return true;
332 }
333 }
334 return false;
335 }
336
RoboErik4646d282014-05-13 10:13:04 -0700337 /**
RoboErikb69ffd42014-05-30 14:57:59 -0700338 * Get the type of playback, either local or remote.
339 *
340 * @return The current type of playback.
341 */
342 public int getPlaybackType() {
RoboErikef3c9e92014-06-19 16:07:28 -0700343 return mVolumeType;
RoboErikb69ffd42014-05-30 14:57:59 -0700344 }
345
346 /**
347 * Get the local audio stream being used. Only valid if playback type is
348 * local.
349 *
350 * @return The audio stream the session is using.
351 */
RoboErik9db9bf72014-07-21 12:44:53 -0700352 public AudioAttributes getAudioAttributes() {
353 return mAudioAttrs;
RoboErikb69ffd42014-05-30 14:57:59 -0700354 }
355
356 /**
357 * Get the type of volume control. Only valid if playback type is remote.
358 *
359 * @return The volume control type being used.
360 */
361 public int getVolumeControl() {
362 return mVolumeControlType;
363 }
364
365 /**
366 * Get the max volume that can be set. Only valid if playback type is
367 * remote.
368 *
369 * @return The max volume that can be set.
370 */
371 public int getMaxVolume() {
372 return mMaxVolume;
373 }
374
375 /**
376 * Get the current volume for this session. Only valid if playback type is
377 * remote.
378 *
379 * @return The current volume of the remote playback.
380 */
381 public int getCurrentVolume() {
382 return mCurrentVolume;
383 }
384
385 /**
RoboErik19c95182014-06-23 15:38:48 -0700386 * Get the volume we'd like it to be set to. This is only valid for a short
387 * while after a call to adjust or set volume.
388 *
389 * @return The current optimistic volume or -1.
390 */
391 public int getOptimisticVolume() {
392 return mOptimisticVolume;
393 }
394
RoboErika8f95142014-05-05 14:23:49 -0700395 public boolean isTransportControlEnabled() {
RoboErik42ea7ee2014-05-16 16:27:35 -0700396 return hasFlag(MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);
RoboErik07c70772014-03-20 13:33:52 -0700397 }
398
RoboErik01fe6612014-02-13 14:19:04 -0800399 @Override
400 public void binderDied() {
401 mService.sessionDied(this);
402 }
403
RoboErik4646d282014-05-13 10:13:04 -0700404 /**
405 * Finish cleaning up this session, including disconnecting if connected and
406 * removing the death observer from the callback binder.
407 */
408 public void onDestroy() {
409 synchronized (mLock) {
410 if (mDestroyed) {
411 return;
412 }
RoboErik4646d282014-05-13 10:13:04 -0700413 mDestroyed = true;
RoboErik24762bf2014-08-13 15:00:21 -0700414 mHandler.post(MessageHandler.MSG_DESTROYED);
RoboErik4646d282014-05-13 10:13:04 -0700415 }
416 }
417
418 public ISessionCallback getCallback() {
419 return mSessionCb.mCb;
420 }
421
RoboErik418c10c2014-05-19 09:25:25 -0700422 public void sendMediaButton(KeyEvent ke, int sequenceId, ResultReceiver cb) {
423 mSessionCb.sendMediaButton(ke, sequenceId, cb);
RoboErik8a2cfc32014-05-16 11:19:38 -0700424 }
425
RoboErika278ea72014-04-24 14:49:01 -0700426 public void dump(PrintWriter pw, String prefix) {
427 pw.println(prefix + mTag + " " + this);
428
429 final String indent = prefix + " ";
RoboErika5b02322014-05-07 17:05:49 -0700430 pw.println(indent + "ownerPid=" + mOwnerPid + ", ownerUid=" + mOwnerUid
431 + ", userId=" + mUserId);
RoboErikaa4e23b2014-07-24 18:35:11 -0700432 pw.println(indent + "package=" + mPackageName);
RoboErik7aef77b2014-08-08 15:56:54 -0700433 pw.println(indent + "launchIntent=" + mLaunchIntent);
434 pw.println(indent + "mediaButtonReceiver=" + mMediaButtonReceiver);
RoboErik4646d282014-05-13 10:13:04 -0700435 pw.println(indent + "active=" + mIsActive);
RoboErika8f95142014-05-05 14:23:49 -0700436 pw.println(indent + "flags=" + mFlags);
RoboErika278ea72014-04-24 14:49:01 -0700437 pw.println(indent + "rating type=" + mRatingType);
438 pw.println(indent + "controllers: " + mControllerCallbacks.size());
RoboErika8f95142014-05-05 14:23:49 -0700439 pw.println(indent + "state=" + (mPlaybackState == null ? null : mPlaybackState.toString()));
RoboErik7aef77b2014-08-08 15:56:54 -0700440 pw.println(indent + "audioAttrs=" + mAudioAttrs);
441 pw.println(indent + "volumeType=" + mVolumeType + ", controlType=" + mVolumeControlType
442 + ", max=" + mMaxVolume + ", current=" + mCurrentVolume);
RoboErik66dea732014-05-01 16:03:59 -0700443 pw.println(indent + "metadata:" + getShortMetadataString());
RoboErik7aef77b2014-08-08 15:56:54 -0700444 pw.println(indent + "queueTitle=" + mQueueTitle + ", size="
445 + (mQueue == null ? 0 : mQueue.getList().size()));
RoboErika278ea72014-04-24 14:49:01 -0700446 }
447
RoboErikaa4e23b2014-07-24 18:35:11 -0700448 @Override
449 public String toString() {
450 return mPackageName + "/" + mTag;
451 }
452
Dongwon Kang500747b2015-07-20 15:59:53 -0700453 private void postAdjustLocalVolume(final int stream, final int direction, final int flags,
454 final String packageName, final int uid, final boolean useSuggested,
455 final int previousFlagPlaySound) {
Dongwon Kanga38e1f42015-06-16 15:28:17 -0700456 mHandler.post(new Runnable() {
457 @Override
458 public void run() {
Dongwon Kang500747b2015-07-20 15:59:53 -0700459 if (useSuggested) {
460 if (AudioSystem.isStreamActive(stream, 0)) {
461 mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(stream, direction,
462 flags, packageName, uid);
463 } else {
464 mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(
465 AudioManager.USE_DEFAULT_STREAM_TYPE, direction,
466 flags | previousFlagPlaySound, packageName, uid);
467 }
468 } else {
469 mAudioManagerInternal.adjustStreamVolumeForUid(stream, direction, flags,
470 packageName, uid);
471 }
Dongwon Kanga38e1f42015-06-16 15:28:17 -0700472 }
473 });
474 }
475
RoboErik66dea732014-05-01 16:03:59 -0700476 private String getShortMetadataString() {
477 int fields = mMetadata == null ? 0 : mMetadata.size();
RoboErik3625bf72014-08-27 16:03:19 -0700478 MediaDescription description = mMetadata == null ? null : mMetadata
RoboErik75847b92014-07-29 13:10:17 -0700479 .getDescription();
480 return "size=" + fields + ", description=" + description;
RoboErik66dea732014-05-01 16:03:59 -0700481 }
482
RoboErik8ae0f342014-02-24 18:02:08 -0800483 private void pushPlaybackStateUpdate() {
RoboErik07c70772014-03-20 13:33:52 -0700484 synchronized (mLock) {
RoboErik4646d282014-05-13 10:13:04 -0700485 if (mDestroyed) {
486 return;
487 }
RoboErik8ae0f342014-02-24 18:02:08 -0800488 for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
RoboErik07c70772014-03-20 13:33:52 -0700489 ISessionControllerCallback cb = mControllerCallbacks.get(i);
RoboErik8ae0f342014-02-24 18:02:08 -0800490 try {
491 cb.onPlaybackStateChanged(mPlaybackState);
RoboErikd3c86422014-06-16 14:00:48 -0700492 } catch (DeadObjectException e) {
RoboErik8ae0f342014-02-24 18:02:08 -0800493 mControllerCallbacks.remove(i);
RoboErik19c95182014-06-23 15:38:48 -0700494 Log.w(TAG, "Removed dead callback in pushPlaybackStateUpdate.", e);
RoboErikd3c86422014-06-16 14:00:48 -0700495 } catch (RemoteException e) {
496 Log.w(TAG, "unexpected exception in pushPlaybackStateUpdate.", e);
RoboErik8ae0f342014-02-24 18:02:08 -0800497 }
498 }
499 }
500 }
501
502 private void pushMetadataUpdate() {
RoboErik07c70772014-03-20 13:33:52 -0700503 synchronized (mLock) {
RoboErik4646d282014-05-13 10:13:04 -0700504 if (mDestroyed) {
505 return;
506 }
RoboErik8ae0f342014-02-24 18:02:08 -0800507 for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
RoboErik07c70772014-03-20 13:33:52 -0700508 ISessionControllerCallback cb = mControllerCallbacks.get(i);
RoboErik8ae0f342014-02-24 18:02:08 -0800509 try {
510 cb.onMetadataChanged(mMetadata);
RoboErikd3c86422014-06-16 14:00:48 -0700511 } catch (DeadObjectException e) {
RoboErik19c95182014-06-23 15:38:48 -0700512 Log.w(TAG, "Removing dead callback in pushMetadataUpdate. ", e);
RoboErik8ae0f342014-02-24 18:02:08 -0800513 mControllerCallbacks.remove(i);
RoboErikd3c86422014-06-16 14:00:48 -0700514 } catch (RemoteException e) {
RoboErik19c95182014-06-23 15:38:48 -0700515 Log.w(TAG, "unexpected exception in pushMetadataUpdate. ", e);
516 }
517 }
518 }
519 }
520
Gabriel Pealf0593bc2014-07-22 09:39:06 -0700521 private void pushQueueUpdate() {
522 synchronized (mLock) {
523 if (mDestroyed) {
524 return;
525 }
526 for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
527 ISessionControllerCallback cb = mControllerCallbacks.get(i);
528 try {
529 cb.onQueueChanged(mQueue);
530 } catch (DeadObjectException e) {
531 mControllerCallbacks.remove(i);
532 Log.w(TAG, "Removed dead callback in pushQueueUpdate.", e);
533 } catch (RemoteException e) {
534 Log.w(TAG, "unexpected exception in pushQueueUpdate.", e);
535 }
536 }
537 }
538 }
539
540 private void pushQueueTitleUpdate() {
541 synchronized (mLock) {
542 if (mDestroyed) {
543 return;
544 }
545 for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
546 ISessionControllerCallback cb = mControllerCallbacks.get(i);
547 try {
548 cb.onQueueTitleChanged(mQueueTitle);
549 } catch (DeadObjectException e) {
550 mControllerCallbacks.remove(i);
551 Log.w(TAG, "Removed dead callback in pushQueueTitleUpdate.", e);
552 } catch (RemoteException e) {
553 Log.w(TAG, "unexpected exception in pushQueueTitleUpdate.", e);
554 }
555 }
556 }
557 }
558
559 private void pushExtrasUpdate() {
560 synchronized (mLock) {
561 if (mDestroyed) {
562 return;
563 }
564 for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
565 ISessionControllerCallback cb = mControllerCallbacks.get(i);
566 try {
567 cb.onExtrasChanged(mExtras);
568 } catch (DeadObjectException e) {
569 mControllerCallbacks.remove(i);
570 Log.w(TAG, "Removed dead callback in pushExtrasUpdate.", e);
571 } catch (RemoteException e) {
572 Log.w(TAG, "unexpected exception in pushExtrasUpdate.", e);
573 }
574 }
575 }
576 }
577
RoboErik19c95182014-06-23 15:38:48 -0700578 private void pushVolumeUpdate() {
579 synchronized (mLock) {
580 if (mDestroyed) {
581 return;
582 }
583 ParcelableVolumeInfo info = mController.getVolumeAttributes();
584 for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
585 ISessionControllerCallback cb = mControllerCallbacks.get(i);
586 try {
587 cb.onVolumeInfoChanged(info);
588 } catch (DeadObjectException e) {
589 Log.w(TAG, "Removing dead callback in pushVolumeUpdate. ", e);
590 } catch (RemoteException e) {
591 Log.w(TAG, "Unexpected exception in pushVolumeUpdate. ", e);
RoboErik8ae0f342014-02-24 18:02:08 -0800592 }
593 }
594 }
595 }
596
RoboErik8ae0f342014-02-24 18:02:08 -0800597 private void pushEvent(String event, Bundle data) {
RoboErik07c70772014-03-20 13:33:52 -0700598 synchronized (mLock) {
RoboErik4646d282014-05-13 10:13:04 -0700599 if (mDestroyed) {
600 return;
601 }
RoboErik8ae0f342014-02-24 18:02:08 -0800602 for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
RoboErik07c70772014-03-20 13:33:52 -0700603 ISessionControllerCallback cb = mControllerCallbacks.get(i);
RoboErik8ae0f342014-02-24 18:02:08 -0800604 try {
605 cb.onEvent(event, data);
RoboErikd3c86422014-06-16 14:00:48 -0700606 } catch (DeadObjectException e) {
607 Log.w(TAG, "Removing dead callback in pushEvent.", e);
608 mControllerCallbacks.remove(i);
RoboErik8ae0f342014-02-24 18:02:08 -0800609 } catch (RemoteException e) {
RoboErikd3c86422014-06-16 14:00:48 -0700610 Log.w(TAG, "unexpected exception in pushEvent.", e);
RoboErik8ae0f342014-02-24 18:02:08 -0800611 }
612 }
613 }
614 }
615
RoboErik24762bf2014-08-13 15:00:21 -0700616 private void pushSessionDestroyed() {
617 synchronized (mLock) {
618 // This is the only method that may be (and can only be) called
619 // after the session is destroyed.
620 if (!mDestroyed) {
621 return;
622 }
623 for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
624 ISessionControllerCallback cb = mControllerCallbacks.get(i);
625 try {
626 cb.onSessionDestroyed();
627 } catch (DeadObjectException e) {
628 Log.w(TAG, "Removing dead callback in pushEvent.", e);
629 mControllerCallbacks.remove(i);
630 } catch (RemoteException e) {
631 Log.w(TAG, "unexpected exception in pushEvent.", e);
632 }
633 }
634 // After notifying clear all listeners
635 mControllerCallbacks.clear();
636 }
637 }
638
RoboErikf1372422014-04-23 14:38:17 -0700639 private PlaybackState getStateWithUpdatedPosition() {
RoboErikdf382ca2014-09-29 13:21:47 -0700640 PlaybackState state;
RoboErik82df2c02014-10-08 10:38:42 -0700641 long duration = -1;
RoboErikdf382ca2014-09-29 13:21:47 -0700642 synchronized (mLock) {
643 state = mPlaybackState;
RoboErik82df2c02014-10-08 10:38:42 -0700644 if (mMetadata != null && mMetadata.containsKey(MediaMetadata.METADATA_KEY_DURATION)) {
645 duration = mMetadata.getLong(MediaMetadata.METADATA_KEY_DURATION);
646 }
RoboErikf1372422014-04-23 14:38:17 -0700647 }
648 PlaybackState result = null;
649 if (state != null) {
RoboErik79fa4632014-05-27 16:49:09 -0700650 if (state.getState() == PlaybackState.STATE_PLAYING
651 || state.getState() == PlaybackState.STATE_FAST_FORWARDING
652 || state.getState() == PlaybackState.STATE_REWINDING) {
RoboErikf1372422014-04-23 14:38:17 -0700653 long updateTime = state.getLastPositionUpdateTime();
RoboErikc785a782014-07-14 13:40:43 -0700654 long currentTime = SystemClock.elapsedRealtime();
RoboErikf1372422014-04-23 14:38:17 -0700655 if (updateTime > 0) {
RoboErikc785a782014-07-14 13:40:43 -0700656 long position = (long) (state.getPlaybackSpeed()
657 * (currentTime - updateTime)) + state.getPosition();
RoboErikf1372422014-04-23 14:38:17 -0700658 if (duration >= 0 && position > duration) {
659 position = duration;
660 } else if (position < 0) {
661 position = 0;
662 }
RoboErikc785a782014-07-14 13:40:43 -0700663 PlaybackState.Builder builder = new PlaybackState.Builder(state);
664 builder.setState(state.getState(), position, state.getPlaybackSpeed(),
665 currentTime);
666 result = builder.build();
RoboErikf1372422014-04-23 14:38:17 -0700667 }
668 }
669 }
670 return result == null ? state : result;
671 }
672
RoboErikd3c86422014-06-16 14:00:48 -0700673 private int getControllerCbIndexForCb(ISessionControllerCallback cb) {
674 IBinder binder = cb.asBinder();
675 for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
676 if (binder.equals(mControllerCallbacks.get(i).asBinder())) {
677 return i;
678 }
679 }
680 return -1;
681 }
682
RoboErik19c95182014-06-23 15:38:48 -0700683 private final Runnable mClearOptimisticVolumeRunnable = new Runnable() {
684 @Override
685 public void run() {
686 boolean needUpdate = (mOptimisticVolume != mCurrentVolume);
687 mOptimisticVolume = -1;
688 if (needUpdate) {
689 pushVolumeUpdate();
690 }
691 }
692 };
693
RoboErik07c70772014-03-20 13:33:52 -0700694 private final class SessionStub extends ISession.Stub {
RoboErik01fe6612014-02-13 14:19:04 -0800695 @Override
RoboErik8ae0f342014-02-24 18:02:08 -0800696 public void destroy() {
RoboErik4646d282014-05-13 10:13:04 -0700697 mService.destroySession(MediaSessionRecord.this);
RoboErik01fe6612014-02-13 14:19:04 -0800698 }
699
700 @Override
RoboErik8ae0f342014-02-24 18:02:08 -0800701 public void sendEvent(String event, Bundle data) {
RoboErikdf382ca2014-09-29 13:21:47 -0700702 mHandler.post(MessageHandler.MSG_SEND_EVENT, event,
703 data == null ? null : new Bundle(data));
RoboErik01fe6612014-02-13 14:19:04 -0800704 }
705
706 @Override
RoboErik07c70772014-03-20 13:33:52 -0700707 public ISessionController getController() {
RoboErik01fe6612014-02-13 14:19:04 -0800708 return mController;
709 }
710
711 @Override
RoboErika8f95142014-05-05 14:23:49 -0700712 public void setActive(boolean active) {
713 mIsActive = active;
714 mService.updateSession(MediaSessionRecord.this);
715 mHandler.post(MessageHandler.MSG_UPDATE_SESSION_STATE);
RoboErik01fe6612014-02-13 14:19:04 -0800716 }
717
RoboErik8ae0f342014-02-24 18:02:08 -0800718 @Override
RoboErika8f95142014-05-05 14:23:49 -0700719 public void setFlags(int flags) {
RoboErik42ea7ee2014-05-16 16:27:35 -0700720 if ((flags & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) {
RoboErike7880d82014-04-30 12:48:25 -0700721 int pid = getCallingPid();
722 int uid = getCallingUid();
723 mService.enforcePhoneStatePermission(pid, uid);
724 }
RoboErike7880d82014-04-30 12:48:25 -0700725 mFlags = flags;
RoboErika8f95142014-05-05 14:23:49 -0700726 mHandler.post(MessageHandler.MSG_UPDATE_SESSION_STATE);
RoboErike7880d82014-04-30 12:48:25 -0700727 }
728
729 @Override
RoboErikb214efb2014-07-24 13:20:30 -0700730 public void setMediaButtonReceiver(PendingIntent pi) {
731 mMediaButtonReceiver = pi;
RoboErik6f0e4dd2014-06-17 16:56:27 -0700732 }
733
734 @Override
RoboErike34c09d2014-07-24 10:20:41 -0700735 public void setLaunchPendingIntent(PendingIntent pi) {
736 mLaunchIntent = pi;
737 }
738
739 @Override
RoboErik8ae0f342014-02-24 18:02:08 -0800740 public void setMetadata(MediaMetadata metadata) {
RoboErikdf382ca2014-09-29 13:21:47 -0700741 synchronized (mLock) {
RoboErik82df2c02014-10-08 10:38:42 -0700742 MediaMetadata temp = metadata == null ? null : new MediaMetadata.Builder(metadata)
743 .build();
744 // This is to guarantee that the underlying bundle is unparceled
745 // before we set it to prevent concurrent reads from throwing an
746 // exception
RoboErik421c9df2014-10-15 12:17:43 -0700747 if (temp != null) {
748 temp.size();
749 }
RoboErik82df2c02014-10-08 10:38:42 -0700750 mMetadata = temp;
RoboErikdf382ca2014-09-29 13:21:47 -0700751 }
RoboErik8ae0f342014-02-24 18:02:08 -0800752 mHandler.post(MessageHandler.MSG_UPDATE_METADATA);
753 }
754
755 @Override
756 public void setPlaybackState(PlaybackState state) {
RoboErika8f95142014-05-05 14:23:49 -0700757 int oldState = mPlaybackState == null ? 0 : mPlaybackState.getState();
758 int newState = state == null ? 0 : state.getState();
RoboErik3c45c292014-07-08 16:47:31 -0700759 if (MediaSession.isActiveState(oldState) && newState == PlaybackState.STATE_PAUSED) {
RoboErika8f95142014-05-05 14:23:49 -0700760 mLastActiveTime = SystemClock.elapsedRealtime();
761 }
RoboErikdf382ca2014-09-29 13:21:47 -0700762 synchronized (mLock) {
763 mPlaybackState = state;
764 }
RoboErika8f95142014-05-05 14:23:49 -0700765 mService.onSessionPlaystateChange(MediaSessionRecord.this, oldState, newState);
RoboErik8ae0f342014-02-24 18:02:08 -0800766 mHandler.post(MessageHandler.MSG_UPDATE_PLAYBACK_STATE);
767 }
768
769 @Override
Gabriel Pealf0593bc2014-07-22 09:39:06 -0700770 public void setQueue(ParceledListSlice queue) {
RoboErikdf382ca2014-09-29 13:21:47 -0700771 synchronized (mLock) {
772 mQueue = queue;
773 }
Gabriel Pealf0593bc2014-07-22 09:39:06 -0700774 mHandler.post(MessageHandler.MSG_UPDATE_QUEUE);
775 }
776
777 @Override
778 public void setQueueTitle(CharSequence title) {
779 mQueueTitle = title;
780 mHandler.post(MessageHandler.MSG_UPDATE_QUEUE_TITLE);
781 }
782
783 @Override
784 public void setExtras(Bundle extras) {
RoboErikdf382ca2014-09-29 13:21:47 -0700785 synchronized (mLock) {
786 mExtras = extras == null ? null : new Bundle(extras);
787 }
Gabriel Pealf0593bc2014-07-22 09:39:06 -0700788 mHandler.post(MessageHandler.MSG_UPDATE_EXTRAS);
789 }
790
791 @Override
RoboErik8ae0f342014-02-24 18:02:08 -0800792 public void setRatingType(int type) {
793 mRatingType = type;
794 }
RoboErik07c70772014-03-20 13:33:52 -0700795
796 @Override
RoboErikb69ffd42014-05-30 14:57:59 -0700797 public void setCurrentVolume(int volume) {
798 mCurrentVolume = volume;
RoboErik19c95182014-06-23 15:38:48 -0700799 mHandler.post(MessageHandler.MSG_UPDATE_VOLUME);
RoboErikb69ffd42014-05-30 14:57:59 -0700800 }
801
802 @Override
RoboErik9db9bf72014-07-21 12:44:53 -0700803 public void setPlaybackToLocal(AudioAttributes attributes) {
804 boolean typeChanged;
805 synchronized (mLock) {
RoboErikd2b8c942014-08-19 11:23:40 -0700806 typeChanged = mVolumeType == PlaybackInfo.PLAYBACK_TYPE_REMOTE;
807 mVolumeType = PlaybackInfo.PLAYBACK_TYPE_LOCAL;
RoboErik9db9bf72014-07-21 12:44:53 -0700808 if (attributes != null) {
809 mAudioAttrs = attributes;
810 } else {
811 Log.e(TAG, "Received null audio attributes, using existing attributes");
812 }
RoboErikb69ffd42014-05-30 14:57:59 -0700813 }
RoboErik19c95182014-06-23 15:38:48 -0700814 if (typeChanged) {
815 mService.onSessionPlaybackTypeChanged(MediaSessionRecord.this);
John Spurlockbfa98592015-03-09 23:13:57 -0400816 mHandler.post(MessageHandler.MSG_UPDATE_VOLUME);
RoboErik19c95182014-06-23 15:38:48 -0700817 }
RoboErikb69ffd42014-05-30 14:57:59 -0700818 }
819
RoboErik9db9bf72014-07-21 12:44:53 -0700820 @Override
821 public void setPlaybackToRemote(int control, int max) {
822 boolean typeChanged;
823 synchronized (mLock) {
RoboErikd2b8c942014-08-19 11:23:40 -0700824 typeChanged = mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL;
825 mVolumeType = PlaybackInfo.PLAYBACK_TYPE_REMOTE;
RoboErik9db9bf72014-07-21 12:44:53 -0700826 mVolumeControlType = control;
827 mMaxVolume = max;
828 }
829 if (typeChanged) {
830 mService.onSessionPlaybackTypeChanged(MediaSessionRecord.this);
John Spurlockbfa98592015-03-09 23:13:57 -0400831 mHandler.post(MessageHandler.MSG_UPDATE_VOLUME);
RoboErik9db9bf72014-07-21 12:44:53 -0700832 }
RoboErikb69ffd42014-05-30 14:57:59 -0700833 }
RoboErik01fe6612014-02-13 14:19:04 -0800834 }
835
836 class SessionCb {
RoboErik07c70772014-03-20 13:33:52 -0700837 private final ISessionCallback mCb;
RoboErik01fe6612014-02-13 14:19:04 -0800838
RoboErik07c70772014-03-20 13:33:52 -0700839 public SessionCb(ISessionCallback cb) {
RoboErik01fe6612014-02-13 14:19:04 -0800840 mCb = cb;
841 }
842
RoboErik79fa4632014-05-27 16:49:09 -0700843 public boolean sendMediaButton(KeyEvent keyEvent, int sequenceId, ResultReceiver cb) {
RoboErik01fe6612014-02-13 14:19:04 -0800844 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
845 mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
846 try {
RoboErik418c10c2014-05-19 09:25:25 -0700847 mCb.onMediaButton(mediaButtonIntent, sequenceId, cb);
RoboErik79fa4632014-05-27 16:49:09 -0700848 return true;
RoboErik01fe6612014-02-13 14:19:04 -0800849 } catch (RemoteException e) {
RoboErik8ae0f342014-02-24 18:02:08 -0800850 Slog.e(TAG, "Remote failure in sendMediaRequest.", e);
RoboErik01fe6612014-02-13 14:19:04 -0800851 }
RoboErik79fa4632014-05-27 16:49:09 -0700852 return false;
RoboErik01fe6612014-02-13 14:19:04 -0800853 }
854
Gabriel Pealf364f942014-07-22 09:39:06 -0700855 public void sendCommand(String command, Bundle args, ResultReceiver cb) {
RoboErik01fe6612014-02-13 14:19:04 -0800856 try {
Gabriel Pealf364f942014-07-22 09:39:06 -0700857 mCb.onCommand(command, args, cb);
RoboErik01fe6612014-02-13 14:19:04 -0800858 } catch (RemoteException e) {
RoboErik8ae0f342014-02-24 18:02:08 -0800859 Slog.e(TAG, "Remote failure in sendCommand.", e);
RoboErik01fe6612014-02-13 14:19:04 -0800860 }
861 }
862
Gabriel Pealf364f942014-07-22 09:39:06 -0700863 public void sendCustomAction(String action, Bundle args) {
864 try {
865 mCb.onCustomAction(action, args);
866 } catch (RemoteException e) {
867 Slog.e(TAG, "Remote failure in sendCustomAction.", e);
868 }
869 }
870
RoboErik8ae0f342014-02-24 18:02:08 -0800871 public void play() {
872 try {
873 mCb.onPlay();
874 } catch (RemoteException e) {
875 Slog.e(TAG, "Remote failure in play.", e);
876 }
RoboErik01fe6612014-02-13 14:19:04 -0800877 }
878
RoboErik3625bf72014-08-27 16:03:19 -0700879 public void playFromMediaId(String mediaId, Bundle extras) {
Gabriel Pealf0593bc2014-07-22 09:39:06 -0700880 try {
RoboErik3625bf72014-08-27 16:03:19 -0700881 mCb.onPlayFromMediaId(mediaId, extras);
Gabriel Pealf0593bc2014-07-22 09:39:06 -0700882 } catch (RemoteException e) {
883 Slog.e(TAG, "Remote failure in playUri.", e);
884 }
885 }
886
887 public void playFromSearch(String query, Bundle extras) {
888 try {
889 mCb.onPlayFromSearch(query, extras);
890 } catch (RemoteException e) {
891 Slog.e(TAG, "Remote failure in playFromSearch.", e);
892 }
893 }
894
P.Y. Laligandc2045472015-03-25 14:51:50 -0700895 public void playFromUri(Uri uri, Bundle extras) {
896 try {
897 mCb.onPlayFromUri(uri, extras);
898 } catch (RemoteException e) {
899 Slog.e(TAG, "Remote failure in playFromUri.", e);
900 }
901 }
902
Gabriel Pealf0593bc2014-07-22 09:39:06 -0700903 public void skipToTrack(long id) {
904 try {
905 mCb.onSkipToTrack(id);
906 } catch (RemoteException e) {
907 Slog.e(TAG, "Remote failure in skipToTrack", e);
908 }
909 }
910
RoboErik8ae0f342014-02-24 18:02:08 -0800911 public void pause() {
912 try {
913 mCb.onPause();
914 } catch (RemoteException e) {
915 Slog.e(TAG, "Remote failure in pause.", e);
916 }
917 }
918
919 public void stop() {
920 try {
921 mCb.onStop();
922 } catch (RemoteException e) {
923 Slog.e(TAG, "Remote failure in stop.", e);
924 }
925 }
926
927 public void next() {
928 try {
929 mCb.onNext();
930 } catch (RemoteException e) {
931 Slog.e(TAG, "Remote failure in next.", e);
932 }
933 }
934
935 public void previous() {
936 try {
937 mCb.onPrevious();
938 } catch (RemoteException e) {
939 Slog.e(TAG, "Remote failure in previous.", e);
940 }
941 }
942
943 public void fastForward() {
944 try {
945 mCb.onFastForward();
946 } catch (RemoteException e) {
947 Slog.e(TAG, "Remote failure in fastForward.", e);
948 }
949 }
950
951 public void rewind() {
952 try {
953 mCb.onRewind();
954 } catch (RemoteException e) {
955 Slog.e(TAG, "Remote failure in rewind.", e);
956 }
957 }
958
959 public void seekTo(long pos) {
960 try {
961 mCb.onSeekTo(pos);
962 } catch (RemoteException e) {
963 Slog.e(TAG, "Remote failure in seekTo.", e);
964 }
965 }
966
967 public void rate(Rating rating) {
968 try {
969 mCb.onRate(rating);
970 } catch (RemoteException e) {
971 Slog.e(TAG, "Remote failure in rate.", e);
972 }
973 }
RoboErikb69ffd42014-05-30 14:57:59 -0700974
RoboErik1ff5b162014-07-15 17:23:18 -0700975 public void adjustVolume(int direction) {
RoboErikb69ffd42014-05-30 14:57:59 -0700976 try {
RoboErik1ff5b162014-07-15 17:23:18 -0700977 mCb.onAdjustVolume(direction);
RoboErikb69ffd42014-05-30 14:57:59 -0700978 } catch (RemoteException e) {
RoboErik1ff5b162014-07-15 17:23:18 -0700979 Slog.e(TAG, "Remote failure in adjustVolume.", e);
RoboErikb69ffd42014-05-30 14:57:59 -0700980 }
981 }
982
983 public void setVolumeTo(int value) {
984 try {
985 mCb.onSetVolumeTo(value);
986 } catch (RemoteException e) {
RoboErik1ff5b162014-07-15 17:23:18 -0700987 Slog.e(TAG, "Remote failure in setVolumeTo.", e);
RoboErikb69ffd42014-05-30 14:57:59 -0700988 }
989 }
RoboErik01fe6612014-02-13 14:19:04 -0800990 }
991
RoboErik07c70772014-03-20 13:33:52 -0700992 class ControllerStub extends ISessionController.Stub {
RoboErik01fe6612014-02-13 14:19:04 -0800993 @Override
Gabriel Pealf364f942014-07-22 09:39:06 -0700994 public void sendCommand(String command, Bundle args, ResultReceiver cb)
RoboErik8ae0f342014-02-24 18:02:08 -0800995 throws RemoteException {
Gabriel Pealf364f942014-07-22 09:39:06 -0700996 mSessionCb.sendCommand(command, args, cb);
RoboErik01fe6612014-02-13 14:19:04 -0800997 }
998
999 @Override
RoboErik79fa4632014-05-27 16:49:09 -07001000 public boolean sendMediaButton(KeyEvent mediaButtonIntent) {
1001 return mSessionCb.sendMediaButton(mediaButtonIntent, 0, null);
RoboErik01fe6612014-02-13 14:19:04 -08001002 }
1003
RoboErik01fe6612014-02-13 14:19:04 -08001004 @Override
RoboErik07c70772014-03-20 13:33:52 -07001005 public void registerCallbackListener(ISessionControllerCallback cb) {
1006 synchronized (mLock) {
RoboErik24762bf2014-08-13 15:00:21 -07001007 // If this session is already destroyed tell the caller and
1008 // don't add them.
1009 if (mDestroyed) {
1010 try {
1011 cb.onSessionDestroyed();
1012 } catch (Exception e) {
1013 // ignored
1014 }
1015 return;
1016 }
RoboErikd3c86422014-06-16 14:00:48 -07001017 if (getControllerCbIndexForCb(cb) < 0) {
RoboErik8ae0f342014-02-24 18:02:08 -08001018 mControllerCallbacks.add(cb);
RoboErikd3c86422014-06-16 14:00:48 -07001019 if (DEBUG) {
1020 Log.d(TAG, "registering controller callback " + cb);
1021 }
RoboErik8ae0f342014-02-24 18:02:08 -08001022 }
RoboErik01fe6612014-02-13 14:19:04 -08001023 }
1024 }
1025
RoboErik01fe6612014-02-13 14:19:04 -08001026 @Override
RoboErik07c70772014-03-20 13:33:52 -07001027 public void unregisterCallbackListener(ISessionControllerCallback cb)
RoboErik01fe6612014-02-13 14:19:04 -08001028 throws RemoteException {
RoboErik07c70772014-03-20 13:33:52 -07001029 synchronized (mLock) {
RoboErikd3c86422014-06-16 14:00:48 -07001030 int index = getControllerCbIndexForCb(cb);
1031 if (index != -1) {
1032 mControllerCallbacks.remove(index);
1033 }
1034 if (DEBUG) {
1035 Log.d(TAG, "unregistering callback " + cb + ". index=" + index);
1036 }
RoboErik8ae0f342014-02-24 18:02:08 -08001037 }
RoboErik01fe6612014-02-13 14:19:04 -08001038 }
1039
RoboErik01fe6612014-02-13 14:19:04 -08001040 @Override
RoboErikaa4e23b2014-07-24 18:35:11 -07001041 public String getPackageName() {
1042 return mPackageName;
1043 }
1044
1045 @Override
1046 public String getTag() {
1047 return mTag;
RoboErikfb442b02014-06-08 11:15:01 -07001048 }
1049
1050 @Override
RoboErike34c09d2014-07-24 10:20:41 -07001051 public PendingIntent getLaunchPendingIntent() {
1052 return mLaunchIntent;
1053 }
1054
1055 @Override
RoboErik73e23e22014-06-10 17:10:41 -07001056 public long getFlags() {
1057 return mFlags;
1058 }
1059
1060 @Override
RoboErikef3c9e92014-06-19 16:07:28 -07001061 public ParcelableVolumeInfo getVolumeAttributes() {
Jae Seod2a8d712015-07-17 10:41:55 -07001062 int volumeType;
1063 AudioAttributes attributes;
RoboErikef3c9e92014-06-19 16:07:28 -07001064 synchronized (mLock) {
RoboErikd2b8c942014-08-19 11:23:40 -07001065 if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_REMOTE) {
Jae Seod2a8d712015-07-17 10:41:55 -07001066 int current = mOptimisticVolume != -1 ? mOptimisticVolume : mCurrentVolume;
1067 return new ParcelableVolumeInfo(
1068 mVolumeType, mAudioAttrs, mVolumeControlType, mMaxVolume, current);
RoboErikef3c9e92014-06-19 16:07:28 -07001069 }
Jae Seod2a8d712015-07-17 10:41:55 -07001070 volumeType = mVolumeType;
1071 attributes = mAudioAttrs;
RoboErikef3c9e92014-06-19 16:07:28 -07001072 }
Jae Seod2a8d712015-07-17 10:41:55 -07001073 int stream = AudioAttributes.toLegacyStreamType(attributes);
1074 int max = mAudioManager.getStreamMaxVolume(stream);
1075 int current = mAudioManager.getStreamVolume(stream);
1076 return new ParcelableVolumeInfo(
1077 volumeType, attributes, VolumeProvider.VOLUME_CONTROL_ABSOLUTE, max, current);
RoboErikef3c9e92014-06-19 16:07:28 -07001078 }
1079
1080 @Override
RoboErik0dac35a2014-08-12 15:48:49 -07001081 public void adjustVolume(int direction, int flags, String packageName) {
1082 int uid = Binder.getCallingUid();
RoboErikf77b99f2014-06-27 11:38:59 -07001083 final long token = Binder.clearCallingIdentity();
1084 try {
RoboErik272e1612014-09-05 11:39:29 -07001085 MediaSessionRecord.this.adjustVolume(direction, flags, packageName, uid, false);
RoboErikf77b99f2014-06-27 11:38:59 -07001086 } finally {
1087 Binder.restoreCallingIdentity(token);
1088 }
RoboErikef3c9e92014-06-19 16:07:28 -07001089 }
1090
1091 @Override
RoboErik0dac35a2014-08-12 15:48:49 -07001092 public void setVolumeTo(int value, int flags, String packageName) {
1093 int uid = Binder.getCallingUid();
RoboErikf77b99f2014-06-27 11:38:59 -07001094 final long token = Binder.clearCallingIdentity();
1095 try {
RoboErik0dac35a2014-08-12 15:48:49 -07001096 MediaSessionRecord.this.setVolumeTo(value, flags, packageName, uid);
RoboErikf77b99f2014-06-27 11:38:59 -07001097 } finally {
1098 Binder.restoreCallingIdentity(token);
1099 }
RoboErikef3c9e92014-06-19 16:07:28 -07001100 }
1101
1102 @Override
RoboErik8ae0f342014-02-24 18:02:08 -08001103 public void play() throws RemoteException {
1104 mSessionCb.play();
1105 }
1106
1107 @Override
RoboErik3625bf72014-08-27 16:03:19 -07001108 public void playFromMediaId(String mediaId, Bundle extras) throws RemoteException {
1109 mSessionCb.playFromMediaId(mediaId, extras);
Gabriel Pealf0593bc2014-07-22 09:39:06 -07001110 }
1111
1112 @Override
1113 public void playFromSearch(String query, Bundle extras) throws RemoteException {
1114 mSessionCb.playFromSearch(query, extras);
1115 }
1116
1117 @Override
P.Y. Laligandc2045472015-03-25 14:51:50 -07001118 public void playFromUri(Uri uri, Bundle extras) throws RemoteException {
1119 mSessionCb.playFromUri(uri, extras);
1120 }
1121
1122 @Override
RoboErik3625bf72014-08-27 16:03:19 -07001123 public void skipToQueueItem(long id) {
Gabriel Pealf0593bc2014-07-22 09:39:06 -07001124 mSessionCb.skipToTrack(id);
1125 }
1126
1127
1128 @Override
RoboErik8ae0f342014-02-24 18:02:08 -08001129 public void pause() throws RemoteException {
1130 mSessionCb.pause();
1131 }
1132
1133 @Override
1134 public void stop() throws RemoteException {
1135 mSessionCb.stop();
1136 }
1137
1138 @Override
1139 public void next() throws RemoteException {
1140 mSessionCb.next();
1141 }
1142
1143 @Override
1144 public void previous() throws RemoteException {
1145 mSessionCb.previous();
1146 }
1147
1148 @Override
1149 public void fastForward() throws RemoteException {
1150 mSessionCb.fastForward();
1151 }
1152
1153 @Override
1154 public void rewind() throws RemoteException {
1155 mSessionCb.rewind();
1156 }
1157
1158 @Override
1159 public void seekTo(long pos) throws RemoteException {
1160 mSessionCb.seekTo(pos);
1161 }
1162
1163 @Override
1164 public void rate(Rating rating) throws RemoteException {
1165 mSessionCb.rate(rating);
1166 }
1167
Gabriel Pealf364f942014-07-22 09:39:06 -07001168 @Override
1169 public void sendCustomAction(String action, Bundle args)
1170 throws RemoteException {
1171 mSessionCb.sendCustomAction(action, args);
1172 }
1173
RoboErik8ae0f342014-02-24 18:02:08 -08001174
1175 @Override
1176 public MediaMetadata getMetadata() {
RoboErikdf382ca2014-09-29 13:21:47 -07001177 synchronized (mLock) {
1178 return mMetadata;
1179 }
RoboErik8ae0f342014-02-24 18:02:08 -08001180 }
1181
1182 @Override
1183 public PlaybackState getPlaybackState() {
RoboErikf1372422014-04-23 14:38:17 -07001184 return getStateWithUpdatedPosition();
RoboErik01fe6612014-02-13 14:19:04 -08001185 }
RoboErik8ae0f342014-02-24 18:02:08 -08001186
1187 @Override
Gabriel Pealf0593bc2014-07-22 09:39:06 -07001188 public ParceledListSlice getQueue() {
RoboErikdf382ca2014-09-29 13:21:47 -07001189 synchronized (mLock) {
1190 return mQueue;
1191 }
Gabriel Pealf0593bc2014-07-22 09:39:06 -07001192 }
1193
1194 @Override
1195 public CharSequence getQueueTitle() {
1196 return mQueueTitle;
1197 }
1198
1199 @Override
1200 public Bundle getExtras() {
RoboErikdf382ca2014-09-29 13:21:47 -07001201 synchronized (mLock) {
1202 return mExtras;
1203 }
Gabriel Pealf0593bc2014-07-22 09:39:06 -07001204 }
1205
1206 @Override
RoboErik8ae0f342014-02-24 18:02:08 -08001207 public int getRatingType() {
1208 return mRatingType;
1209 }
1210
1211 @Override
RoboErik07c70772014-03-20 13:33:52 -07001212 public boolean isTransportControlEnabled() {
RoboErika8f95142014-05-05 14:23:49 -07001213 return MediaSessionRecord.this.isTransportControlEnabled();
RoboErik8ae0f342014-02-24 18:02:08 -08001214 }
1215 }
1216
1217 private class MessageHandler extends Handler {
1218 private static final int MSG_UPDATE_METADATA = 1;
1219 private static final int MSG_UPDATE_PLAYBACK_STATE = 2;
Gabriel Pealf0593bc2014-07-22 09:39:06 -07001220 private static final int MSG_UPDATE_QUEUE = 3;
1221 private static final int MSG_UPDATE_QUEUE_TITLE = 4;
1222 private static final int MSG_UPDATE_EXTRAS = 5;
1223 private static final int MSG_SEND_EVENT = 6;
1224 private static final int MSG_UPDATE_SESSION_STATE = 7;
1225 private static final int MSG_UPDATE_VOLUME = 8;
RoboErik24762bf2014-08-13 15:00:21 -07001226 private static final int MSG_DESTROYED = 9;
RoboErik8ae0f342014-02-24 18:02:08 -08001227
1228 public MessageHandler(Looper looper) {
1229 super(looper);
1230 }
1231 @Override
1232 public void handleMessage(Message msg) {
1233 switch (msg.what) {
1234 case MSG_UPDATE_METADATA:
1235 pushMetadataUpdate();
1236 break;
1237 case MSG_UPDATE_PLAYBACK_STATE:
1238 pushPlaybackStateUpdate();
1239 break;
Gabriel Pealf0593bc2014-07-22 09:39:06 -07001240 case MSG_UPDATE_QUEUE:
1241 pushQueueUpdate();
1242 break;
1243 case MSG_UPDATE_QUEUE_TITLE:
1244 pushQueueTitleUpdate();
1245 break;
1246 case MSG_UPDATE_EXTRAS:
1247 pushExtrasUpdate();
1248 break;
RoboErik8ae0f342014-02-24 18:02:08 -08001249 case MSG_SEND_EVENT:
1250 pushEvent((String) msg.obj, msg.getData());
1251 break;
RoboErika8f95142014-05-05 14:23:49 -07001252 case MSG_UPDATE_SESSION_STATE:
1253 // TODO add session state
1254 break;
RoboErik19c95182014-06-23 15:38:48 -07001255 case MSG_UPDATE_VOLUME:
1256 pushVolumeUpdate();
1257 break;
RoboErik24762bf2014-08-13 15:00:21 -07001258 case MSG_DESTROYED:
1259 pushSessionDestroyed();
RoboErik8ae0f342014-02-24 18:02:08 -08001260 }
1261 }
1262
1263 public void post(int what) {
1264 post(what, null);
1265 }
1266
1267 public void post(int what, Object obj) {
1268 obtainMessage(what, obj).sendToTarget();
1269 }
1270
1271 public void post(int what, Object obj, Bundle data) {
1272 Message msg = obtainMessage(what, obj);
1273 msg.setData(data);
1274 msg.sendToTarget();
1275 }
RoboErik01fe6612014-02-13 14:19:04 -08001276 }
1277
1278}