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