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