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