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