Player.java revision 76d965dc41863b33f887db33d283cb7f1523f60d
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.content.Context;
20import android.graphics.Bitmap;
21import android.support.v4.media.MediaMetadataCompat;
22import android.support.v4.media.session.MediaSessionCompat;
23import android.support.v4.media.session.PlaybackStateCompat;
24import android.support.v7.media.MediaControlIntent;
25import android.support.v7.media.MediaRouter.RouteInfo;
26import android.util.Log;
27
28/**
29 * Abstraction of common playback operations of media items, such as play,
30 * seek, etc. Used by PlaybackManager as a backend to handle actual playback
31 * of media items.
32 *
33 * TODO: Introduce prepare() method and refactor subclasses accordingly.
34 */
35public abstract class Player {
36    private static final String TAG = "SampleMediaRoutePlayer";
37    protected static final int STATE_IDLE = 0;
38    protected static final int STATE_PREPARING_FOR_PLAY = 1;
39    protected static final int STATE_PREPARING_FOR_PAUSE = 2;
40    protected static final int STATE_READY = 3;
41    protected static final int STATE_PLAYING = 4;
42    protected static final int STATE_PAUSED = 5;
43
44    private static final long PLAYBACK_ACTIONS = PlaybackStateCompat.ACTION_PAUSE
45            | PlaybackStateCompat.ACTION_PLAY;
46    private static final PlaybackStateCompat INIT_PLAYBACK_STATE = new PlaybackStateCompat.Builder()
47            .setState(PlaybackStateCompat.STATE_NONE, 0, .0f).build();
48
49    protected Callback mCallback;
50    protected MediaSessionCompat mMediaSession;
51
52    public abstract boolean isRemotePlayback();
53    public abstract boolean isQueuingSupported();
54
55    public abstract void connect(RouteInfo route);
56    public abstract void release();
57
58    // basic operations that are always supported
59    public abstract void play(final PlaylistItem item);
60    public abstract void seek(final PlaylistItem item);
61    public abstract void getStatus(final PlaylistItem item, final boolean update);
62    public abstract void pause();
63    public abstract void resume();
64    public abstract void stop();
65
66    // advanced queuing (enqueue & remove) are only supported
67    // if isQueuingSupported() returns true
68    public abstract void enqueue(final PlaylistItem item);
69    public abstract PlaylistItem remove(String iid);
70
71    // track info for current media item
72    public void updateTrackInfo() {}
73    public String getDescription() { return ""; }
74    public Bitmap getSnapshot() { return null; }
75
76    // presentation display
77    public void updatePresentation() {}
78
79    public void setCallback(Callback callback) {
80        mCallback = callback;
81    }
82
83    public static Player create(Context context, RouteInfo route, MediaSessionCompat session) {
84        Player player;
85        if (route != null && route.supportsControlCategory(
86                MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) {
87            player = new RemotePlayer(context);
88        } else if (route != null) {
89            player = new LocalPlayer.SurfaceViewPlayer(context);
90        } else {
91            player = new LocalPlayer.OverlayPlayer(context);
92        }
93        player.setMediaSession(session);
94        player.initMediaSession();
95        player.connect(route);
96        return player;
97    }
98
99    protected void initMediaSession() {
100        if (mMediaSession == null) {
101            return;
102        }
103        mMediaSession.setMetadata(null);
104        mMediaSession.setPlaybackState(INIT_PLAYBACK_STATE);
105    }
106
107    protected void updateMetadata() {
108        if (mMediaSession == null) {
109            return;
110        }
111        MediaMetadataCompat.Builder bob = new MediaMetadataCompat.Builder();
112        bob.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, getDescription());
113        bob.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, "Subtitle of the thing");
114        bob.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_DESCRIPTION,
115                "Description of the thing");
116        bob.putBitmap(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, getSnapshot());
117        mMediaSession.setMetadata(bob.build());
118    }
119
120    protected void publishState(int state) {
121        if (mMediaSession == null) {
122            return;
123        }
124        PlaybackStateCompat.Builder bob = new PlaybackStateCompat.Builder();
125        bob.setActions(PLAYBACK_ACTIONS);
126        switch (state) {
127            case STATE_PLAYING:
128                bob.setState(PlaybackStateCompat.STATE_PLAYING, -1, 1);
129                break;
130            case STATE_READY:
131            case STATE_PAUSED:
132                bob.setState(PlaybackStateCompat.STATE_PAUSED, -1, 0);
133                break;
134            case STATE_IDLE:
135                bob.setState(PlaybackStateCompat.STATE_STOPPED, -1, 0);
136                break;
137        }
138        PlaybackStateCompat pbState = bob.build();
139        Log.d(TAG, "Setting state to " + pbState);
140        mMediaSession.setPlaybackState(pbState);
141        if (state != STATE_IDLE) {
142            mMediaSession.setActive(true);
143        } else {
144            mMediaSession.setActive(false);
145        }
146    }
147
148    private void setMediaSession(MediaSessionCompat session) {
149        mMediaSession = session;
150    }
151
152    public interface Callback {
153        void onError();
154        void onCompletion();
155        void onPlaylistChanged();
156        void onPlaylistReady();
157    }
158}
159