SampleMediaRouteProvider.java revision 1636d4634299cba990966c01dbb577275ab8273c
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<IntentFilter>(); 137 CONTROL_FILTERS_BASIC.add(f1); 138 CONTROL_FILTERS_BASIC.add(f2); 139 CONTROL_FILTERS_BASIC.add(f3); 140 141 CONTROL_FILTERS_QUEUING = 142 new ArrayList<IntentFilter>(CONTROL_FILTERS_BASIC); 143 CONTROL_FILTERS_QUEUING.add(f4); 144 CONTROL_FILTERS_QUEUING.add(f5); 145 146 CONTROL_FILTERS_SESSION = 147 new ArrayList<IntentFilter>(CONTROL_FILTERS_QUEUING); 148 CONTROL_FILTERS_SESSION.add(f6); 149 } 150 151 private static void addDataTypeUnchecked(IntentFilter filter, String type) { 152 try { 153 filter.addDataType(type); 154 } catch (MalformedMimeTypeException ex) { 155 throw new RuntimeException(ex); 156 } 157 } 158 159 private int mVolume = 5; 160 private int mEnqueueCount; 161 162 public SampleMediaRouteProvider(Context context) { 163 super(context); 164 165 publishRoutes(); 166 } 167 168 @Override 169 public RouteController onCreateRouteController(String routeId) { 170 return new SampleRouteController(routeId); 171 } 172 173 private void publishRoutes() { 174 Resources r = getContext().getResources(); 175 Intent settingsIntent = new Intent(Intent.ACTION_MAIN); 176 settingsIntent.setClass(getContext(), SampleMediaRouteSettingsActivity.class); 177 IntentSender is = PendingIntent.getActivity(getContext(), 99, settingsIntent, 178 Intent.FLAG_ACTIVITY_NEW_TASK).getIntentSender(); 179 180 MediaRouteDescriptor routeDescriptor1 = new MediaRouteDescriptor.Builder( 181 FIXED_VOLUME_ROUTE_ID, 182 r.getString(R.string.fixed_volume_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_FIXED) 188 .setVolume(VOLUME_MAX) 189 .setCanDisconnect(true) 190 .setSettingsActivity(is) 191 .build(); 192 193 MediaRouteDescriptor routeDescriptor2 = new MediaRouteDescriptor.Builder( 194 VARIABLE_VOLUME_BASIC_ROUTE_ID, 195 r.getString(R.string.variable_volume_basic_route_name)) 196 .setDescription(r.getString(R.string.sample_route_description)) 197 .addControlFilters(CONTROL_FILTERS_BASIC) 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 .setSettingsActivity(is) 204 .build(); 205 206 MediaRouteDescriptor routeDescriptor3 = new MediaRouteDescriptor.Builder( 207 VARIABLE_VOLUME_QUEUING_ROUTE_ID, 208 r.getString(R.string.variable_volume_queuing_route_name)) 209 .setDescription(r.getString(R.string.sample_route_description)) 210 .addControlFilters(CONTROL_FILTERS_QUEUING) 211 .setPlaybackStream(AudioManager.STREAM_MUSIC) 212 .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE) 213 .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE) 214 .setVolumeMax(VOLUME_MAX) 215 .setVolume(mVolume) 216 .setCanDisconnect(true) 217 .build(); 218 219 MediaRouteDescriptor routeDescriptor4 = new MediaRouteDescriptor.Builder( 220 VARIABLE_VOLUME_SESSION_ROUTE_ID, 221 r.getString(R.string.variable_volume_session_route_name)) 222 .setDescription(r.getString(R.string.sample_route_description)) 223 .addControlFilters(CONTROL_FILTERS_SESSION) 224 .setPlaybackStream(AudioManager.STREAM_MUSIC) 225 .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE) 226 .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE) 227 .setVolumeMax(VOLUME_MAX) 228 .setVolume(mVolume) 229 .build(); 230 231 MediaRouteDescriptor routeDescriptor5 = new MediaRouteDescriptor.Builder( 232 VARIABLE_VOLUME_ROUTE_GROUP_ID, 233 r.getString(R.string.variable_volume_route_group_name)) 234 .addChildId(VARIABLE_VOLUME_BASIC_ROUTE_ID) 235 .addChildId(VARIABLE_VOLUME_QUEUING_ROUTE_ID) 236 .addChildId(VARIABLE_VOLUME_SESSION_ROUTE_ID) 237 .setDescription(r.getString(R.string.sample_route_description)) 238 .addControlFilters(CONTROL_FILTERS_SESSION) 239 .setPlaybackStream(AudioManager.STREAM_MUSIC) 240 .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE) 241 .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE) 242 .setVolumeMax(VOLUME_MAX) 243 .setVolume(mVolume) 244 .build(); 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 .addControlFilters(CONTROL_FILTERS_SESSION) 254 .setPlaybackStream(AudioManager.STREAM_MUSIC) 255 .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE) 256 .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE) 257 .setVolumeMax(VOLUME_MAX) 258 .setVolume(mVolume) 259 .build(); 260 261 MediaRouteProviderDescriptor providerDescriptor = new MediaRouteProviderDescriptor.Builder() 262 .addRoute(routeDescriptor1) 263 .addRoute(routeDescriptor2) 264 .addRoute(routeDescriptor3) 265 .addRoute(routeDescriptor4) 266 .addRoute(routeDescriptor5) 267 .addRoute(routeDescriptor6) 268 .build(); 269 setDescriptor(providerDescriptor); 270 } 271 272 private final class SampleRouteController extends MediaRouteProvider.RouteController { 273 private final String mRouteId; 274 private final SessionManager mSessionManager = new SessionManager("mrp"); 275 private final Player mPlayer; 276 private PendingIntent mSessionReceiver; 277 278 public SampleRouteController(String routeId) { 279 mRouteId = routeId; 280 mPlayer = Player.create(getContext(), null, null); 281 mSessionManager.setPlayer(mPlayer); 282 mSessionManager.setCallback(new SessionManager.Callback() { 283 @Override 284 public void onStatusChanged() { 285 } 286 287 @Override 288 public void onItemChanged(PlaylistItem item) { 289 handleStatusChange(item); 290 } 291 }); 292 setVolumeInternal(mVolume); 293 Log.d(TAG, mRouteId + ": Controller created"); 294 } 295 296 @Override 297 public void onRelease() { 298 Log.d(TAG, mRouteId + ": Controller released"); 299 mPlayer.release(); 300 } 301 302 @Override 303 public void onSelect() { 304 Log.d(TAG, mRouteId + ": Selected"); 305 mPlayer.connect(null); 306 } 307 308 @Override 309 public void onUnselect() { 310 Log.d(TAG, mRouteId + ": Unselected"); 311 mPlayer.release(); 312 } 313 314 @Override 315 public void onSetVolume(int volume) { 316 Log.d(TAG, mRouteId + ": Set volume to " + volume); 317 if (!mRouteId.equals(FIXED_VOLUME_ROUTE_ID)) { 318 setVolumeInternal(volume); 319 } 320 } 321 322 @Override 323 public void onUpdateVolume(int delta) { 324 Log.d(TAG, mRouteId + ": Update volume by " + delta); 325 if (!mRouteId.equals(FIXED_VOLUME_ROUTE_ID)) { 326 setVolumeInternal(mVolume + delta); 327 } 328 } 329 330 @Override 331 public boolean onControlRequest(Intent intent, ControlRequestCallback callback) { 332 Log.d(TAG, mRouteId + ": Received control request " + intent); 333 String action = intent.getAction(); 334 if (intent.hasCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) { 335 boolean success = false; 336 if (action.equals(MediaControlIntent.ACTION_PLAY)) { 337 success = handlePlay(intent, callback); 338 } else if (action.equals(MediaControlIntent.ACTION_ENQUEUE)) { 339 success = handleEnqueue(intent, callback); 340 } else if (action.equals(MediaControlIntent.ACTION_REMOVE)) { 341 success = handleRemove(intent, callback); 342 } else if (action.equals(MediaControlIntent.ACTION_SEEK)) { 343 success = handleSeek(intent, callback); 344 } else if (action.equals(MediaControlIntent.ACTION_GET_STATUS)) { 345 success = handleGetStatus(intent, callback); 346 } else if (action.equals(MediaControlIntent.ACTION_PAUSE)) { 347 success = handlePause(intent, callback); 348 } else if (action.equals(MediaControlIntent.ACTION_RESUME)) { 349 success = handleResume(intent, callback); 350 } else if (action.equals(MediaControlIntent.ACTION_STOP)) { 351 success = handleStop(intent, callback); 352 } else if (action.equals(MediaControlIntent.ACTION_START_SESSION)) { 353 success = handleStartSession(intent, callback); 354 } else if (action.equals(MediaControlIntent.ACTION_GET_SESSION_STATUS)) { 355 success = handleGetSessionStatus(intent, callback); 356 } else if (action.equals(MediaControlIntent.ACTION_END_SESSION)) { 357 success = handleEndSession(intent, callback); 358 } 359 Log.d(TAG, mSessionManager.toString()); 360 return success; 361 } 362 363 if (action.equals(ACTION_GET_TRACK_INFO) 364 && intent.hasCategory(CATEGORY_SAMPLE_ROUTE)) { 365 Bundle data = new Bundle(); 366 PlaylistItem item = mSessionManager.getCurrentItem(); 367 if (item != null) { 368 data.putString(TRACK_INFO_DESC, item.toString()); 369 data.putParcelable(TRACK_INFO_SNAPSHOT, mPlayer.getSnapshot()); 370 } 371 if (callback != null) { 372 callback.onResult(data); 373 } 374 return true; 375 } 376 return false; 377 } 378 379 private void setVolumeInternal(int volume) { 380 if (volume >= 0 && volume <= VOLUME_MAX) { 381 mVolume = volume; 382 Log.d(TAG, mRouteId + ": New volume is " + mVolume); 383 AudioManager audioManager = 384 (AudioManager)getContext().getSystemService(Context.AUDIO_SERVICE); 385 audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0); 386 publishRoutes(); 387 } 388 } 389 390 private boolean handlePlay(Intent intent, ControlRequestCallback callback) { 391 String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID); 392 if (sid != null && !sid.equals(mSessionManager.getSessionId())) { 393 Log.d(TAG, "handlePlay fails because of bad sid="+sid); 394 return false; 395 } 396 if (mSessionManager.hasSession()) { 397 mSessionManager.stop(); 398 } 399 return handleEnqueue(intent, callback); 400 } 401 402 private boolean handleEnqueue(Intent intent, ControlRequestCallback callback) { 403 String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID); 404 if (sid != null && !sid.equals(mSessionManager.getSessionId())) { 405 Log.d(TAG, "handleEnqueue fails because of bad sid="+sid); 406 return false; 407 } 408 409 Uri uri = intent.getData(); 410 if (uri == null) { 411 Log.d(TAG, "handleEnqueue fails because of bad uri="+uri); 412 return false; 413 } 414 415 boolean enqueue = intent.getAction().equals(MediaControlIntent.ACTION_ENQUEUE); 416 String mime = intent.getType(); 417 long pos = intent.getLongExtra(MediaControlIntent.EXTRA_ITEM_CONTENT_POSITION, 0); 418 Bundle metadata = intent.getBundleExtra(MediaControlIntent.EXTRA_ITEM_METADATA); 419 Bundle headers = intent.getBundleExtra(MediaControlIntent.EXTRA_ITEM_HTTP_HEADERS); 420 PendingIntent receiver = (PendingIntent)intent.getParcelableExtra( 421 MediaControlIntent.EXTRA_ITEM_STATUS_UPDATE_RECEIVER); 422 423 Log.d(TAG, mRouteId + ": Received " + (enqueue?"enqueue":"play") + " request" 424 + ", uri=" + uri 425 + ", mime=" + mime 426 + ", sid=" + sid 427 + ", pos=" + pos 428 + ", metadata=" + metadata 429 + ", headers=" + headers 430 + ", receiver=" + receiver); 431 PlaylistItem item = mSessionManager.add(uri, mime, receiver); 432 if (callback != null) { 433 if (item != null) { 434 Bundle result = new Bundle(); 435 result.putString(MediaControlIntent.EXTRA_SESSION_ID, item.getSessionId()); 436 result.putString(MediaControlIntent.EXTRA_ITEM_ID, item.getItemId()); 437 result.putBundle(MediaControlIntent.EXTRA_ITEM_STATUS, 438 item.getStatus().asBundle()); 439 callback.onResult(result); 440 } else { 441 callback.onError("Failed to open " + uri.toString(), null); 442 } 443 } 444 mEnqueueCount +=1; 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}