SampleMediaRouteProvider.java revision f515b3268334381e81f7a4eb8283a362b9a6f725
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 mEnqueueCount +=1; 446 return true; 447 } 448 449 private boolean handleRemove(Intent intent, ControlRequestCallback callback) { 450 String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID); 451 if (sid == null || !sid.equals(mSessionManager.getSessionId())) { 452 return false; 453 } 454 455 String iid = intent.getStringExtra(MediaControlIntent.EXTRA_ITEM_ID); 456 PlaylistItem item = mSessionManager.remove(iid); 457 if (callback != null) { 458 if (item != null) { 459 Bundle result = new Bundle(); 460 result.putBundle(MediaControlIntent.EXTRA_ITEM_STATUS, 461 item.getStatus().asBundle()); 462 callback.onResult(result); 463 } else { 464 callback.onError("Failed to remove" + 465 ", sid=" + sid + ", iid=" + iid, null); 466 } 467 } 468 return (item != null); 469 } 470 471 private boolean handleSeek(Intent intent, ControlRequestCallback callback) { 472 String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID); 473 if (sid == null || !sid.equals(mSessionManager.getSessionId())) { 474 return false; 475 } 476 477 String iid = intent.getStringExtra(MediaControlIntent.EXTRA_ITEM_ID); 478 long pos = intent.getLongExtra(MediaControlIntent.EXTRA_ITEM_CONTENT_POSITION, 0); 479 Log.d(TAG, mRouteId + ": Received seek request, pos=" + pos); 480 PlaylistItem item = mSessionManager.seek(iid, pos); 481 if (callback != null) { 482 if (item != null) { 483 Bundle result = new Bundle(); 484 result.putBundle(MediaControlIntent.EXTRA_ITEM_STATUS, 485 item.getStatus().asBundle()); 486 callback.onResult(result); 487 } else { 488 callback.onError("Failed to seek" + 489 ", sid=" + sid + ", iid=" + iid + ", pos=" + pos, null); 490 } 491 } 492 return (item != null); 493 } 494 495 private boolean handleGetStatus(Intent intent, ControlRequestCallback callback) { 496 String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID); 497 String iid = intent.getStringExtra(MediaControlIntent.EXTRA_ITEM_ID); 498 Log.d(TAG, mRouteId + ": Received getStatus request, sid=" + sid + ", iid=" + iid); 499 PlaylistItem item = mSessionManager.getStatus(iid); 500 if (callback != null) { 501 if (item != null) { 502 Bundle result = new Bundle(); 503 result.putBundle(MediaControlIntent.EXTRA_ITEM_STATUS, 504 item.getStatus().asBundle()); 505 callback.onResult(result); 506 } else { 507 callback.onError("Failed to get status" + 508 ", sid=" + sid + ", iid=" + iid, null); 509 } 510 } 511 return (item != null); 512 } 513 514 private boolean handlePause(Intent intent, ControlRequestCallback callback) { 515 String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID); 516 boolean success = (sid != null) && sid.equals(mSessionManager.getSessionId()); 517 mSessionManager.pause(); 518 if (callback != null) { 519 if (success) { 520 callback.onResult(new Bundle()); 521 handleSessionStatusChange(sid); 522 } else { 523 callback.onError("Failed to pause, sid=" + sid, null); 524 } 525 } 526 return success; 527 } 528 529 private boolean handleResume(Intent intent, ControlRequestCallback callback) { 530 String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID); 531 boolean success = (sid != null) && sid.equals(mSessionManager.getSessionId()); 532 mSessionManager.resume(); 533 if (callback != null) { 534 if (success) { 535 callback.onResult(new Bundle()); 536 handleSessionStatusChange(sid); 537 } else { 538 callback.onError("Failed to resume, sid=" + sid, null); 539 } 540 } 541 return success; 542 } 543 544 private boolean handleStop(Intent intent, ControlRequestCallback callback) { 545 String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID); 546 boolean success = (sid != null) && sid.equals(mSessionManager.getSessionId()); 547 mSessionManager.stop(); 548 if (callback != null) { 549 if (success) { 550 callback.onResult(new Bundle()); 551 handleSessionStatusChange(sid); 552 } else { 553 callback.onError("Failed to stop, sid=" + sid, null); 554 } 555 } 556 return success; 557 } 558 559 private boolean handleStartSession(Intent intent, ControlRequestCallback callback) { 560 String sid = mSessionManager.startSession(); 561 Log.d(TAG, "StartSession returns sessionId "+sid); 562 if (callback != null) { 563 if (sid != null) { 564 Bundle result = new Bundle(); 565 result.putString(MediaControlIntent.EXTRA_SESSION_ID, sid); 566 result.putBundle(MediaControlIntent.EXTRA_SESSION_STATUS, 567 mSessionManager.getSessionStatus(sid).asBundle()); 568 callback.onResult(result); 569 mSessionReceiver = (PendingIntent)intent.getParcelableExtra( 570 MediaControlIntent.EXTRA_SESSION_STATUS_UPDATE_RECEIVER); 571 handleSessionStatusChange(sid); 572 } else { 573 callback.onError("Failed to start session.", null); 574 } 575 } 576 return (sid != null); 577 } 578 579 private boolean handleGetSessionStatus(Intent intent, ControlRequestCallback callback) { 580 String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID); 581 582 MediaSessionStatus sessionStatus = mSessionManager.getSessionStatus(sid); 583 if (callback != null) { 584 if (sessionStatus != null) { 585 Bundle result = new Bundle(); 586 result.putBundle(MediaControlIntent.EXTRA_SESSION_STATUS, 587 mSessionManager.getSessionStatus(sid).asBundle()); 588 callback.onResult(result); 589 } else { 590 callback.onError("Failed to get session status, sid=" + sid, null); 591 } 592 } 593 return (sessionStatus != null); 594 } 595 596 private boolean handleEndSession(Intent intent, ControlRequestCallback callback) { 597 String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID); 598 boolean success = (sid != null) && sid.equals(mSessionManager.getSessionId()) 599 && mSessionManager.endSession(); 600 if (callback != null) { 601 if (success) { 602 Bundle result = new Bundle(); 603 MediaSessionStatus sessionStatus = new MediaSessionStatus.Builder( 604 MediaSessionStatus.SESSION_STATE_ENDED).build(); 605 result.putBundle(MediaControlIntent.EXTRA_SESSION_STATUS, sessionStatus.asBundle()); 606 callback.onResult(result); 607 handleSessionStatusChange(sid); 608 mSessionReceiver = null; 609 } else { 610 callback.onError("Failed to end session, sid=" + sid, null); 611 } 612 } 613 return success; 614 } 615 616 private void handleStatusChange(PlaylistItem item) { 617 if (item == null) { 618 item = mSessionManager.getCurrentItem(); 619 } 620 if (item != null) { 621 PendingIntent receiver = item.getUpdateReceiver(); 622 if (receiver != null) { 623 Intent intent = new Intent(); 624 intent.putExtra(MediaControlIntent.EXTRA_SESSION_ID, item.getSessionId()); 625 intent.putExtra(MediaControlIntent.EXTRA_ITEM_ID, item.getItemId()); 626 intent.putExtra(MediaControlIntent.EXTRA_ITEM_STATUS, 627 item.getStatus().asBundle()); 628 try { 629 receiver.send(getContext(), 0, intent); 630 Log.d(TAG, mRouteId + ": Sending status update from provider"); 631 } catch (PendingIntent.CanceledException e) { 632 Log.d(TAG, mRouteId + ": Failed to send status update!"); 633 } 634 } 635 } 636 } 637 638 private void handleSessionStatusChange(String sid) { 639 if (mSessionReceiver != null) { 640 Intent intent = new Intent(); 641 intent.putExtra(MediaControlIntent.EXTRA_SESSION_ID, sid); 642 intent.putExtra(MediaControlIntent.EXTRA_SESSION_STATUS, 643 mSessionManager.getSessionStatus(sid).asBundle()); 644 try { 645 mSessionReceiver.send(getContext(), 0, intent); 646 Log.d(TAG, mRouteId + ": Sending session status update from provider"); 647 } catch (PendingIntent.CanceledException e) { 648 Log.d(TAG, mRouteId + ": Failed to send session status update!"); 649 } 650 } 651 } 652 } 653}