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 1961636870e0a12db5909955eca58e0070357dde42Donghyun Choimport android.annotation.TargetApi; 20a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.content.Context; 21cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhangimport android.graphics.Bitmap; 2261636870e0a12db5909955eca58e0070357dde42Donghyun Choimport android.os.Build; 235d429bc3a8195d6f37cf2f7da0935972950539b4RoboErikimport android.support.v4.media.MediaMetadataCompat; 245d429bc3a8195d6f37cf2f7da0935972950539b4RoboErikimport android.support.v4.media.session.MediaSessionCompat; 255d429bc3a8195d6f37cf2f7da0935972950539b4RoboErikimport android.support.v4.media.session.PlaybackStateCompat; 26a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.support.v7.media.MediaControlIntent; 27a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.support.v7.media.MediaRouter.RouteInfo; 285d429bc3a8195d6f37cf2f7da0935972950539b4RoboErikimport android.util.Log; 29a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang 30a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang/** 31a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang * Abstraction of common playback operations of media items, such as play, 32a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang * seek, etc. Used by PlaybackManager as a backend to handle actual playback 33a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang * of media items. 3476d965dc41863b33f887db33d283cb7f1523f60dJae Seo * 3576d965dc41863b33f887db33d283cb7f1523f60dJae Seo * TODO: Introduce prepare() method and refactor subclasses accordingly. 36a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang */ 37a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangpublic abstract class Player { 385d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik private static final String TAG = "SampleMediaRoutePlayer"; 3970f3627685b55b2bc1b3f0c17c9c30aa3a7fd062Donghyun Cho private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 405d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik protected static final int STATE_IDLE = 0; 4176d965dc41863b33f887db33d283cb7f1523f60dJae Seo protected static final int STATE_PREPARING_FOR_PLAY = 1; 4276d965dc41863b33f887db33d283cb7f1523f60dJae Seo protected static final int STATE_PREPARING_FOR_PAUSE = 2; 4376d965dc41863b33f887db33d283cb7f1523f60dJae Seo protected static final int STATE_READY = 3; 4476d965dc41863b33f887db33d283cb7f1523f60dJae Seo protected static final int STATE_PLAYING = 4; 4576d965dc41863b33f887db33d283cb7f1523f60dJae Seo protected static final int STATE_PAUSED = 5; 465d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik 475d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik private static final long PLAYBACK_ACTIONS = PlaybackStateCompat.ACTION_PAUSE 485d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik | PlaybackStateCompat.ACTION_PLAY; 4976d965dc41863b33f887db33d283cb7f1523f60dJae Seo private static final PlaybackStateCompat INIT_PLAYBACK_STATE = new PlaybackStateCompat.Builder() 5076d965dc41863b33f887db33d283cb7f1523f60dJae Seo .setState(PlaybackStateCompat.STATE_NONE, 0, .0f).build(); 515d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik 52a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang protected Callback mCallback; 535d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik protected MediaSessionCompat mMediaSession; 54a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang 55a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang public abstract boolean isRemotePlayback(); 56a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang public abstract boolean isQueuingSupported(); 57a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang 58a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang public abstract void connect(RouteInfo route); 59a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang public abstract void release(); 60a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang 61a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang // basic operations that are always supported 62a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang public abstract void play(final PlaylistItem item); 63a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang public abstract void seek(final PlaylistItem item); 64a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang public abstract void getStatus(final PlaylistItem item, final boolean update); 65a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang public abstract void pause(); 66a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang public abstract void resume(); 67a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang public abstract void stop(); 68a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang 69a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang // advanced queuing (enqueue & remove) are only supported 70a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang // if isQueuingSupported() returns true 71a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang public abstract void enqueue(final PlaylistItem item); 72a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang public abstract PlaylistItem remove(String iid); 73a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang 7470f3627685b55b2bc1b3f0c17c9c30aa3a7fd062Donghyun Cho public void takeSnapshot() {} 75cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang public Bitmap getSnapshot() { return null; } 76a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang 7761636870e0a12db5909955eca58e0070357dde42Donghyun Cho /** 7861636870e0a12db5909955eca58e0070357dde42Donghyun Cho * presentation display 7961636870e0a12db5909955eca58e0070357dde42Donghyun Cho */ 8061636870e0a12db5909955eca58e0070357dde42Donghyun Cho @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) 81a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang public void updatePresentation() {} 82a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang 83a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang public void setCallback(Callback callback) { 84a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang mCallback = callback; 85a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang } 86a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang 879a2de97bec8126f8c8c05e9c995f378c5a73319aRoboErik public static Player create(Context context, RouteInfo route, MediaSessionCompat session) { 88a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang Player player; 89a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang if (route != null && route.supportsControlCategory( 90a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) { 91a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang player = new RemotePlayer(context); 92a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang } else if (route != null) { 93a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang player = new LocalPlayer.SurfaceViewPlayer(context); 94a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang } else { 95a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang player = new LocalPlayer.OverlayPlayer(context); 96a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang } 9776d965dc41863b33f887db33d283cb7f1523f60dJae Seo player.setMediaSession(session); 9876d965dc41863b33f887db33d283cb7f1523f60dJae Seo player.initMediaSession(); 99a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang player.connect(route); 100a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang return player; 101a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang } 102a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang 10376d965dc41863b33f887db33d283cb7f1523f60dJae Seo protected void initMediaSession() { 10476d965dc41863b33f887db33d283cb7f1523f60dJae Seo if (mMediaSession == null) { 10576d965dc41863b33f887db33d283cb7f1523f60dJae Seo return; 10676d965dc41863b33f887db33d283cb7f1523f60dJae Seo } 10776d965dc41863b33f887db33d283cb7f1523f60dJae Seo mMediaSession.setMetadata(null); 10876d965dc41863b33f887db33d283cb7f1523f60dJae Seo mMediaSession.setPlaybackState(INIT_PLAYBACK_STATE); 1095d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik } 1105d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik 11170f3627685b55b2bc1b3f0c17c9c30aa3a7fd062Donghyun Cho protected void updateMetadata(PlaylistItem currentItem) { 1129a2de97bec8126f8c8c05e9c995f378c5a73319aRoboErik if (mMediaSession == null) { 1139a2de97bec8126f8c8c05e9c995f378c5a73319aRoboErik return; 1149a2de97bec8126f8c8c05e9c995f378c5a73319aRoboErik } 11570f3627685b55b2bc1b3f0c17c9c30aa3a7fd062Donghyun Cho if (DEBUG) { 11670f3627685b55b2bc1b3f0c17c9c30aa3a7fd062Donghyun Cho Log.d(TAG, "Update metadata: currentItem=" + currentItem); 11770f3627685b55b2bc1b3f0c17c9c30aa3a7fd062Donghyun Cho } 11870f3627685b55b2bc1b3f0c17c9c30aa3a7fd062Donghyun Cho if (currentItem == null) { 11970f3627685b55b2bc1b3f0c17c9c30aa3a7fd062Donghyun Cho mMediaSession.setMetadata(null); 12070f3627685b55b2bc1b3f0c17c9c30aa3a7fd062Donghyun Cho return; 12170f3627685b55b2bc1b3f0c17c9c30aa3a7fd062Donghyun Cho } 1225d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik MediaMetadataCompat.Builder bob = new MediaMetadataCompat.Builder(); 12370f3627685b55b2bc1b3f0c17c9c30aa3a7fd062Donghyun Cho bob.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, currentItem.getTitle()); 1245d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik bob.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, "Subtitle of the thing"); 1255d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik bob.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_DESCRIPTION, 1265d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik "Description of the thing"); 1275d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik bob.putBitmap(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, getSnapshot()); 1285d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik mMediaSession.setMetadata(bob.build()); 1295d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik } 1305d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik 1315d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik protected void publishState(int state) { 1329a2de97bec8126f8c8c05e9c995f378c5a73319aRoboErik if (mMediaSession == null) { 1339a2de97bec8126f8c8c05e9c995f378c5a73319aRoboErik return; 1349a2de97bec8126f8c8c05e9c995f378c5a73319aRoboErik } 1355d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik PlaybackStateCompat.Builder bob = new PlaybackStateCompat.Builder(); 1365d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik bob.setActions(PLAYBACK_ACTIONS); 1375d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik switch (state) { 1385d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik case STATE_PLAYING: 1395d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik bob.setState(PlaybackStateCompat.STATE_PLAYING, -1, 1); 1405d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik break; 1415d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik case STATE_READY: 1425d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik case STATE_PAUSED: 1435d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik bob.setState(PlaybackStateCompat.STATE_PAUSED, -1, 0); 1445d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik break; 14570f3627685b55b2bc1b3f0c17c9c30aa3a7fd062Donghyun Cho case STATE_PREPARING_FOR_PLAY: 14670f3627685b55b2bc1b3f0c17c9c30aa3a7fd062Donghyun Cho case STATE_PREPARING_FOR_PAUSE: 14770f3627685b55b2bc1b3f0c17c9c30aa3a7fd062Donghyun Cho bob.setState(PlaybackStateCompat.STATE_BUFFERING, -1, 0); 14870f3627685b55b2bc1b3f0c17c9c30aa3a7fd062Donghyun Cho break; 1495d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik case STATE_IDLE: 1505d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik bob.setState(PlaybackStateCompat.STATE_STOPPED, -1, 0); 1515d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik break; 1525d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik } 1535d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik PlaybackStateCompat pbState = bob.build(); 1545d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik Log.d(TAG, "Setting state to " + pbState); 1555d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik mMediaSession.setPlaybackState(pbState); 1565d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik if (state != STATE_IDLE) { 1575d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik mMediaSession.setActive(true); 1585d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik } else { 1595d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik mMediaSession.setActive(false); 1605d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik } 1615d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik } 1625d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik 16376d965dc41863b33f887db33d283cb7f1523f60dJae Seo private void setMediaSession(MediaSessionCompat session) { 1649a2de97bec8126f8c8c05e9c995f378c5a73319aRoboErik mMediaSession = session; 1655d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik } 1665d429bc3a8195d6f37cf2f7da0935972950539b4RoboErik 167a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang public interface Callback { 168a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang void onError(); 169a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang void onCompletion(); 170a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang void onPlaylistChanged(); 171a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang void onPlaylistReady(); 172a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang } 17376d965dc41863b33f887db33d283cb7f1523f60dJae Seo} 174