1 /* 2 * Copyright (C) 2013 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 17 package com.example.android.supportv7.media; 18 19 import com.example.android.supportv7.R; 20 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.IntentFilter; 24 import android.content.IntentFilter.MalformedMimeTypeException; 25 import android.content.res.Resources; 26 import android.graphics.Bitmap; 27 import android.media.AudioManager; 28 import android.media.MediaRouter; 29 import android.net.Uri; 30 import android.os.Bundle; 31 import android.app.PendingIntent; 32 import android.support.v7.media.MediaControlIntent; 33 import android.support.v7.media.MediaItemStatus; 34 import android.support.v7.media.MediaRouteProvider; 35 import android.support.v7.media.MediaRouter.ControlRequestCallback; 36 import android.support.v7.media.MediaRouteProviderDescriptor; 37 import android.support.v7.media.MediaRouteDescriptor; 38 import android.support.v7.media.MediaSessionStatus; 39 import android.util.Log; 40 import android.view.Gravity; 41 import android.view.Surface; 42 import android.view.SurfaceHolder; 43 44 import java.util.ArrayList; 45 46 /** 47 * Demonstrates how to create a custom media route provider. 48 * 49 * @see SampleMediaRouteProviderService 50 */ 51 final class SampleMediaRouteProvider extends MediaRouteProvider { 52 private static final String TAG = "SampleMediaRouteProvider"; 53 54 private static final String FIXED_VOLUME_ROUTE_ID = "fixed"; 55 private static final String VARIABLE_VOLUME_BASIC_ROUTE_ID = "variable_basic"; 56 private static final String VARIABLE_VOLUME_QUEUING_ROUTE_ID = "variable_queuing"; 57 private static final String VARIABLE_VOLUME_SESSION_ROUTE_ID = "variable_session"; 58 private static final int VOLUME_MAX = 10; 59 60 /** 61 * A custom media control intent category for special requests that are 62 * supported by this provider's routes. 63 */ 64 public static final String CATEGORY_SAMPLE_ROUTE = 65 "com.example.android.supportv7.media.CATEGORY_SAMPLE_ROUTE"; 66 67 /** 68 * A custom media control intent action for special requests that are 69 * supported by this provider's routes. 70 * </p> 71 * 72 * @see #TRACK_INFO_DESC 73 * @see #TRACK_INFO_SNAPSHOT 74 */ 75 public static final String ACTION_GET_TRACK_INFO = 76 "com.example.android.supportv7.media.ACTION_GET_TRACK_INFO"; 77 78 /** 79 * {@link #ACTION_GET_TRACK_INFO} result data: a string of information about 80 * the currently playing media item 81 */ 82 public static final String TRACK_INFO_DESC = 83 "com.example.android.supportv7.media.EXTRA_TRACK_INFO_DESC"; 84 85 /** 86 * {@link #ACTION_GET_TRACK_INFO} result data: a bitmap containing a snapshot 87 * of the currently playing media item 88 */ 89 public static final String TRACK_INFO_SNAPSHOT = 90 "com.example.android.supportv7.media.EXTRA_TRACK_INFO_SNAPSHOT"; 91 92 private static final ArrayList<IntentFilter> CONTROL_FILTERS_BASIC; 93 private static final ArrayList<IntentFilter> CONTROL_FILTERS_QUEUING; 94 private static final ArrayList<IntentFilter> CONTROL_FILTERS_SESSION; 95 96 static { 97 IntentFilter f1 = new IntentFilter(); 98 f1.addCategory(CATEGORY_SAMPLE_ROUTE); 99 f1.addAction(ACTION_GET_TRACK_INFO); 100 101 IntentFilter f2 = new IntentFilter(); 102 f2.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK); 103 f2.addAction(MediaControlIntent.ACTION_PLAY); 104 f2.addDataScheme("http"); 105 f2.addDataScheme("https"); 106 f2.addDataScheme("rtsp"); 107 f2.addDataScheme("file"); 108 addDataTypeUnchecked(f2, "video/*"); 109 110 IntentFilter f3 = new IntentFilter(); 111 f3.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK); 112 f3.addAction(MediaControlIntent.ACTION_SEEK); 113 f3.addAction(MediaControlIntent.ACTION_GET_STATUS); 114 f3.addAction(MediaControlIntent.ACTION_PAUSE); 115 f3.addAction(MediaControlIntent.ACTION_RESUME); 116 f3.addAction(MediaControlIntent.ACTION_STOP); 117 118 IntentFilter f4 = new IntentFilter(); 119 f4.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK); 120 f4.addAction(MediaControlIntent.ACTION_ENQUEUE); 121 f4.addDataScheme("http"); 122 f4.addDataScheme("https"); 123 f4.addDataScheme("rtsp"); 124 f4.addDataScheme("file"); 125 addDataTypeUnchecked(f4, "video/*"); 126 127 IntentFilter f5 = new IntentFilter(); 128 f5.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK); 129 f5.addAction(MediaControlIntent.ACTION_REMOVE); 130 131 IntentFilter f6 = new IntentFilter(); 132 f6.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK); 133 f6.addAction(MediaControlIntent.ACTION_START_SESSION); 134 f6.addAction(MediaControlIntent.ACTION_GET_SESSION_STATUS); 135 f6.addAction(MediaControlIntent.ACTION_END_SESSION); 136 137 CONTROL_FILTERS_BASIC = new ArrayList<IntentFilter>(); 138 CONTROL_FILTERS_BASIC.add(f1); 139 CONTROL_FILTERS_BASIC.add(f2); 140 CONTROL_FILTERS_BASIC.add(f3); 141 142 CONTROL_FILTERS_QUEUING = 143 new ArrayList<IntentFilter>(CONTROL_FILTERS_BASIC); 144 CONTROL_FILTERS_QUEUING.add(f4); 145 CONTROL_FILTERS_QUEUING.add(f5); 146 147 CONTROL_FILTERS_SESSION = 148 new ArrayList<IntentFilter>(CONTROL_FILTERS_QUEUING); 149 CONTROL_FILTERS_SESSION.add(f6); 150 } 151 152 private static void addDataTypeUnchecked(IntentFilter filter, String type) { 153 try { 154 filter.addDataType(type); 155 } catch (MalformedMimeTypeException ex) { 156 throw new RuntimeException(ex); 157 } 158 } 159 160 private int mVolume = 5; 161 private int mEnqueueCount; 162 163 public SampleMediaRouteProvider(Context context) { 164 super(context); 165 166 publishRoutes(); 167 } 168 169 @Override 170 public RouteController onCreateRouteController(String routeId) { 171 return new SampleRouteController(routeId); 172 } 173 174 private void publishRoutes() { 175 Resources r = getContext().getResources(); 176 177 MediaRouteDescriptor routeDescriptor1 = new MediaRouteDescriptor.Builder( 178 FIXED_VOLUME_ROUTE_ID, 179 r.getString(R.string.fixed_volume_route_name)) 180 .setDescription(r.getString(R.string.sample_route_description)) 181 .addControlFilters(CONTROL_FILTERS_BASIC) 182 .setPlaybackStream(AudioManager.STREAM_MUSIC) 183 .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE) 184 .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_FIXED) 185 .setVolume(VOLUME_MAX) 186 .build(); 187 188 MediaRouteDescriptor routeDescriptor2 = new MediaRouteDescriptor.Builder( 189 VARIABLE_VOLUME_BASIC_ROUTE_ID, 190 r.getString(R.string.variable_volume_basic_route_name)) 191 .setDescription(r.getString(R.string.sample_route_description)) 192 .addControlFilters(CONTROL_FILTERS_BASIC) 193 .setPlaybackStream(AudioManager.STREAM_MUSIC) 194 .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE) 195 .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE) 196 .setVolumeMax(VOLUME_MAX) 197 .setVolume(mVolume) 198 .build(); 199 200 MediaRouteDescriptor routeDescriptor3 = new MediaRouteDescriptor.Builder( 201 VARIABLE_VOLUME_QUEUING_ROUTE_ID, 202 r.getString(R.string.variable_volume_queuing_route_name)) 203 .setDescription(r.getString(R.string.sample_route_description)) 204 .addControlFilters(CONTROL_FILTERS_QUEUING) 205 .setPlaybackStream(AudioManager.STREAM_MUSIC) 206 .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE) 207 .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE) 208 .setVolumeMax(VOLUME_MAX) 209 .setVolume(mVolume) 210 .build(); 211 212 MediaRouteDescriptor routeDescriptor4 = new MediaRouteDescriptor.Builder( 213 VARIABLE_VOLUME_SESSION_ROUTE_ID, 214 r.getString(R.string.variable_volume_session_route_name)) 215 .setDescription(r.getString(R.string.sample_route_description)) 216 .addControlFilters(CONTROL_FILTERS_SESSION) 217 .setPlaybackStream(AudioManager.STREAM_MUSIC) 218 .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE) 219 .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE) 220 .setVolumeMax(VOLUME_MAX) 221 .setVolume(mVolume) 222 .build(); 223 224 MediaRouteProviderDescriptor providerDescriptor = 225 new MediaRouteProviderDescriptor.Builder() 226 .addRoute(routeDescriptor1) 227 .addRoute(routeDescriptor2) 228 .addRoute(routeDescriptor3) 229 .addRoute(routeDescriptor4) 230 .build(); 231 setDescriptor(providerDescriptor); 232 } 233 234 private final class SampleRouteController extends MediaRouteProvider.RouteController { 235 private final String mRouteId; 236 private final SessionManager mSessionManager = new SessionManager("mrp"); 237 private final Player mPlayer; 238 private PendingIntent mSessionReceiver; 239 240 public SampleRouteController(String routeId) { 241 mRouteId = routeId; 242 mPlayer = Player.create(getContext(), null); 243 mSessionManager.setPlayer(mPlayer); 244 mSessionManager.setCallback(new SessionManager.Callback() { 245 @Override 246 public void onStatusChanged() { 247 } 248 249 @Override 250 public void onItemChanged(PlaylistItem item) { 251 handleStatusChange(item); 252 } 253 }); 254 setVolumeInternal(mVolume); 255 Log.d(TAG, mRouteId + ": Controller created"); 256 } 257 258 @Override 259 public void onRelease() { 260 Log.d(TAG, mRouteId + ": Controller released"); 261 mPlayer.release(); 262 } 263 264 @Override 265 public void onSelect() { 266 Log.d(TAG, mRouteId + ": Selected"); 267 mPlayer.connect(null); 268 } 269 270 @Override 271 public void onUnselect() { 272 Log.d(TAG, mRouteId + ": Unselected"); 273 mPlayer.release(); 274 } 275 276 @Override 277 public void onSetVolume(int volume) { 278 Log.d(TAG, mRouteId + ": Set volume to " + volume); 279 if (!mRouteId.equals(FIXED_VOLUME_ROUTE_ID)) { 280 setVolumeInternal(volume); 281 } 282 } 283 284 @Override 285 public void onUpdateVolume(int delta) { 286 Log.d(TAG, mRouteId + ": Update volume by " + delta); 287 if (!mRouteId.equals(FIXED_VOLUME_ROUTE_ID)) { 288 setVolumeInternal(mVolume + delta); 289 } 290 } 291 292 @Override 293 public boolean onControlRequest(Intent intent, ControlRequestCallback callback) { 294 Log.d(TAG, mRouteId + ": Received control request " + intent); 295 String action = intent.getAction(); 296 if (intent.hasCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) { 297 boolean success = false; 298 if (action.equals(MediaControlIntent.ACTION_PLAY)) { 299 success = handlePlay(intent, callback); 300 } else if (action.equals(MediaControlIntent.ACTION_ENQUEUE)) { 301 success = handleEnqueue(intent, callback); 302 } else if (action.equals(MediaControlIntent.ACTION_REMOVE)) { 303 success = handleRemove(intent, callback); 304 } else if (action.equals(MediaControlIntent.ACTION_SEEK)) { 305 success = handleSeek(intent, callback); 306 } else if (action.equals(MediaControlIntent.ACTION_GET_STATUS)) { 307 success = handleGetStatus(intent, callback); 308 } else if (action.equals(MediaControlIntent.ACTION_PAUSE)) { 309 success = handlePause(intent, callback); 310 } else if (action.equals(MediaControlIntent.ACTION_RESUME)) { 311 success = handleResume(intent, callback); 312 } else if (action.equals(MediaControlIntent.ACTION_STOP)) { 313 success = handleStop(intent, callback); 314 } else if (action.equals(MediaControlIntent.ACTION_START_SESSION)) { 315 success = handleStartSession(intent, callback); 316 } else if (action.equals(MediaControlIntent.ACTION_GET_SESSION_STATUS)) { 317 success = handleGetSessionStatus(intent, callback); 318 } else if (action.equals(MediaControlIntent.ACTION_END_SESSION)) { 319 success = handleEndSession(intent, callback); 320 } 321 Log.d(TAG, mSessionManager.toString()); 322 return success; 323 } 324 325 if (action.equals(ACTION_GET_TRACK_INFO) 326 && intent.hasCategory(CATEGORY_SAMPLE_ROUTE)) { 327 Bundle data = new Bundle(); 328 PlaylistItem item = mSessionManager.getCurrentItem(); 329 if (item != null) { 330 data.putString(TRACK_INFO_DESC, item.toString()); 331 data.putParcelable(TRACK_INFO_SNAPSHOT, mPlayer.getSnapshot()); 332 } 333 if (callback != null) { 334 callback.onResult(data); 335 } 336 return true; 337 } 338 return false; 339 } 340 341 private void setVolumeInternal(int volume) { 342 if (volume >= 0 && volume <= VOLUME_MAX) { 343 mVolume = volume; 344 Log.d(TAG, mRouteId + ": New volume is " + mVolume); 345 AudioManager audioManager = 346 (AudioManager)getContext().getSystemService(Context.AUDIO_SERVICE); 347 audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0); 348 publishRoutes(); 349 } 350 } 351 352 private boolean handlePlay(Intent intent, ControlRequestCallback callback) { 353 String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID); 354 if (sid != null && !sid.equals(mSessionManager.getSessionId())) { 355 Log.d(TAG, "handlePlay fails because of bad sid="+sid); 356 return false; 357 } 358 if (mSessionManager.hasSession()) { 359 mSessionManager.stop(); 360 } 361 return handleEnqueue(intent, callback); 362 } 363 364 private boolean handleEnqueue(Intent intent, ControlRequestCallback callback) { 365 String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID); 366 if (sid != null && !sid.equals(mSessionManager.getSessionId())) { 367 Log.d(TAG, "handleEnqueue fails because of bad sid="+sid); 368 return false; 369 } 370 371 Uri uri = intent.getData(); 372 if (uri == null) { 373 Log.d(TAG, "handleEnqueue fails because of bad uri="+uri); 374 return false; 375 } 376 377 boolean enqueue = intent.getAction().equals(MediaControlIntent.ACTION_ENQUEUE); 378 String mime = intent.getType(); 379 long pos = intent.getLongExtra(MediaControlIntent.EXTRA_ITEM_CONTENT_POSITION, 0); 380 Bundle metadata = intent.getBundleExtra(MediaControlIntent.EXTRA_ITEM_METADATA); 381 Bundle headers = intent.getBundleExtra(MediaControlIntent.EXTRA_ITEM_HTTP_HEADERS); 382 PendingIntent receiver = (PendingIntent)intent.getParcelableExtra( 383 MediaControlIntent.EXTRA_ITEM_STATUS_UPDATE_RECEIVER); 384 385 Log.d(TAG, mRouteId + ": Received " + (enqueue?"enqueue":"play") + " request" 386 + ", uri=" + uri 387 + ", mime=" + mime 388 + ", sid=" + sid 389 + ", pos=" + pos 390 + ", metadata=" + metadata 391 + ", headers=" + headers 392 + ", receiver=" + receiver); 393 PlaylistItem item = mSessionManager.add(uri, mime, receiver); 394 if (callback != null) { 395 if (item != null) { 396 Bundle result = new Bundle(); 397 result.putString(MediaControlIntent.EXTRA_SESSION_ID, item.getSessionId()); 398 result.putString(MediaControlIntent.EXTRA_ITEM_ID, item.getItemId()); 399 result.putBundle(MediaControlIntent.EXTRA_ITEM_STATUS, 400 item.getStatus().asBundle()); 401 callback.onResult(result); 402 } else { 403 callback.onError("Failed to open " + uri.toString(), null); 404 } 405 } 406 mEnqueueCount +=1; 407 return true; 408 } 409 410 private boolean handleRemove(Intent intent, ControlRequestCallback callback) { 411 String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID); 412 if (sid == null || !sid.equals(mSessionManager.getSessionId())) { 413 return false; 414 } 415 416 String iid = intent.getStringExtra(MediaControlIntent.EXTRA_ITEM_ID); 417 PlaylistItem item = mSessionManager.remove(iid); 418 if (callback != null) { 419 if (item != null) { 420 Bundle result = new Bundle(); 421 result.putBundle(MediaControlIntent.EXTRA_ITEM_STATUS, 422 item.getStatus().asBundle()); 423 callback.onResult(result); 424 } else { 425 callback.onError("Failed to remove" + 426 ", sid=" + sid + ", iid=" + iid, null); 427 } 428 } 429 return (item != null); 430 } 431 432 private boolean handleSeek(Intent intent, ControlRequestCallback callback) { 433 String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID); 434 if (sid == null || !sid.equals(mSessionManager.getSessionId())) { 435 return false; 436 } 437 438 String iid = intent.getStringExtra(MediaControlIntent.EXTRA_ITEM_ID); 439 long pos = intent.getLongExtra(MediaControlIntent.EXTRA_ITEM_CONTENT_POSITION, 0); 440 Log.d(TAG, mRouteId + ": Received seek request, pos=" + pos); 441 PlaylistItem item = mSessionManager.seek(iid, pos); 442 if (callback != null) { 443 if (item != null) { 444 Bundle result = new Bundle(); 445 result.putBundle(MediaControlIntent.EXTRA_ITEM_STATUS, 446 item.getStatus().asBundle()); 447 callback.onResult(result); 448 } else { 449 callback.onError("Failed to seek" + 450 ", sid=" + sid + ", iid=" + iid + ", pos=" + pos, null); 451 } 452 } 453 return (item != null); 454 } 455 456 private boolean handleGetStatus(Intent intent, ControlRequestCallback callback) { 457 String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID); 458 String iid = intent.getStringExtra(MediaControlIntent.EXTRA_ITEM_ID); 459 Log.d(TAG, mRouteId + ": Received getStatus request, sid=" + sid + ", iid=" + iid); 460 PlaylistItem item = mSessionManager.getStatus(iid); 461 if (callback != null) { 462 if (item != null) { 463 Bundle result = new Bundle(); 464 result.putBundle(MediaControlIntent.EXTRA_ITEM_STATUS, 465 item.getStatus().asBundle()); 466 callback.onResult(result); 467 } else { 468 callback.onError("Failed to get status" + 469 ", sid=" + sid + ", iid=" + iid, null); 470 } 471 } 472 return (item != null); 473 } 474 475 private boolean handlePause(Intent intent, ControlRequestCallback callback) { 476 String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID); 477 boolean success = (sid != null) && sid.equals(mSessionManager.getSessionId()); 478 mSessionManager.pause(); 479 if (callback != null) { 480 if (success) { 481 callback.onResult(new Bundle()); 482 handleSessionStatusChange(sid); 483 } else { 484 callback.onError("Failed to pause, sid=" + sid, null); 485 } 486 } 487 return success; 488 } 489 490 private boolean handleResume(Intent intent, ControlRequestCallback callback) { 491 String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID); 492 boolean success = (sid != null) && sid.equals(mSessionManager.getSessionId()); 493 mSessionManager.resume(); 494 if (callback != null) { 495 if (success) { 496 callback.onResult(new Bundle()); 497 handleSessionStatusChange(sid); 498 } else { 499 callback.onError("Failed to resume, sid=" + sid, null); 500 } 501 } 502 return success; 503 } 504 505 private boolean handleStop(Intent intent, ControlRequestCallback callback) { 506 String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID); 507 boolean success = (sid != null) && sid.equals(mSessionManager.getSessionId()); 508 mSessionManager.stop(); 509 if (callback != null) { 510 if (success) { 511 callback.onResult(new Bundle()); 512 handleSessionStatusChange(sid); 513 } else { 514 callback.onError("Failed to stop, sid=" + sid, null); 515 } 516 } 517 return success; 518 } 519 520 private boolean handleStartSession(Intent intent, ControlRequestCallback callback) { 521 String sid = mSessionManager.startSession(); 522 Log.d(TAG, "StartSession returns sessionId "+sid); 523 if (callback != null) { 524 if (sid != null) { 525 Bundle result = new Bundle(); 526 result.putString(MediaControlIntent.EXTRA_SESSION_ID, sid); 527 result.putBundle(MediaControlIntent.EXTRA_SESSION_STATUS, 528 mSessionManager.getSessionStatus(sid).asBundle()); 529 callback.onResult(result); 530 mSessionReceiver = (PendingIntent)intent.getParcelableExtra( 531 MediaControlIntent.EXTRA_SESSION_STATUS_UPDATE_RECEIVER); 532 handleSessionStatusChange(sid); 533 } else { 534 callback.onError("Failed to start session.", null); 535 } 536 } 537 return (sid != null); 538 } 539 540 private boolean handleGetSessionStatus(Intent intent, ControlRequestCallback callback) { 541 String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID); 542 543 MediaSessionStatus sessionStatus = mSessionManager.getSessionStatus(sid); 544 if (callback != null) { 545 if (sessionStatus != null) { 546 Bundle result = new Bundle(); 547 result.putBundle(MediaControlIntent.EXTRA_SESSION_STATUS, 548 mSessionManager.getSessionStatus(sid).asBundle()); 549 callback.onResult(result); 550 } else { 551 callback.onError("Failed to get session status, sid=" + sid, null); 552 } 553 } 554 return (sessionStatus != null); 555 } 556 557 private boolean handleEndSession(Intent intent, ControlRequestCallback callback) { 558 String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID); 559 boolean success = (sid != null) && sid.equals(mSessionManager.getSessionId()) 560 && mSessionManager.endSession(); 561 if (callback != null) { 562 if (success) { 563 Bundle result = new Bundle(); 564 MediaSessionStatus sessionStatus = new MediaSessionStatus.Builder( 565 MediaSessionStatus.SESSION_STATE_ENDED).build(); 566 result.putBundle(MediaControlIntent.EXTRA_SESSION_STATUS, sessionStatus.asBundle()); 567 callback.onResult(result); 568 handleSessionStatusChange(sid); 569 mSessionReceiver = null; 570 } else { 571 callback.onError("Failed to end session, sid=" + sid, null); 572 } 573 } 574 return success; 575 } 576 577 private void handleStatusChange(PlaylistItem item) { 578 if (item == null) { 579 item = mSessionManager.getCurrentItem(); 580 } 581 if (item != null) { 582 PendingIntent receiver = item.getUpdateReceiver(); 583 if (receiver != null) { 584 Intent intent = new Intent(); 585 intent.putExtra(MediaControlIntent.EXTRA_SESSION_ID, item.getSessionId()); 586 intent.putExtra(MediaControlIntent.EXTRA_ITEM_ID, item.getItemId()); 587 intent.putExtra(MediaControlIntent.EXTRA_ITEM_STATUS, 588 item.getStatus().asBundle()); 589 try { 590 receiver.send(getContext(), 0, intent); 591 Log.d(TAG, mRouteId + ": Sending status update from provider"); 592 } catch (PendingIntent.CanceledException e) { 593 Log.d(TAG, mRouteId + ": Failed to send status update!"); 594 } 595 } 596 } 597 } 598 599 private void handleSessionStatusChange(String sid) { 600 if (mSessionReceiver != null) { 601 Intent intent = new Intent(); 602 intent.putExtra(MediaControlIntent.EXTRA_SESSION_ID, sid); 603 intent.putExtra(MediaControlIntent.EXTRA_SESSION_STATUS, 604 mSessionManager.getSessionStatus(sid).asBundle()); 605 try { 606 mSessionReceiver.send(getContext(), 0, intent); 607 Log.d(TAG, mRouteId + ": Sending session status update from provider"); 608 } catch (PendingIntent.CanceledException e) { 609 Log.d(TAG, mRouteId + ": Failed to send session status update!"); 610 } 611 } 612 } 613 } 614 }