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.app.Activity;
21a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.app.Presentation;
22a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.content.Context;
23a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.content.DialogInterface;
24cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhangimport android.graphics.Bitmap;
25a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.media.MediaPlayer;
26a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.os.Build;
27a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.os.Bundle;
28a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.os.Handler;
29a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.os.SystemClock;
30a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.support.v7.media.MediaItemStatus;
3161636870e0a12db5909955eca58e0070357dde42Donghyun Choimport android.support.v7.media.MediaRouter.RouteInfo;
32a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.util.Log;
33a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.view.Display;
34a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.view.Gravity;
35a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.view.Surface;
36a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.view.SurfaceHolder;
37a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.view.SurfaceView;
38a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.view.View;
39a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.view.ViewGroup;
40a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.view.WindowManager;
41a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport android.widget.FrameLayout;
42a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
43a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport com.example.android.supportv7.R;
44a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
45a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangimport java.io.IOException;
46a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
47a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang/**
48a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang * Handles playback of a single media item using MediaPlayer.
49a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang */
50a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhangpublic abstract class LocalPlayer extends Player implements
51a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        MediaPlayer.OnPreparedListener,
52a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        MediaPlayer.OnCompletionListener,
53a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        MediaPlayer.OnErrorListener,
54a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        MediaPlayer.OnSeekCompleteListener {
55a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private static final String TAG = "LocalPlayer";
56a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
57a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
58a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private final Context mContext;
59a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private final Handler mHandler = new Handler();
6076d965dc41863b33f887db33d283cb7f1523f60dJae Seo    private final Handler mUpdateSurfaceHandler = new Handler(mHandler.getLooper());
61a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private MediaPlayer mMediaPlayer;
62a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private int mState = STATE_IDLE;
63a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private int mSeekToPos;
64a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private int mVideoWidth;
65a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private int mVideoHeight;
66a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private Surface mSurface;
67a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private SurfaceHolder mSurfaceHolder;
68a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
69a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public LocalPlayer(Context context) {
70a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mContext = context;
71a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
72a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        // reset media player
73a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        reset();
74a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
75a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
76a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
77a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public boolean isRemotePlayback() {
78a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        return false;
79a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
80a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
81a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
82a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public boolean isQueuingSupported() {
83a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        return false;
84a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
85a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
86a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
87a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public void connect(RouteInfo route) {
88a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (DEBUG) {
89a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.d(TAG, "connecting to: " + route);
90a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
91a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
92a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
93a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
94a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public void release() {
95a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (DEBUG) {
96a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.d(TAG, "releasing");
97a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
98a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        // release media player
99a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (mMediaPlayer != null) {
100a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            mMediaPlayer.stop();
101a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            mMediaPlayer.release();
102a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            mMediaPlayer = null;
103a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
104a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
105a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
106a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    // Player
107a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
108a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public void play(final PlaylistItem item) {
109a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (DEBUG) {
110a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.d(TAG, "play: item=" + item);
111a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
112a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        reset();
113a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mSeekToPos = (int)item.getPosition();
114a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        try {
115a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            mMediaPlayer.setDataSource(mContext, item.getUri());
116a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            mMediaPlayer.prepareAsync();
117a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        } catch (IllegalStateException e) {
118a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.e(TAG, "MediaPlayer throws IllegalStateException, uri=" + item.getUri());
119a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        } catch (IOException e) {
120a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.e(TAG, "MediaPlayer throws IOException, uri=" + item.getUri());
121a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        } catch (IllegalArgumentException e) {
122a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.e(TAG, "MediaPlayer throws IllegalArgumentException, uri=" + item.getUri());
123a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        } catch (SecurityException e) {
124a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.e(TAG, "MediaPlayer throws SecurityException, uri=" + item.getUri());
125a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
126a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (item.getState() == MediaItemStatus.PLAYBACK_STATE_PLAYING) {
127a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            resume();
128a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        } else {
129a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            pause();
130a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
131a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
132a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
133a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
134a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public void seek(final PlaylistItem item) {
135a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (DEBUG) {
136a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.d(TAG, "seek: item=" + item);
137a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
138a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        int pos = (int)item.getPosition();
139a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (mState == STATE_PLAYING || mState == STATE_PAUSED) {
140a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            mMediaPlayer.seekTo(pos);
141a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            mSeekToPos = pos;
14276d965dc41863b33f887db33d283cb7f1523f60dJae Seo        } else if (mState == STATE_IDLE || mState == STATE_PREPARING_FOR_PLAY
14376d965dc41863b33f887db33d283cb7f1523f60dJae Seo                || mState == STATE_PREPARING_FOR_PAUSE) {
144a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            // Seek before onPrepared() arrives,
145a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            // need to performed delayed seek in onPrepared()
146a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            mSeekToPos = pos;
147a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
148a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
149a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
150a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
151a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public void getStatus(final PlaylistItem item, final boolean update) {
152a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (mState == STATE_PLAYING || mState == STATE_PAUSED) {
153a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            // use mSeekToPos if we're currently seeking (mSeekToPos is reset
154a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            // when seeking is completed)
155a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            item.setDuration(mMediaPlayer.getDuration());
156a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            item.setPosition(mSeekToPos > 0 ?
157a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    mSeekToPos : mMediaPlayer.getCurrentPosition());
158a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            item.setTimestamp(SystemClock.elapsedRealtime());
159a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
160a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (update && mCallback != null) {
161a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            mCallback.onPlaylistReady();
162a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
163a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
164a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
165a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
166a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public void pause() {
167a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (DEBUG) {
168a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.d(TAG, "pause");
169a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
170a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (mState == STATE_PLAYING) {
171a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            mMediaPlayer.pause();
172a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            mState = STATE_PAUSED;
17376d965dc41863b33f887db33d283cb7f1523f60dJae Seo        } else if (mState == STATE_PREPARING_FOR_PLAY) {
17476d965dc41863b33f887db33d283cb7f1523f60dJae Seo            mState = STATE_PREPARING_FOR_PAUSE;
175a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
176a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
177a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
178a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
179a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public void resume() {
180a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (DEBUG) {
181a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.d(TAG, "resume");
182a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
183a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (mState == STATE_READY || mState == STATE_PAUSED) {
184a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            mMediaPlayer.start();
185a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            mState = STATE_PLAYING;
18676d965dc41863b33f887db33d283cb7f1523f60dJae Seo        } else if (mState == STATE_IDLE || mState == STATE_PREPARING_FOR_PAUSE) {
18776d965dc41863b33f887db33d283cb7f1523f60dJae Seo            mState = STATE_PREPARING_FOR_PLAY;
188a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
189a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
190a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
191a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
192a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public void stop() {
193a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (DEBUG) {
194a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.d(TAG, "stop");
195a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
196a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (mState == STATE_PLAYING || mState == STATE_PAUSED) {
197a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            mMediaPlayer.stop();
198a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            mState = STATE_IDLE;
199a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
200a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
201a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
202a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
203a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public void enqueue(final PlaylistItem item) {
204a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        throw new UnsupportedOperationException("LocalPlayer doesn't support enqueue!");
205a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
206a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
207a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
208a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public PlaylistItem remove(String iid) {
209a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        throw new UnsupportedOperationException("LocalPlayer doesn't support remove!");
210a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
211a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
212a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    //MediaPlayer Listeners
213a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
214a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public void onPrepared(MediaPlayer mp) {
215a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (DEBUG) {
216a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.d(TAG, "onPrepared");
217a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
218a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mHandler.post(new Runnable() {
219a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
220a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void run() {
221a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (mState == STATE_IDLE) {
222a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    mState = STATE_READY;
223a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    updateVideoRect();
22476d965dc41863b33f887db33d283cb7f1523f60dJae Seo                } else if (mState == STATE_PREPARING_FOR_PLAY
22576d965dc41863b33f887db33d283cb7f1523f60dJae Seo                        || mState == STATE_PREPARING_FOR_PAUSE) {
22676d965dc41863b33f887db33d283cb7f1523f60dJae Seo                    int prevState = mState;
22776d965dc41863b33f887db33d283cb7f1523f60dJae Seo                    mState = mState == STATE_PREPARING_FOR_PLAY ? STATE_PLAYING : STATE_PAUSED;
228a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    updateVideoRect();
229a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    if (mSeekToPos > 0) {
230a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                        if (DEBUG) {
231a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                            Log.d(TAG, "seek to initial pos: " + mSeekToPos);
232a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                        }
233a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                        mMediaPlayer.seekTo(mSeekToPos);
234a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    }
23576d965dc41863b33f887db33d283cb7f1523f60dJae Seo                    if (prevState == STATE_PREPARING_FOR_PLAY) {
23676d965dc41863b33f887db33d283cb7f1523f60dJae Seo                        mMediaPlayer.start();
23776d965dc41863b33f887db33d283cb7f1523f60dJae Seo                    }
238a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
239a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (mCallback != null) {
240a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    mCallback.onPlaylistChanged();
241a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
242a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
243a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        });
244a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
245a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
246a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
247a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public void onCompletion(MediaPlayer mp) {
248a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (DEBUG) {
249a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.d(TAG, "onCompletion");
250a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
251a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mHandler.post(new Runnable() {
252a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
253a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void run() {
254a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (mCallback != null) {
255a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    mCallback.onCompletion();
256a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
257a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
258a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        });
259a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
260a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
261a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
262a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public boolean onError(MediaPlayer mp, int what, int extra) {
263a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (DEBUG) {
264a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.d(TAG, "onError");
265a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
266a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mHandler.post(new Runnable() {
267a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
268a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void run() {
269a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (mCallback != null) {
270a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    mCallback.onError();
271a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
272a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
273a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        });
274a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        // return true so that onCompletion is not called
275a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        return true;
276a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
277a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
278a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    @Override
279a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public void onSeekComplete(MediaPlayer mp) {
280a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (DEBUG) {
281a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Log.d(TAG, "onSeekComplete");
282a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
283a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mHandler.post(new Runnable() {
284a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
285a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void run() {
286a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                mSeekToPos = 0;
287a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (mCallback != null) {
288a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    mCallback.onPlaylistChanged();
289a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
290a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
291a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        });
292a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
293a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
294a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    protected Context getContext() { return mContext; }
295a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    protected MediaPlayer getMediaPlayer() { return mMediaPlayer; }
296a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    protected int getVideoWidth() { return mVideoWidth; }
297a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    protected int getVideoHeight() { return mVideoHeight; }
29876d965dc41863b33f887db33d283cb7f1523f60dJae Seo    protected int getState() { return mState; }
299a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    protected void setSurface(Surface surface) {
300a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mSurface = surface;
301a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mSurfaceHolder = null;
302a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        updateSurface();
303a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
304a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
305a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    protected void setSurface(SurfaceHolder surfaceHolder) {
306a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mSurface = null;
307a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mSurfaceHolder = surfaceHolder;
308a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        updateSurface();
309a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
310a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
311a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    protected void removeSurface(SurfaceHolder surfaceHolder) {
312a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (surfaceHolder == mSurfaceHolder) {
313a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            setSurface((SurfaceHolder)null);
314a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
315a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
316a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
317a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    protected void updateSurface() {
31876d965dc41863b33f887db33d283cb7f1523f60dJae Seo        mUpdateSurfaceHandler.removeCallbacksAndMessages(null);
31976d965dc41863b33f887db33d283cb7f1523f60dJae Seo        mUpdateSurfaceHandler.post(new Runnable() {
32076d965dc41863b33f887db33d283cb7f1523f60dJae Seo            @Override
32176d965dc41863b33f887db33d283cb7f1523f60dJae Seo            public void run() {
32276d965dc41863b33f887db33d283cb7f1523f60dJae Seo                if (mMediaPlayer == null) {
32376d965dc41863b33f887db33d283cb7f1523f60dJae Seo                    // just return if media player is already gone
32476d965dc41863b33f887db33d283cb7f1523f60dJae Seo                    return;
32576d965dc41863b33f887db33d283cb7f1523f60dJae Seo                }
32676d965dc41863b33f887db33d283cb7f1523f60dJae Seo                if (mSurface != null) {
32776d965dc41863b33f887db33d283cb7f1523f60dJae Seo                    // The setSurface API does not exist until V14+.
32876d965dc41863b33f887db33d283cb7f1523f60dJae Seo                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
32976d965dc41863b33f887db33d283cb7f1523f60dJae Seo                        ICSMediaPlayer.setSurface(mMediaPlayer, mSurface);
33076d965dc41863b33f887db33d283cb7f1523f60dJae Seo                    } else {
33176d965dc41863b33f887db33d283cb7f1523f60dJae Seo                        throw new UnsupportedOperationException("MediaPlayer does not support "
33276d965dc41863b33f887db33d283cb7f1523f60dJae Seo                                + "setSurface() on this version of the platform.");
33376d965dc41863b33f887db33d283cb7f1523f60dJae Seo                    }
33476d965dc41863b33f887db33d283cb7f1523f60dJae Seo                } else if (mSurfaceHolder != null) {
33576d965dc41863b33f887db33d283cb7f1523f60dJae Seo                    mMediaPlayer.setDisplay(mSurfaceHolder);
33676d965dc41863b33f887db33d283cb7f1523f60dJae Seo                } else {
33776d965dc41863b33f887db33d283cb7f1523f60dJae Seo                    mMediaPlayer.setDisplay(null);
33876d965dc41863b33f887db33d283cb7f1523f60dJae Seo                }
339a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
34076d965dc41863b33f887db33d283cb7f1523f60dJae Seo        });
341a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
342a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
343a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    protected abstract void updateSize();
344a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
345a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private void reset() {
346a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        if (mMediaPlayer != null) {
347a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            mMediaPlayer.stop();
348a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            mMediaPlayer.release();
349a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            mMediaPlayer = null;
350a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
351a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mMediaPlayer = new MediaPlayer();
352a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mMediaPlayer.setOnPreparedListener(this);
353a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mMediaPlayer.setOnCompletionListener(this);
354a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mMediaPlayer.setOnErrorListener(this);
355a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mMediaPlayer.setOnSeekCompleteListener(this);
356a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        updateSurface();
357a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mState = STATE_IDLE;
358a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        mSeekToPos = 0;
359a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
360a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
361a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private void updateVideoRect() {
36276d965dc41863b33f887db33d283cb7f1523f60dJae Seo        if (mState != STATE_IDLE && mState != STATE_PREPARING_FOR_PLAY
36376d965dc41863b33f887db33d283cb7f1523f60dJae Seo                && mState != STATE_PREPARING_FOR_PAUSE) {
364a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            int width = mMediaPlayer.getVideoWidth();
365a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            int height = mMediaPlayer.getVideoHeight();
366a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            if (width > 0 && height > 0) {
367a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                mVideoWidth = width;
368a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                mVideoHeight = height;
369a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                updateSize();
370a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            } else {
371a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                Log.e(TAG, "video rect is 0x0!");
372a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                mVideoWidth = mVideoHeight = 0;
373a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
374a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
375a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
376a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
37761636870e0a12db5909955eca58e0070357dde42Donghyun Cho    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
378a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    private static final class ICSMediaPlayer {
379a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        public static final void setSurface(MediaPlayer player, Surface surface) {
380a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            player.setSurface(surface);
381a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
382a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
383a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
384a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    /**
385a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang     * Handles playback of a single media item using MediaPlayer in SurfaceView
386a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang     */
387a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public static class SurfaceViewPlayer extends LocalPlayer implements
388a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            SurfaceHolder.Callback {
389a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        private static final String TAG = "SurfaceViewPlayer";
390a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        private RouteInfo mRoute;
391a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        private final SurfaceView mSurfaceView;
392a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        private final FrameLayout mLayout;
393a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        private DemoPresentation mPresentation;
394a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
395a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        public SurfaceViewPlayer(Context context) {
396a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            super(context);
397a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
398a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            mLayout = (FrameLayout)((Activity)context).findViewById(R.id.player);
399a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            mSurfaceView = (SurfaceView)((Activity)context).findViewById(R.id.surface_view);
400a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
401a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            // add surface holder callback
402a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            SurfaceHolder holder = mSurfaceView.getHolder();
403a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            holder.addCallback(this);
404a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
405a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
406a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        @Override
407a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        public void connect(RouteInfo route) {
408a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            super.connect(route);
409a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            mRoute = route;
410a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
411a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
412a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        @Override
413a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        public void release() {
414a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            super.release();
415a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
41663a2530d57dfe7a90de8b3ef70088e23773428fbAurimas Liutikas            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
41761636870e0a12db5909955eca58e0070357dde42Donghyun Cho                releasePresentation();
418a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
419a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
420a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            // remove surface holder callback
421a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            SurfaceHolder holder = mSurfaceView.getHolder();
422a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            holder.removeCallback(this);
423a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
424a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            // hide the surface view when SurfaceViewPlayer is destroyed
425a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            mSurfaceView.setVisibility(View.GONE);
426a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            mLayout.setVisibility(View.GONE);
427a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
428a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
42961636870e0a12db5909955eca58e0070357dde42Donghyun Cho        @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
430a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        @Override
431a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        public void updatePresentation() {
432a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            // Get the current route and its presentation display.
433a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            Display presentationDisplay = mRoute != null ? mRoute.getPresentationDisplay() : null;
434a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
435a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            // Dismiss the current presentation if the display has changed.
436a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            if (mPresentation != null && mPresentation.getDisplay() != presentationDisplay) {
437a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                Log.i(TAG, "Dismissing presentation because the current route no longer "
438a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                        + "has a presentation display.");
439a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                mPresentation.dismiss();
440a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                mPresentation = null;
441a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
442a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
443a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            // Show a new presentation if needed.
444a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            if (mPresentation == null && presentationDisplay != null) {
445a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                Log.i(TAG, "Showing presentation on display: " + presentationDisplay);
446a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                mPresentation = new DemoPresentation(getContext(), presentationDisplay);
447a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                mPresentation.setOnDismissListener(mOnDismissListener);
448a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                try {
449a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    mPresentation.show();
450a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                } catch (WindowManager.InvalidDisplayException ex) {
451a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    Log.w(TAG, "Couldn't show presentation!  Display was removed in "
452a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                              + "the meantime.", ex);
453a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    mPresentation = null;
454a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
455a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
456a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
457a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            updateContents();
458a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
459a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
460a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        // SurfaceHolder.Callback
461a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        @Override
462a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        public void surfaceChanged(SurfaceHolder holder, int format,
463a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                int width, int height) {
464a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            if (DEBUG) {
465a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                Log.d(TAG, "surfaceChanged: " + width + "x" + height);
466a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
467a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            setSurface(holder);
468a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
469a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
470a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        @Override
471a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        public void surfaceCreated(SurfaceHolder holder) {
472a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            if (DEBUG) {
473a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                Log.d(TAG, "surfaceCreated");
474a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
475a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            setSurface(holder);
476a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            updateSize();
477a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
478a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
479a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        @Override
480a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        public void surfaceDestroyed(SurfaceHolder holder) {
481a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            if (DEBUG) {
482a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                Log.d(TAG, "surfaceDestroyed");
483a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
484a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            removeSurface(holder);
485a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
486a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
487a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        @Override
488a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        protected void updateSize() {
489a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            int width = getVideoWidth();
490a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            int height = getVideoHeight();
491a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            if (width > 0 && height > 0) {
49263a2530d57dfe7a90de8b3ef70088e23773428fbAurimas Liutikas                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1
49363a2530d57dfe7a90de8b3ef70088e23773428fbAurimas Liutikas                        && mPresentation != null) {
49461636870e0a12db5909955eca58e0070357dde42Donghyun Cho                    mPresentation.updateSize(width, height);
49561636870e0a12db5909955eca58e0070357dde42Donghyun Cho                } else {
496a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    int surfaceWidth = mLayout.getWidth();
497a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    int surfaceHeight = mLayout.getHeight();
498a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
499a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    // Calculate the new size of mSurfaceView, so that video is centered
500a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    // inside the framelayout with proper letterboxing/pillarboxing
501a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    ViewGroup.LayoutParams lp = mSurfaceView.getLayoutParams();
502a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    if (surfaceWidth * height < surfaceHeight * width) {
503a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                        // Black bars on top&bottom, mSurfaceView has full layout width,
504a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                        // while height is derived from video's aspect ratio
505a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                        lp.width = surfaceWidth;
506a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                        lp.height = surfaceWidth * height / width;
507a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    } else {
508a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                        // Black bars on left&right, mSurfaceView has full layout height,
509a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                        // while width is derived from video's aspect ratio
510a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                        lp.width = surfaceHeight * width / height;
511a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                        lp.height = surfaceHeight;
512a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    }
513a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    Log.i(TAG, "video rect is " + lp.width + "x" + lp.height);
514a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    mSurfaceView.setLayoutParams(lp);
515a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
516a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
517a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
518a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
519a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        private void updateContents() {
520a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            // Show either the content in the main activity or the content in the presentation
521a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            if (mPresentation != null) {
522a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                mLayout.setVisibility(View.GONE);
523a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                mSurfaceView.setVisibility(View.GONE);
524a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            } else {
525a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                mLayout.setVisibility(View.VISIBLE);
526a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                mSurfaceView.setVisibility(View.VISIBLE);
527a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
528a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
529a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
530a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        // Listens for when presentations are dismissed.
531a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        private final DialogInterface.OnDismissListener mOnDismissListener =
532a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                new DialogInterface.OnDismissListener() {
533a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
534a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void onDismiss(DialogInterface dialog) {
535a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (dialog == mPresentation) {
536a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    Log.i(TAG, "Presentation dismissed.");
537a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    mPresentation = null;
538a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    updateContents();
539a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
540a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
541a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        };
542a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
54361636870e0a12db5909955eca58e0070357dde42Donghyun Cho        @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
54461636870e0a12db5909955eca58e0070357dde42Donghyun Cho        private void releasePresentation() {
54561636870e0a12db5909955eca58e0070357dde42Donghyun Cho            // dismiss presentation display
54661636870e0a12db5909955eca58e0070357dde42Donghyun Cho            if (mPresentation != null) {
54761636870e0a12db5909955eca58e0070357dde42Donghyun Cho                Log.i(TAG, "Dismissing presentation because the activity is no longer visible.");
54861636870e0a12db5909955eca58e0070357dde42Donghyun Cho                mPresentation.dismiss();
54961636870e0a12db5909955eca58e0070357dde42Donghyun Cho                mPresentation = null;
55061636870e0a12db5909955eca58e0070357dde42Donghyun Cho            }
55161636870e0a12db5909955eca58e0070357dde42Donghyun Cho        }
55261636870e0a12db5909955eca58e0070357dde42Donghyun Cho
553a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        // Presentation
55461636870e0a12db5909955eca58e0070357dde42Donghyun Cho        @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
555a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        private final class DemoPresentation extends Presentation {
556a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            private SurfaceView mPresentationSurfaceView;
557a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
558a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public DemoPresentation(Context context, Display display) {
559a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                super(context, display);
560a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
561a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
562a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            @Override
563a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            protected void onCreate(Bundle savedInstanceState) {
564a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                // Be sure to call the super class.
565a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                super.onCreate(savedInstanceState);
566a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
567a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                // Inflate the layout.
568a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                setContentView(R.layout.sample_media_router_presentation);
569a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
570a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                // Set up the surface view.
571a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                mPresentationSurfaceView = (SurfaceView)findViewById(R.id.surface_view);
572a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                SurfaceHolder holder = mPresentationSurfaceView.getHolder();
573a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                holder.addCallback(SurfaceViewPlayer.this);
574a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                Log.i(TAG, "Presentation created");
575a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
576a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
577a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            public void updateSize(int width, int height) {
578a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                int surfaceHeight = getWindow().getDecorView().getHeight();
579a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                int surfaceWidth = getWindow().getDecorView().getWidth();
580a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                ViewGroup.LayoutParams lp = mPresentationSurfaceView.getLayoutParams();
581a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                if (surfaceWidth * height < surfaceHeight * width) {
582a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    lp.width = surfaceWidth;
583a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    lp.height = surfaceWidth * height / width;
584a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                } else {
585a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    lp.width = surfaceHeight * width / height;
586a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    lp.height = surfaceHeight;
587a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                }
588a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                Log.i(TAG, "Presentation video rect is " + lp.width + "x" + lp.height);
589a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                mPresentationSurfaceView.setLayoutParams(lp);
590a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
591a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
592a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
593a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
594a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    /**
595a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang     * Handles playback of a single media item using MediaPlayer in
596a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang     * OverlayDisplayWindow.
597a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang     */
598a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    public static class OverlayPlayer extends LocalPlayer implements
599a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            OverlayDisplayWindow.OverlayWindowListener {
600a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        private static final String TAG = "OverlayPlayer";
601a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        private final OverlayDisplayWindow mOverlay;
602a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
603a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        public OverlayPlayer(Context context) {
604a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            super(context);
605a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
606a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            mOverlay = OverlayDisplayWindow.create(getContext(),
607a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    getContext().getResources().getString(
608a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                            R.string.sample_media_route_provider_remote),
609a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                    1024, 768, Gravity.CENTER);
610a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
611a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            mOverlay.setOverlayWindowListener(this);
612a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
613a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
614a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        @Override
615a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        public void connect(RouteInfo route) {
616a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            super.connect(route);
617a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            mOverlay.show();
618a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
619a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
620a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        @Override
621a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        public void release() {
622a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            super.release();
623a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            mOverlay.dismiss();
624a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
625a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
626a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        @Override
627a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        protected void updateSize() {
628a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            int width = getVideoWidth();
629a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            int height = getVideoHeight();
630a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            if (width > 0 && height > 0) {
631a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang                mOverlay.updateAspectRatio(width, height);
632a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            }
633a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
634a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
635a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        // OverlayDisplayWindow.OverlayWindowListener
636a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        @Override
637a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        public void onWindowCreated(Surface surface) {
638a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            setSurface(surface);
639a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
640a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
641a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        @Override
642a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        public void onWindowCreated(SurfaceHolder surfaceHolder) {
643a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            setSurface(surfaceHolder);
644a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
645a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang
646a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        @Override
647a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        public void onWindowDestroyed() {
648a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang            setSurface((SurfaceHolder)null);
649a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang        }
650cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang
651cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang        @Override
652cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang        public Bitmap getSnapshot() {
65376d965dc41863b33f887db33d283cb7f1523f60dJae Seo            if (getState() == STATE_PLAYING || getState() == STATE_PAUSED) {
65476d965dc41863b33f887db33d283cb7f1523f60dJae Seo                return mOverlay.getSnapshot();
65576d965dc41863b33f887db33d283cb7f1523f60dJae Seo            }
65676d965dc41863b33f887db33d283cb7f1523f60dJae Seo            return null;
657cf61a6ed2bfa6141b832fdc40a9fbfb70af91416Chong Zhang        }
658a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang    }
659a6bf581f7a7a6326505569f0d1215d0ba84779d7Chong Zhang}
660