Adding browsable prebuilt samples for march push
Change-Id: I952db10d9c9acb4940db08a07789347ea2effe4d
This commit is contained in:
@@ -0,0 +1,419 @@
|
||||
/*
|
||||
* Copyright (C) 2013 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.example.android.mediarouter.player;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.net.Uri;
|
||||
import android.support.v7.media.MediaItemStatus;
|
||||
import android.support.v7.media.MediaSessionStatus;
|
||||
import android.util.Log;
|
||||
|
||||
import com.example.android.mediarouter.player.Player.Callback;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* SessionManager manages a media session as a queue. It supports common
|
||||
* queuing behaviors such as enqueue/remove of media items, pause/resume/stop,
|
||||
* etc.
|
||||
*
|
||||
* Actual playback of a single media item is abstracted into a Player interface,
|
||||
* and is handled outside this class.
|
||||
*/
|
||||
public class SessionManager implements Callback {
|
||||
private static final String TAG = "SessionManager";
|
||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||
|
||||
private String mName;
|
||||
private int mSessionId;
|
||||
private int mItemId;
|
||||
private boolean mPaused;
|
||||
private boolean mSessionValid;
|
||||
private Player mPlayer;
|
||||
private Callback mCallback;
|
||||
private List<PlaylistItem> mPlaylist = new ArrayList<PlaylistItem>();
|
||||
|
||||
public SessionManager(String name) {
|
||||
mName = name;
|
||||
}
|
||||
|
||||
public boolean hasSession() {
|
||||
return mSessionValid;
|
||||
}
|
||||
|
||||
public String getSessionId() {
|
||||
return mSessionValid ? Integer.toString(mSessionId) : null;
|
||||
}
|
||||
|
||||
public PlaylistItem getCurrentItem() {
|
||||
return mPlaylist.isEmpty() ? null : mPlaylist.get(0);
|
||||
}
|
||||
|
||||
// Get the cached statistic info from the player (will not update it)
|
||||
public String getStatistics() {
|
||||
checkPlayer();
|
||||
return mPlayer.getStatistics();
|
||||
}
|
||||
|
||||
// Returns the cached playlist (note this is not responsible for updating it)
|
||||
public List<PlaylistItem> getPlaylist() {
|
||||
return mPlaylist;
|
||||
}
|
||||
|
||||
// Updates the playlist asynchronously, calls onPlaylistReady() when finished.
|
||||
public void updateStatus() {
|
||||
if (DEBUG) {
|
||||
log("updateStatus");
|
||||
}
|
||||
checkPlayer();
|
||||
// update the statistics first, so that the stats string is valid when
|
||||
// onPlaylistReady() gets called in the end
|
||||
mPlayer.updateStatistics();
|
||||
|
||||
if (mPlaylist.isEmpty()) {
|
||||
// If queue is empty, don't forget to call onPlaylistReady()!
|
||||
onPlaylistReady();
|
||||
} else if (mPlayer.isQueuingSupported()) {
|
||||
// If player supports queuing, get status of each item. Player is
|
||||
// responsible to call onPlaylistReady() after last getStatus().
|
||||
// (update=1 requires player to callback onPlaylistReady())
|
||||
for (int i = 0; i < mPlaylist.size(); i++) {
|
||||
PlaylistItem item = mPlaylist.get(i);
|
||||
mPlayer.getStatus(item, (i == mPlaylist.size() - 1) /* update */);
|
||||
}
|
||||
} else {
|
||||
// Otherwise, only need to get status for current item. Player is
|
||||
// responsible to call onPlaylistReady() when finished.
|
||||
mPlayer.getStatus(getCurrentItem(), true /* update */);
|
||||
}
|
||||
}
|
||||
|
||||
public PlaylistItem add(Uri uri, String mime) {
|
||||
return add(uri, mime, null);
|
||||
}
|
||||
|
||||
public PlaylistItem add(Uri uri, String mime, PendingIntent receiver) {
|
||||
if (DEBUG) {
|
||||
log("add: uri=" + uri + ", receiver=" + receiver);
|
||||
}
|
||||
// create new session if needed
|
||||
startSession();
|
||||
checkPlayerAndSession();
|
||||
|
||||
// append new item with initial status PLAYBACK_STATE_PENDING
|
||||
PlaylistItem item = new PlaylistItem(
|
||||
Integer.toString(mSessionId), Integer.toString(mItemId), uri, mime, receiver);
|
||||
mPlaylist.add(item);
|
||||
mItemId++;
|
||||
|
||||
// if player supports queuing, enqueue the item now
|
||||
if (mPlayer.isQueuingSupported()) {
|
||||
mPlayer.enqueue(item);
|
||||
}
|
||||
updatePlaybackState();
|
||||
return item;
|
||||
}
|
||||
|
||||
public PlaylistItem remove(String iid) {
|
||||
if (DEBUG) {
|
||||
log("remove: iid=" + iid);
|
||||
}
|
||||
checkPlayerAndSession();
|
||||
return removeItem(iid, MediaItemStatus.PLAYBACK_STATE_CANCELED);
|
||||
}
|
||||
|
||||
public PlaylistItem seek(String iid, long pos) {
|
||||
if (DEBUG) {
|
||||
log("seek: iid=" + iid +", pos=" + pos);
|
||||
}
|
||||
checkPlayerAndSession();
|
||||
// seeking on pending items are not yet supported
|
||||
checkItemCurrent(iid);
|
||||
|
||||
PlaylistItem item = getCurrentItem();
|
||||
if (pos != item.getPosition()) {
|
||||
item.setPosition(pos);
|
||||
if (item.getState() == MediaItemStatus.PLAYBACK_STATE_PLAYING
|
||||
|| item.getState() == MediaItemStatus.PLAYBACK_STATE_PAUSED) {
|
||||
mPlayer.seek(item);
|
||||
}
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
public PlaylistItem getStatus(String iid) {
|
||||
checkPlayerAndSession();
|
||||
|
||||
// This should only be called for local player. Remote player is
|
||||
// asynchronous, need to use updateStatus() instead.
|
||||
if (mPlayer.isRemotePlayback()) {
|
||||
throw new IllegalStateException(
|
||||
"getStatus should not be called on remote player!");
|
||||
}
|
||||
|
||||
for (PlaylistItem item : mPlaylist) {
|
||||
if (item.getItemId().equals(iid)) {
|
||||
if (item == getCurrentItem()) {
|
||||
mPlayer.getStatus(item, false);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void pause() {
|
||||
if (DEBUG) {
|
||||
log("pause");
|
||||
}
|
||||
mPaused = true;
|
||||
updatePlaybackState();
|
||||
}
|
||||
|
||||
public void resume() {
|
||||
if (DEBUG) {
|
||||
log("resume");
|
||||
}
|
||||
mPaused = false;
|
||||
updatePlaybackState();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (DEBUG) {
|
||||
log("stop");
|
||||
}
|
||||
mPlayer.stop();
|
||||
mPlaylist.clear();
|
||||
mPaused = false;
|
||||
updateStatus();
|
||||
}
|
||||
|
||||
public String startSession() {
|
||||
if (!mSessionValid) {
|
||||
mSessionId++;
|
||||
mItemId = 0;
|
||||
mPaused = false;
|
||||
mSessionValid = true;
|
||||
return Integer.toString(mSessionId);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean endSession() {
|
||||
if (mSessionValid) {
|
||||
mSessionValid = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public MediaSessionStatus getSessionStatus(String sid) {
|
||||
int sessionState = (sid != null && sid.equals(mSessionId)) ?
|
||||
MediaSessionStatus.SESSION_STATE_ACTIVE :
|
||||
MediaSessionStatus.SESSION_STATE_INVALIDATED;
|
||||
|
||||
return new MediaSessionStatus.Builder(sessionState)
|
||||
.setQueuePaused(mPaused)
|
||||
.build();
|
||||
}
|
||||
|
||||
// Suspend the playback manager. Put the current item back into PENDING
|
||||
// state, and remember the current playback position. Called when switching
|
||||
// to a different player (route).
|
||||
public void suspend(long pos) {
|
||||
for (PlaylistItem item : mPlaylist) {
|
||||
item.setRemoteItemId(null);
|
||||
item.setDuration(0);
|
||||
}
|
||||
PlaylistItem item = getCurrentItem();
|
||||
if (DEBUG) {
|
||||
log("suspend: item=" + item + ", pos=" + pos);
|
||||
}
|
||||
if (item != null) {
|
||||
if (item.getState() == MediaItemStatus.PLAYBACK_STATE_PLAYING
|
||||
|| item.getState() == MediaItemStatus.PLAYBACK_STATE_PAUSED) {
|
||||
item.setState(MediaItemStatus.PLAYBACK_STATE_PENDING);
|
||||
item.setPosition(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unsuspend the playback manager. Restart playback on new player (route).
|
||||
// This will resume playback of current item. Furthermore, if the new player
|
||||
// supports queuing, playlist will be re-established on the remote player.
|
||||
public void unsuspend() {
|
||||
if (DEBUG) {
|
||||
log("unsuspend");
|
||||
}
|
||||
if (mPlayer.isQueuingSupported()) {
|
||||
for (PlaylistItem item : mPlaylist) {
|
||||
mPlayer.enqueue(item);
|
||||
}
|
||||
}
|
||||
updatePlaybackState();
|
||||
}
|
||||
|
||||
// Player.Callback
|
||||
@Override
|
||||
public void onError() {
|
||||
finishItem(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCompletion() {
|
||||
finishItem(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlaylistChanged() {
|
||||
// Playlist has changed, update the cached playlist
|
||||
updateStatus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlaylistReady() {
|
||||
// Notify activity to update Ui
|
||||
if (mCallback != null) {
|
||||
mCallback.onStatusChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void log(String message) {
|
||||
Log.d(TAG, mName + ": " + message);
|
||||
}
|
||||
|
||||
private void checkPlayer() {
|
||||
if (mPlayer == null) {
|
||||
throw new IllegalStateException("Player not set!");
|
||||
}
|
||||
}
|
||||
|
||||
private void checkSession() {
|
||||
if (!mSessionValid) {
|
||||
throw new IllegalStateException("Session not set!");
|
||||
}
|
||||
}
|
||||
|
||||
private void checkPlayerAndSession() {
|
||||
checkPlayer();
|
||||
checkSession();
|
||||
}
|
||||
|
||||
private void checkItemCurrent(String iid) {
|
||||
PlaylistItem item = getCurrentItem();
|
||||
if (item == null || !item.getItemId().equals(iid)) {
|
||||
throw new IllegalArgumentException("Item is not current!");
|
||||
}
|
||||
}
|
||||
|
||||
private void updatePlaybackState() {
|
||||
PlaylistItem item = getCurrentItem();
|
||||
if (item != null) {
|
||||
if (item.getState() == MediaItemStatus.PLAYBACK_STATE_PENDING) {
|
||||
item.setState(mPaused ? MediaItemStatus.PLAYBACK_STATE_PAUSED
|
||||
: MediaItemStatus.PLAYBACK_STATE_PLAYING);
|
||||
if (!mPlayer.isQueuingSupported()) {
|
||||
mPlayer.play(item);
|
||||
}
|
||||
} else if (mPaused && item.getState() == MediaItemStatus.PLAYBACK_STATE_PLAYING) {
|
||||
mPlayer.pause();
|
||||
item.setState(MediaItemStatus.PLAYBACK_STATE_PAUSED);
|
||||
} else if (!mPaused && item.getState() == MediaItemStatus.PLAYBACK_STATE_PAUSED) {
|
||||
mPlayer.resume();
|
||||
item.setState(MediaItemStatus.PLAYBACK_STATE_PLAYING);
|
||||
}
|
||||
// notify client that item playback status has changed
|
||||
if (mCallback != null) {
|
||||
mCallback.onItemChanged(item);
|
||||
}
|
||||
}
|
||||
updateStatus();
|
||||
}
|
||||
|
||||
private PlaylistItem removeItem(String iid, int state) {
|
||||
checkPlayerAndSession();
|
||||
List<PlaylistItem> queue =
|
||||
new ArrayList<PlaylistItem>(mPlaylist.size());
|
||||
PlaylistItem found = null;
|
||||
for (PlaylistItem item : mPlaylist) {
|
||||
if (iid.equals(item.getItemId())) {
|
||||
if (mPlayer.isQueuingSupported()) {
|
||||
mPlayer.remove(item.getRemoteItemId());
|
||||
} else if (item.getState() == MediaItemStatus.PLAYBACK_STATE_PLAYING
|
||||
|| item.getState() == MediaItemStatus.PLAYBACK_STATE_PAUSED){
|
||||
mPlayer.stop();
|
||||
}
|
||||
item.setState(state);
|
||||
found = item;
|
||||
// notify client that item is now removed
|
||||
if (mCallback != null) {
|
||||
mCallback.onItemChanged(found);
|
||||
}
|
||||
} else {
|
||||
queue.add(item);
|
||||
}
|
||||
}
|
||||
if (found != null) {
|
||||
mPlaylist = queue;
|
||||
updatePlaybackState();
|
||||
} else {
|
||||
log("item not found");
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
private void finishItem(boolean error) {
|
||||
PlaylistItem item = getCurrentItem();
|
||||
if (item != null) {
|
||||
removeItem(item.getItemId(), error ?
|
||||
MediaItemStatus.PLAYBACK_STATE_ERROR :
|
||||
MediaItemStatus.PLAYBACK_STATE_FINISHED);
|
||||
updateStatus();
|
||||
}
|
||||
}
|
||||
|
||||
// set the Player that this playback manager will interact with
|
||||
public void setPlayer(Player player) {
|
||||
mPlayer = player;
|
||||
checkPlayer();
|
||||
mPlayer.setCallback(this);
|
||||
}
|
||||
|
||||
// provide a callback interface to tell the UI when significant state changes occur
|
||||
public void setCallback(Callback callback) {
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String result = "Media Queue: ";
|
||||
if (!mPlaylist.isEmpty()) {
|
||||
for (PlaylistItem item : mPlaylist) {
|
||||
result += "\n" + item.toString();
|
||||
}
|
||||
} else {
|
||||
result += "<empty>";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public interface Callback {
|
||||
void onStatusChanged();
|
||||
void onItemChanged(PlaylistItem item);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user