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