1a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang/*
2a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang * Copyright (C) 2013 The Android Open Source Project
3a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang *
4a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang * Licensed under the Apache License, Version 2.0 (the "License");
5a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang * you may not use this file except in compliance with the License.
6a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang * You may obtain a copy of the License at
7a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang *
8a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang *      http://www.apache.org/licenses/LICENSE-2.0
9a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang *
10a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang * Unless required by applicable law or agreed to in writing, software
11a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang * distributed under the License is distributed on an "AS IS" BASIS,
12a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang * See the License for the specific language governing permissions and
14a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang * limitations under the License.
15a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang */
16a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
17a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangpackage com.example.android.supportv7.media;
18a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
19a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.content.Context;
20a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.content.Intent;
21cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhangimport android.graphics.Bitmap;
22a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.os.Bundle;
23a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.support.v7.media.MediaItemStatus;
24a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.support.v7.media.MediaRouter.ControlRequestCallback;
25a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.support.v7.media.MediaRouter.RouteInfo;
26a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.support.v7.media.MediaSessionStatus;
27a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.support.v7.media.RemotePlaybackClient;
28a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.support.v7.media.RemotePlaybackClient.ItemActionCallback;
29a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.support.v7.media.RemotePlaybackClient.SessionActionCallback;
30a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.support.v7.media.RemotePlaybackClient.StatusCallback;
31a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.util.Log;
32a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
33a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport java.util.ArrayList;
34a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport java.util.List;
35a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
36a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang/**
37a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang * Handles playback of media items using a remote route.
38a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang *
39a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang * This class is used as a backend by PlaybackManager to feed media items to
40a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang * the remote route. When the remote route doesn't support queuing, media items
41a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang * are fed one-at-a-time; otherwise media items are enqueued to the remote side.
42a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang */
43a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangpublic class RemotePlayer extends Player {
44a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private static final String TAG = "RemotePlayer";
45a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
46a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private Context mContext;
47a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private RouteInfo mRoute;
48a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private boolean mEnqueuePending;
49cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang    private Bitmap mSnapshot;
50a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private List<PlaylistItem> mTempQueue = new ArrayList<PlaylistItem>();
51a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
52a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private RemotePlaybackClient mClient;
53a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private StatusCallback mStatusCallback = new StatusCallback() {
54a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        @Override
55a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        public void onItemStatusChanged(Bundle data,
56a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                String sessionId, MediaSessionStatus sessionStatus,
57a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                String itemId, MediaItemStatus itemStatus) {
58a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            logStatus("onItemStatusChanged", sessionId, sessionStatus, itemId, itemStatus);
5970f3627685b55b2bc1b3f0c17c9c30aa3a7fd062Donghyun Cho            if (mCallback != null) {
6070f3627685b55b2bc1b3f0c17c9c30aa3a7fd062Donghyun Cho                mCallback.onPlaylistChanged();
6170f3627685b55b2bc1b3f0c17c9c30aa3a7fd062Donghyun Cho                int state = itemStatus.getPlaybackState();
6270f3627685b55b2bc1b3f0c17c9c30aa3a7fd062Donghyun Cho                if (state == MediaItemStatus.PLAYBACK_STATE_FINISHED) {
6370f3627685b55b2bc1b3f0c17c9c30aa3a7fd062Donghyun Cho                    mCallback.onCompletion();
6470f3627685b55b2bc1b3f0c17c9c30aa3a7fd062Donghyun Cho                } else if (state == MediaItemStatus.PLAYBACK_STATE_ERROR) {
6570f3627685b55b2bc1b3f0c17c9c30aa3a7fd062Donghyun Cho                    mCallback.onError();
6670f3627685b55b2bc1b3f0c17c9c30aa3a7fd062Donghyun Cho                }
67a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
68a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
69a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
70a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        @Override
71a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        public void onSessionStatusChanged(Bundle data,
72a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                String sessionId, MediaSessionStatus sessionStatus) {
73a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            logStatus("onSessionStatusChanged", sessionId, sessionStatus, null, null);
74a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            if (mCallback != null) {
75a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                mCallback.onPlaylistChanged();
76a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
77a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
78a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
79a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        @Override
80a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        public void onSessionChanged(String sessionId) {
81a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            if (DEBUG) {
82a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                Log.d(TAG, "onSessionChanged: sessionId=" + sessionId);
83a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
84a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
85a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    };
86a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
87a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public RemotePlayer(Context context) {
88a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mContext = context;
89a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
90a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
91a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
92a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public boolean isRemotePlayback() {
93a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        return true;
94a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
95a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
96a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
97a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public boolean isQueuingSupported() {
98a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        return mClient.isQueuingSupported();
99a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
100a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
101a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
102a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public void connect(RouteInfo route) {
103a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mRoute = route;
104a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mClient = new RemotePlaybackClient(mContext, route);
105a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mClient.setStatusCallback(mStatusCallback);
106a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
107a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (DEBUG) {
108a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.d(TAG, "connected to: " + route
109a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    + ", isRemotePlaybackSupported: " + mClient.isRemotePlaybackSupported()
110a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    + ", isQueuingSupported: "+ mClient.isQueuingSupported());
111a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
112a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
113a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
114a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
115a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public void release() {
116a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mClient.release();
117a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
118a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (DEBUG) {
119a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.d(TAG, "released.");
120a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
121a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
122a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
123a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    // basic playback operations that are always supported
124a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
125a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public void play(final PlaylistItem item) {
126a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (DEBUG) {
127a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.d(TAG, "play: item=" + item);
128a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
129a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mClient.play(item.getUri(), "video/mp4", null, 0, null, new ItemActionCallback() {
130a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
131a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus,
132a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    String itemId, MediaItemStatus itemStatus) {
133a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logStatus("play: succeeded", sessionId, sessionStatus, itemId, itemStatus);
134a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                item.setRemoteItemId(itemId);
135a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (item.getPosition() > 0) {
136a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    seekInternal(item);
137a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
138a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (item.getState() == MediaItemStatus.PLAYBACK_STATE_PAUSED) {
139a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    pause();
1405d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik                } else {
1415d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik                    publishState(STATE_PLAYING);
142a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
143a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (mCallback != null) {
144a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    mCallback.onPlaylistChanged();
145a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
146a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
147a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
148a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
149a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onError(String error, int code, Bundle data) {
150a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logError("play: failed", error, code);
151a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
152a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        });
153a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
154a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
155a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
156a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public void seek(final PlaylistItem item) {
157a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        seekInternal(item);
158a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
159a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
160a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
161a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public void getStatus(final PlaylistItem item, final boolean update) {
162a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (!mClient.hasSession() || item.getRemoteItemId() == null) {
163a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            // if session is not valid or item id not assigend yet.
164a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            // just return, it's not fatal
165a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            return;
166a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
167a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
168a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (DEBUG) {
169a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.d(TAG, "getStatus: item=" + item + ", update=" + update);
170a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
171a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mClient.getStatus(item.getRemoteItemId(), null, new ItemActionCallback() {
172a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
173a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus,
174a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    String itemId, MediaItemStatus itemStatus) {
175a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logStatus("getStatus: succeeded", sessionId, sessionStatus, itemId, itemStatus);
176a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                int state = itemStatus.getPlaybackState();
177a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (state == MediaItemStatus.PLAYBACK_STATE_PLAYING
178a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                        || state == MediaItemStatus.PLAYBACK_STATE_PAUSED
179a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                        || state == MediaItemStatus.PLAYBACK_STATE_PENDING) {
180a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    item.setState(state);
181a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    item.setPosition(itemStatus.getContentPosition());
182a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    item.setDuration(itemStatus.getContentDuration());
183a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    item.setTimestamp(itemStatus.getTimestamp());
184a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
185a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (update && mCallback != null) {
186a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    mCallback.onPlaylistReady();
187a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
188a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
189a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
190a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
191a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onError(String error, int code, Bundle data) {
192a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logError("getStatus: failed", error, code);
193a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (update && mCallback != null) {
194a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    mCallback.onPlaylistReady();
195a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
196a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
197a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        });
198a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
199a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
200a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
201a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public void pause() {
202a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (!mClient.hasSession()) {
203a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            // ignore if no session
204a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            return;
205a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
206a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (DEBUG) {
207a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.d(TAG, "pause");
208a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
209a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mClient.pause(null, new SessionActionCallback() {
210a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
211a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus) {
212a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logStatus("pause: succeeded", sessionId, sessionStatus, null, null);
213a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (mCallback != null) {
214a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    mCallback.onPlaylistChanged();
215a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
2165d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik                publishState(STATE_PAUSED);
217a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
218a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
219a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
220a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onError(String error, int code, Bundle data) {
221a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logError("pause: failed", error, code);
222a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
223a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        });
224a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
225a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
226a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
227a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public void resume() {
228a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (!mClient.hasSession()) {
229a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            // ignore if no session
230a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            return;
231a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
232a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (DEBUG) {
233a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.d(TAG, "resume");
234a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
235a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mClient.resume(null, new SessionActionCallback() {
236a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
237a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus) {
238a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logStatus("resume: succeeded", sessionId, sessionStatus, null, null);
239a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (mCallback != null) {
240a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    mCallback.onPlaylistChanged();
241a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
2425d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik                publishState(STATE_PLAYING);
243a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
244a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
245a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
246a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onError(String error, int code, Bundle data) {
247a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logError("resume: failed", error, code);
248a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
249a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        });
250a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
251a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
252a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
253a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public void stop() {
254a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (!mClient.hasSession()) {
255a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            // ignore if no session
256a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            return;
257a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
2585d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik        publishState(STATE_IDLE);
259a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (DEBUG) {
260a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.d(TAG, "stop");
261a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
262a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mClient.stop(null, new SessionActionCallback() {
263a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
264a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus) {
265a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logStatus("stop: succeeded", sessionId, sessionStatus, null, null);
266a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (mClient.isSessionManagementSupported()) {
267a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    endSession();
268a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
269a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (mCallback != null) {
270a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    mCallback.onPlaylistChanged();
271a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
272a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
273a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
274a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
275a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onError(String error, int code, Bundle data) {
276a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logError("stop: failed", error, code);
277a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
278a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        });
279a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
280a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
281a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    // enqueue & remove are only supported if isQueuingSupported() returns true
282a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
283a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public void enqueue(final PlaylistItem item) {
284a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        throwIfQueuingUnsupported();
285a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
286a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (!mClient.hasSession() && !mEnqueuePending) {
287a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            mEnqueuePending = true;
288a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            if (mClient.isSessionManagementSupported()) {
289a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                startSession(item);
290a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            } else {
291a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                enqueueInternal(item);
292a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
293a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        } else if (mEnqueuePending){
294a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            mTempQueue.add(item);
295a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        } else {
296a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            enqueueInternal(item);
297a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
298a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
299a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
300a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
301a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public PlaylistItem remove(String itemId) {
302a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        throwIfNoSession();
303a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        throwIfQueuingUnsupported();
304a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
305a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (DEBUG) {
306a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.d(TAG, "remove: itemId=" + itemId);
307a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
308a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mClient.remove(itemId, null, new ItemActionCallback() {
309a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
310a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus,
311a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    String itemId, MediaItemStatus itemStatus) {
312a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logStatus("remove: succeeded", sessionId, sessionStatus, itemId, itemStatus);
313a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
314a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
315a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
316a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onError(String error, int code, Bundle data) {
317a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logError("remove: failed", error, code);
318a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
319a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        });
320a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
321a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        return null;
322a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
323a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
324a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
32570f3627685b55b2bc1b3f0c17c9c30aa3a7fd062Donghyun Cho    public void takeSnapshot() {
326cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang        mSnapshot = null;
327a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
32870f3627685b55b2bc1b3f0c17c9c30aa3a7fd062Donghyun Cho        Intent intent = new Intent(SampleMediaRouteProvider.ACTION_TAKE_SNAPSHOT);
329a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        intent.addCategory(SampleMediaRouteProvider.CATEGORY_SAMPLE_ROUTE);
330a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
331a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (mRoute != null && mRoute.supportsControlRequest(intent)) {
332a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            ControlRequestCallback callback = new ControlRequestCallback() {
333a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                @Override
334a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                public void onResult(Bundle data) {
335a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    if (DEBUG) {
33670f3627685b55b2bc1b3f0c17c9c30aa3a7fd062Donghyun Cho                        Log.d(TAG, "takeSnapshot: succeeded: data=" + data);
337a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    }
338a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    if (data != null) {
33970f3627685b55b2bc1b3f0c17c9c30aa3a7fd062Donghyun Cho                        mSnapshot = data.getParcelable(SampleMediaRouteProvider.EXTRA_SNAPSHOT);
340a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    }
341a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
342a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
343a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                @Override
344a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                public void onError(String error, Bundle data) {
34570f3627685b55b2bc1b3f0c17c9c30aa3a7fd062Donghyun Cho                    Log.d(TAG, "takeSnapshot: failed: error=" + error + ", data=" + data);
346a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
347a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            };
348a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
349a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            mRoute.sendControlRequest(intent, callback);
350a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
351a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
352a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
353a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
354cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang    public Bitmap getSnapshot() {
355cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang        return mSnapshot;
356a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
357a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
358a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private void enqueueInternal(final PlaylistItem item) {
359a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        throwIfQueuingUnsupported();
360a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
361a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (DEBUG) {
362a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.d(TAG, "enqueue: item=" + item);
363a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
364a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mClient.enqueue(item.getUri(), "video/mp4", null, 0, null, new ItemActionCallback() {
365a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
366a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus,
367a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    String itemId, MediaItemStatus itemStatus) {
368a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logStatus("enqueue: succeeded", sessionId, sessionStatus, itemId, itemStatus);
369a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                item.setRemoteItemId(itemId);
370a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (item.getPosition() > 0) {
371a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    seekInternal(item);
372a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
373a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (item.getState() == MediaItemStatus.PLAYBACK_STATE_PAUSED) {
374a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    pause();
37576d965dc41863b33f887db33d283cb7f1523f60dJae Seo                } else if (item.getState() == MediaItemStatus.PLAYBACK_STATE_PLAYING) {
37676d965dc41863b33f887db33d283cb7f1523f60dJae Seo                    publishState(STATE_PLAYING);
377a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
378a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (mEnqueuePending) {
379a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    mEnqueuePending = false;
380a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    for (PlaylistItem item : mTempQueue) {
381a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                        enqueueInternal(item);
382a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    }
383a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    mTempQueue.clear();
384a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
385a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (mCallback != null) {
386a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    mCallback.onPlaylistChanged();
387a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
388a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
389a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
390a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
391a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onError(String error, int code, Bundle data) {
392a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logError("enqueue: failed", error, code);
393a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (mCallback != null) {
394a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    mCallback.onPlaylistChanged();
395a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
396a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
397a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        });
398a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
399a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
400a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private void seekInternal(final PlaylistItem item) {
401a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        throwIfNoSession();
402a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
403a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (DEBUG) {
404a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.d(TAG, "seek: item=" + item);
405a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
406a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mClient.seek(item.getRemoteItemId(), item.getPosition(), null, new ItemActionCallback() {
407a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang           @Override
408a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang           public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus,
409a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                   String itemId, MediaItemStatus itemStatus) {
410a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang               logStatus("seek: succeeded", sessionId, sessionStatus, itemId, itemStatus);
411a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang               if (mCallback != null) {
412a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                   mCallback.onPlaylistChanged();
413a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang               }
414a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang           }
415a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
416a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang           @Override
417a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang           public void onError(String error, int code, Bundle data) {
418a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang               logError("seek: failed", error, code);
419a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang           }
420a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        });
421a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
422a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
423a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private void startSession(final PlaylistItem item) {
424a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mClient.startSession(null, new SessionActionCallback() {
425a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
426a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus) {
427a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logStatus("startSession: succeeded", sessionId, sessionStatus, null, null);
428a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                enqueueInternal(item);
429a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
430a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
431a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
432a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onError(String error, int code, Bundle data) {
433a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logError("startSession: failed", error, code);
434a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
435a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        });
436a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
437a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
438a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private void endSession() {
439a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mClient.endSession(null, new SessionActionCallback() {
440a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
441a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus) {
442a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logStatus("endSession: succeeded", sessionId, sessionStatus, null, null);
443a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
444a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
445a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
446a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onError(String error, int code, Bundle data) {
447a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                logError("endSession: failed", error, code);
448a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
449a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        });
450a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
451a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
452a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private void logStatus(String message,
453a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            String sessionId, MediaSessionStatus sessionStatus,
454a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            String itemId, MediaItemStatus itemStatus) {
455a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (DEBUG) {
456a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            String result = "";
457a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            if (sessionId != null && sessionStatus != null) {
458a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                result += "sessionId=" + sessionId + ", sessionStatus=" + sessionStatus;
459a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
460a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            if (itemId != null & itemStatus != null) {
461a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                result += (result.isEmpty() ? "" : ", ")
462a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                        + "itemId=" + itemId + ", itemStatus=" + itemStatus;
463a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
464a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.d(TAG, message + ": " + result);
465a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
466a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
467a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
468a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private void logError(String message, String error, int code) {
469a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        Log.d(TAG, message + ": error=" + error + ", code=" + code);
470a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
471a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
472a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private void throwIfNoSession() {
473a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (!mClient.hasSession()) {
474a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            throw new IllegalStateException("Session is invalid");
475a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
476a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
477a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
478a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private void throwIfQueuingUnsupported() {
479a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (!isQueuingSupported()) {
480a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            throw new UnsupportedOperationException("Queuing is unsupported");
481a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
482a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
483a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang}
484