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