SampleMediaRouteProvider.java revision 50070d31a0e0f0173b4bfe3b65a2a62496537c44
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
55    private static final int VOLUME_MAX = 10;
56
57    /**
58     * A custom media control intent category for special requests that are
59     * supported by this provider's routes.
60     */
61    public static final String CATEGORY_SAMPLE_ROUTE =
62            "com.example.android.supportv7.media.CATEGORY_SAMPLE_ROUTE";
63
64    /**
65     * A custom media control intent action for special requests that are
66     * supported by this provider's routes.
67     * </p>
68     *
69     * @see #TRACK_INFO_DESC
70     * @see #TRACK_INFO_SNAPSHOT
71     */
72    public static final String ACTION_GET_TRACK_INFO =
73            "com.example.android.supportv7.media.ACTION_GET_TRACK_INFO";
74
75    /**
76     * {@link #ACTION_GET_TRACK_INFO} result data: a string of information about
77     * the currently playing media item
78     */
79    public static final String TRACK_INFO_DESC =
80            "com.example.android.supportv7.media.EXTRA_TRACK_INFO_DESC";
81
82    /**
83     * {@link #ACTION_GET_TRACK_INFO} result data: a bitmap containing a snapshot
84     * of the currently playing media item
85     */
86    public static final String TRACK_INFO_SNAPSHOT =
87            "com.example.android.supportv7.media.EXTRA_TRACK_INFO_SNAPSHOT";
88
89    private static final ArrayList<IntentFilter> CONTROL_FILTERS_BASIC;
90    private static final ArrayList<IntentFilter> CONTROL_FILTERS_QUEUING;
91    private static final ArrayList<IntentFilter> CONTROL_FILTERS_SESSION;
92
93    static {
94        IntentFilter f1 = new IntentFilter();
95        f1.addCategory(CATEGORY_SAMPLE_ROUTE);
96        f1.addAction(ACTION_GET_TRACK_INFO);
97
98        IntentFilter f2 = new IntentFilter();
99        f2.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
100        f2.addAction(MediaControlIntent.ACTION_PLAY);
101        f2.addDataScheme("http");
102        f2.addDataScheme("https");
103        f2.addDataScheme("rtsp");
104        f2.addDataScheme("file");
105        addDataTypeUnchecked(f2, "video/*");
106
107        IntentFilter f3 = new IntentFilter();
108        f3.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
109        f3.addAction(MediaControlIntent.ACTION_SEEK);
110        f3.addAction(MediaControlIntent.ACTION_GET_STATUS);
111        f3.addAction(MediaControlIntent.ACTION_PAUSE);
112        f3.addAction(MediaControlIntent.ACTION_RESUME);
113        f3.addAction(MediaControlIntent.ACTION_STOP);
114
115        IntentFilter f4 = new IntentFilter();
116        f4.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
117        f4.addAction(MediaControlIntent.ACTION_ENQUEUE);
118        f4.addDataScheme("http");
119        f4.addDataScheme("https");
120        f4.addDataScheme("rtsp");
121        f4.addDataScheme("file");
122        addDataTypeUnchecked(f4, "video/*");
123
124        IntentFilter f5 = new IntentFilter();
125        f5.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
126        f5.addAction(MediaControlIntent.ACTION_REMOVE);
127
128        IntentFilter f6 = new IntentFilter();
129        f6.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
130        f6.addAction(MediaControlIntent.ACTION_START_SESSION);
131        f6.addAction(MediaControlIntent.ACTION_GET_SESSION_STATUS);
132        f6.addAction(MediaControlIntent.ACTION_END_SESSION);
133
134        CONTROL_FILTERS_BASIC = new ArrayList<>();
135        CONTROL_FILTERS_BASIC.add(f1);
136        CONTROL_FILTERS_BASIC.add(f2);
137        CONTROL_FILTERS_BASIC.add(f3);
138
139        CONTROL_FILTERS_QUEUING = new ArrayList<>(CONTROL_FILTERS_BASIC);
140        CONTROL_FILTERS_QUEUING.add(f4);
141        CONTROL_FILTERS_QUEUING.add(f5);
142
143        CONTROL_FILTERS_SESSION = new ArrayList<>(CONTROL_FILTERS_QUEUING);
144        CONTROL_FILTERS_SESSION.add(f6);
145    }
146
147    private static void addDataTypeUnchecked(IntentFilter filter, String type) {
148        try {
149            filter.addDataType(type);
150        } catch (MalformedMimeTypeException ex) {
151            throw new RuntimeException(ex);
152        }
153    }
154
155    private int mVolume = 5;
156
157    public SampleMediaRouteProvider(Context context) {
158        super(context);
159
160        publishRoutes();
161    }
162
163    @Override
164    public RouteController onCreateRouteController(String routeId) {
165        return new SampleRouteController(routeId);
166    }
167
168    private void publishRoutes() {
169        Resources r = getContext().getResources();
170        Intent settingsIntent = new Intent(Intent.ACTION_MAIN);
171        settingsIntent.setClass(getContext(), SampleMediaRouteSettingsActivity.class);
172        IntentSender is = PendingIntent.getActivity(getContext(), 99, settingsIntent,
173                Intent.FLAG_ACTIVITY_NEW_TASK).getIntentSender();
174
175        MediaRouteDescriptor routeDescriptor1 = new MediaRouteDescriptor.Builder(
176                FIXED_VOLUME_ROUTE_ID,
177                r.getString(R.string.fixed_volume_route_name))
178                .setDescription(r.getString(R.string.sample_route_description))
179                .addControlFilters(CONTROL_FILTERS_BASIC)
180                .setPlaybackStream(AudioManager.STREAM_MUSIC)
181                .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
182                .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_FIXED)
183                .setVolume(VOLUME_MAX)
184                .setCanDisconnect(true)
185                .setSettingsActivity(is)
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                .setSettingsActivity(is)
199                .build();
200
201        MediaRouteDescriptor routeDescriptor3 = new MediaRouteDescriptor.Builder(
202                VARIABLE_VOLUME_QUEUING_ROUTE_ID,
203                r.getString(R.string.variable_volume_queuing_route_name))
204                .setDescription(r.getString(R.string.sample_route_description))
205                .addControlFilters(CONTROL_FILTERS_QUEUING)
206                .setPlaybackStream(AudioManager.STREAM_MUSIC)
207                .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
208                .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE)
209                .setVolumeMax(VOLUME_MAX)
210                .setVolume(mVolume)
211                .setCanDisconnect(true)
212                .build();
213
214        MediaRouteDescriptor routeDescriptor4 = new MediaRouteDescriptor.Builder(
215                VARIABLE_VOLUME_SESSION_ROUTE_ID,
216                r.getString(R.string.variable_volume_session_route_name))
217                .setDescription(r.getString(R.string.sample_route_description))
218                .addControlFilters(CONTROL_FILTERS_SESSION)
219                .setPlaybackStream(AudioManager.STREAM_MUSIC)
220                .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
221                .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE)
222                .setVolumeMax(VOLUME_MAX)
223                .setVolume(mVolume)
224                .build();
225
226        MediaRouteProviderDescriptor providerDescriptor = new MediaRouteProviderDescriptor.Builder()
227                .addRoute(routeDescriptor1)
228                .addRoute(routeDescriptor2)
229                .addRoute(routeDescriptor3)
230                .addRoute(routeDescriptor4)
231                .build();
232        setDescriptor(providerDescriptor);
233    }
234
235    private final class SampleRouteController extends MediaRouteProvider.RouteController {
236        private final String mRouteId;
237        private final SessionManager mSessionManager = new SessionManager("mrp");
238        private final Player mPlayer;
239        private PendingIntent mSessionReceiver;
240
241        public SampleRouteController(String routeId) {
242            mRouteId = routeId;
243            mPlayer = Player.create(getContext(), null, null);
244            mSessionManager.setPlayer(mPlayer);
245            mSessionManager.setCallback(new SessionManager.Callback() {
246                @Override
247                public void onStatusChanged() {
248                }
249
250                @Override
251                public void onItemChanged(PlaylistItem item) {
252                    handleStatusChange(item);
253                }
254            });
255            setVolumeInternal(mVolume);
256            Log.d(TAG, mRouteId + ": Controller created");
257        }
258
259        @Override
260        public void onRelease() {
261            Log.d(TAG, mRouteId + ": Controller released");
262            mPlayer.release();
263        }
264
265        @Override
266        public void onSelect() {
267            Log.d(TAG, mRouteId + ": Selected");
268            mPlayer.connect(null);
269        }
270
271        @Override
272        public void onUnselect() {
273            Log.d(TAG, mRouteId + ": Unselected");
274            mPlayer.release();
275        }
276
277        @Override
278        public void onSetVolume(int volume) {
279            Log.d(TAG, mRouteId + ": Set volume to " + volume);
280            if (!mRouteId.equals(FIXED_VOLUME_ROUTE_ID)) {
281                setVolumeInternal(volume);
282            }
283        }
284
285        @Override
286        public void onUpdateVolume(int delta) {
287            Log.d(TAG, mRouteId + ": Update volume by " + delta);
288            if (!mRouteId.equals(FIXED_VOLUME_ROUTE_ID)) {
289                setVolumeInternal(mVolume + delta);
290            }
291        }
292
293        @Override
294        public boolean onControlRequest(Intent intent, ControlRequestCallback callback) {
295            Log.d(TAG, mRouteId + ": Received control request " + intent);
296            String action = intent.getAction();
297            if (intent.hasCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) {
298                boolean success = false;
299                if (action.equals(MediaControlIntent.ACTION_PLAY)) {
300                    success = handlePlay(intent, callback);
301                } else if (action.equals(MediaControlIntent.ACTION_ENQUEUE)) {
302                    success = handleEnqueue(intent, callback);
303                } else if (action.equals(MediaControlIntent.ACTION_REMOVE)) {
304                    success = handleRemove(intent, callback);
305                } else if (action.equals(MediaControlIntent.ACTION_SEEK)) {
306                    success = handleSeek(intent, callback);
307                } else if (action.equals(MediaControlIntent.ACTION_GET_STATUS)) {
308                    success = handleGetStatus(intent, callback);
309                } else if (action.equals(MediaControlIntent.ACTION_PAUSE)) {
310                    success = handlePause(intent, callback);
311                } else if (action.equals(MediaControlIntent.ACTION_RESUME)) {
312                    success = handleResume(intent, callback);
313                } else if (action.equals(MediaControlIntent.ACTION_STOP)) {
314                    success = handleStop(intent, callback);
315                } else if (action.equals(MediaControlIntent.ACTION_START_SESSION)) {
316                    success = handleStartSession(intent, callback);
317                } else if (action.equals(MediaControlIntent.ACTION_GET_SESSION_STATUS)) {
318                    success = handleGetSessionStatus(intent, callback);
319                } else if (action.equals(MediaControlIntent.ACTION_END_SESSION)) {
320                    success = handleEndSession(intent, callback);
321                }
322                Log.d(TAG, mSessionManager.toString());
323                return success;
324            }
325
326            if (action.equals(ACTION_GET_TRACK_INFO)
327                    && intent.hasCategory(CATEGORY_SAMPLE_ROUTE)) {
328                Bundle data = new Bundle();
329                PlaylistItem item = mSessionManager.getCurrentItem();
330                if (item != null) {
331                    data.putString(TRACK_INFO_DESC, item.toString());
332                    data.putParcelable(TRACK_INFO_SNAPSHOT, mPlayer.getSnapshot());
333                }
334                if (callback != null) {
335                    callback.onResult(data);
336                }
337                return true;
338            }
339            return false;
340        }
341
342        private void setVolumeInternal(int volume) {
343            if (volume >= 0 && volume <= VOLUME_MAX) {
344                mVolume = volume;
345                Log.d(TAG, mRouteId + ": New volume is " + mVolume);
346                AudioManager audioManager =
347                        (AudioManager)getContext().getSystemService(Context.AUDIO_SERVICE);
348                audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
349                publishRoutes();
350            }
351        }
352
353        private boolean handlePlay(Intent intent, ControlRequestCallback callback) {
354            String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID);
355            if (sid != null && !sid.equals(mSessionManager.getSessionId())) {
356                Log.d(TAG, "handlePlay fails because of bad sid="+sid);
357                return false;
358            }
359            if (mSessionManager.hasSession()) {
360                mSessionManager.stop();
361            }
362            return handleEnqueue(intent, callback);
363        }
364
365        private boolean handleEnqueue(Intent intent, ControlRequestCallback callback) {
366            String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID);
367            if (sid != null && !sid.equals(mSessionManager.getSessionId())) {
368                Log.d(TAG, "handleEnqueue fails because of bad sid="+sid);
369                return false;
370            }
371
372            Uri uri = intent.getData();
373            if (uri == null) {
374                Log.d(TAG, "handleEnqueue fails because of bad uri="+uri);
375                return false;
376            }
377
378            boolean enqueue = intent.getAction().equals(MediaControlIntent.ACTION_ENQUEUE);
379            String mime = intent.getType();
380            long pos = intent.getLongExtra(MediaControlIntent.EXTRA_ITEM_CONTENT_POSITION, 0);
381            Bundle metadata = intent.getBundleExtra(MediaControlIntent.EXTRA_ITEM_METADATA);
382            Bundle headers = intent.getBundleExtra(MediaControlIntent.EXTRA_ITEM_HTTP_HEADERS);
383            PendingIntent receiver = (PendingIntent)intent.getParcelableExtra(
384                    MediaControlIntent.EXTRA_ITEM_STATUS_UPDATE_RECEIVER);
385
386            Log.d(TAG, mRouteId + ": Received " + (enqueue?"enqueue":"play") + " request"
387                    + ", uri=" + uri
388                    + ", mime=" + mime
389                    + ", sid=" + sid
390                    + ", pos=" + pos
391                    + ", metadata=" + metadata
392                    + ", headers=" + headers
393                    + ", receiver=" + receiver);
394            PlaylistItem item = mSessionManager.add(uri, mime, receiver);
395            if (callback != null) {
396                if (item != null) {
397                    Bundle result = new Bundle();
398                    result.putString(MediaControlIntent.EXTRA_SESSION_ID, item.getSessionId());
399                    result.putString(MediaControlIntent.EXTRA_ITEM_ID, item.getItemId());
400                    result.putBundle(MediaControlIntent.EXTRA_ITEM_STATUS,
401                            item.getStatus().asBundle());
402                    callback.onResult(result);
403                } else {
404                    callback.onError("Failed to open " + uri.toString(), null);
405                }
406            }
407            return true;
408        }
409
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
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
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
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
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
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
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
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
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
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
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}
615