| /* |
| * 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.supportv7.media; |
| |
| import android.annotation.TargetApi; |
| import android.content.Context; |
| import android.graphics.Bitmap; |
| import android.os.Build; |
| import android.support.v4.media.MediaMetadataCompat; |
| import android.support.v4.media.session.MediaSessionCompat; |
| import android.support.v4.media.session.PlaybackStateCompat; |
| import android.support.v7.media.MediaControlIntent; |
| import android.support.v7.media.MediaRouter.RouteInfo; |
| import android.util.Log; |
| |
| /** |
| * Abstraction of common playback operations of media items, such as play, |
| * seek, etc. Used by PlaybackManager as a backend to handle actual playback |
| * of media items. |
| * |
| * TODO: Introduce prepare() method and refactor subclasses accordingly. |
| */ |
| public abstract class Player { |
| private static final String TAG = "SampleMediaRoutePlayer"; |
| private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); |
| protected static final int STATE_IDLE = 0; |
| protected static final int STATE_PREPARING_FOR_PLAY = 1; |
| protected static final int STATE_PREPARING_FOR_PAUSE = 2; |
| protected static final int STATE_READY = 3; |
| protected static final int STATE_PLAYING = 4; |
| protected static final int STATE_PAUSED = 5; |
| |
| private static final long PLAYBACK_ACTIONS = PlaybackStateCompat.ACTION_PAUSE |
| | PlaybackStateCompat.ACTION_PLAY; |
| private static final PlaybackStateCompat INIT_PLAYBACK_STATE = new PlaybackStateCompat.Builder() |
| .setState(PlaybackStateCompat.STATE_NONE, 0, .0f).build(); |
| |
| protected Callback mCallback; |
| protected MediaSessionCompat mMediaSession; |
| |
| public abstract boolean isRemotePlayback(); |
| public abstract boolean isQueuingSupported(); |
| |
| public abstract void connect(RouteInfo route); |
| public abstract void release(); |
| |
| // basic operations that are always supported |
| public abstract void play(final PlaylistItem item); |
| public abstract void seek(final PlaylistItem item); |
| public abstract void getStatus(final PlaylistItem item, final boolean update); |
| public abstract void pause(); |
| public abstract void resume(); |
| public abstract void stop(); |
| |
| // advanced queuing (enqueue & remove) are only supported |
| // if isQueuingSupported() returns true |
| public abstract void enqueue(final PlaylistItem item); |
| public abstract PlaylistItem remove(String iid); |
| |
| public void takeSnapshot() {} |
| public Bitmap getSnapshot() { return null; } |
| |
| /** |
| * presentation display |
| */ |
| @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) |
| public void updatePresentation() {} |
| |
| public void setCallback(Callback callback) { |
| mCallback = callback; |
| } |
| |
| public static Player create(Context context, RouteInfo route, MediaSessionCompat session) { |
| Player player; |
| if (route != null && route.supportsControlCategory( |
| MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) { |
| player = new RemotePlayer(context); |
| } else if (route != null) { |
| player = new LocalPlayer.SurfaceViewPlayer(context); |
| } else { |
| player = new LocalPlayer.OverlayPlayer(context); |
| } |
| player.setMediaSession(session); |
| player.initMediaSession(); |
| player.connect(route); |
| return player; |
| } |
| |
| protected void initMediaSession() { |
| if (mMediaSession == null) { |
| return; |
| } |
| mMediaSession.setMetadata(null); |
| mMediaSession.setPlaybackState(INIT_PLAYBACK_STATE); |
| } |
| |
| protected void updateMetadata(PlaylistItem currentItem) { |
| if (mMediaSession == null) { |
| return; |
| } |
| if (DEBUG) { |
| Log.d(TAG, "Update metadata: currentItem=" + currentItem); |
| } |
| if (currentItem == null) { |
| mMediaSession.setMetadata(null); |
| return; |
| } |
| MediaMetadataCompat.Builder bob = new MediaMetadataCompat.Builder(); |
| bob.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, currentItem.getTitle()); |
| bob.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, "Subtitle of the thing"); |
| bob.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_DESCRIPTION, |
| "Description of the thing"); |
| bob.putBitmap(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, getSnapshot()); |
| mMediaSession.setMetadata(bob.build()); |
| } |
| |
| protected void publishState(int state) { |
| if (mMediaSession == null) { |
| return; |
| } |
| PlaybackStateCompat.Builder bob = new PlaybackStateCompat.Builder(); |
| bob.setActions(PLAYBACK_ACTIONS); |
| switch (state) { |
| case STATE_PLAYING: |
| bob.setState(PlaybackStateCompat.STATE_PLAYING, -1, 1); |
| break; |
| case STATE_READY: |
| case STATE_PAUSED: |
| bob.setState(PlaybackStateCompat.STATE_PAUSED, -1, 0); |
| break; |
| case STATE_PREPARING_FOR_PLAY: |
| case STATE_PREPARING_FOR_PAUSE: |
| bob.setState(PlaybackStateCompat.STATE_BUFFERING, -1, 0); |
| break; |
| case STATE_IDLE: |
| bob.setState(PlaybackStateCompat.STATE_STOPPED, -1, 0); |
| break; |
| } |
| PlaybackStateCompat pbState = bob.build(); |
| Log.d(TAG, "Setting state to " + pbState); |
| mMediaSession.setPlaybackState(pbState); |
| if (state != STATE_IDLE) { |
| mMediaSession.setActive(true); |
| } else { |
| mMediaSession.setActive(false); |
| } |
| } |
| |
| private void setMediaSession(MediaSessionCompat session) { |
| mMediaSession = session; |
| } |
| |
| public interface Callback { |
| void onError(); |
| void onCompletion(); |
| void onPlaylistChanged(); |
| void onPlaylistReady(); |
| } |
| } |