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