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