19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.widget; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.AlertDialog; 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.DialogInterface; 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.Resources; 23de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viveretteimport android.graphics.Canvas; 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.media.AudioManager; 25bdfd91024767893829017918ab565f224ccd35ecChong Zhangimport android.media.ClosedCaptionRenderer; 26af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnarimport android.media.MediaFormat; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.media.MediaPlayer; 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.media.MediaPlayer.OnCompletionListener; 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.media.MediaPlayer.OnErrorListener; 30a0ba79473b9067e315155718545103bb4f361873James Dongimport android.media.MediaPlayer.OnInfoListener; 31af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnarimport android.media.Metadata; 32484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnarimport android.media.SubtitleController; 33d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viveretteimport android.media.SubtitleTrack.RenderingWidget; 34ba3699b568e656910641b246b27448d92632a389Sungsoo Limimport android.media.TtmlRenderer; 35484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnarimport android.media.WebVttRenderer; 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Uri; 3729f5183794efd58a3442aedcf829e3dbcd3fd867Lajos Molnarimport android.os.Looper; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet; 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log; 40484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnarimport android.util.Pair; 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.KeyEvent; 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.MotionEvent; 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.SurfaceHolder; 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.SurfaceView; 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.View; 468a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganovimport android.view.accessibility.AccessibilityEvent; 478a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganovimport android.view.accessibility.AccessibilityNodeInfo; 48a8381dfc5ee60dcf99dfd16a840f746cd7cb42abOwen Linimport android.widget.MediaController.MediaPlayerControl; 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException; 51af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnarimport java.io.InputStream; 52256430093679e1d62b54fb0c852126e54d162f6fAndreas Huberimport java.util.Map; 53af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnarimport java.util.Vector; 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Displays a video file. The VideoView class 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * can load images from various sources (such as resources or content 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * providers), takes care of computing its measurement from the video so that 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * it can be used in any layout manager, and provides various display options 607e11b16b9f8896170d492240a5fd50c8bd04105dLajos Molnar * such as scaling and tinting.<p> 617e11b16b9f8896170d492240a5fd50c8bd04105dLajos Molnar * 627e11b16b9f8896170d492240a5fd50c8bd04105dLajos Molnar * <em>Note: VideoView does not retain its full state when going into the 637e11b16b9f8896170d492240a5fd50c8bd04105dLajos Molnar * background.</em> In particular, it does not restore the current play state, 647e11b16b9f8896170d492240a5fd50c8bd04105dLajos Molnar * play position, selected tracks, or any subtitle tracks added via 657e11b16b9f8896170d492240a5fd50c8bd04105dLajos Molnar * {@link #addSubtitleSource addSubtitleSource()}. Applications should 667e11b16b9f8896170d492240a5fd50c8bd04105dLajos Molnar * save and restore these on their own in 677e11b16b9f8896170d492240a5fd50c8bd04105dLajos Molnar * {@link android.app.Activity#onSaveInstanceState} and 687e11b16b9f8896170d492240a5fd50c8bd04105dLajos Molnar * {@link android.app.Activity#onRestoreInstanceState}.<p> 697e11b16b9f8896170d492240a5fd50c8bd04105dLajos Molnar * Also note that the audio session id (from {@link #getAudioSessionId}) may 707e11b16b9f8896170d492240a5fd50c8bd04105dLajos Molnar * change from its previously returned value when the VideoView is restored. 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 72484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnarpublic class VideoView extends SurfaceView 73484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar implements MediaPlayerControl, SubtitleController.Anchor { 74b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project private String TAG = "VideoView"; 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // settable by the client 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Uri mUri; 77256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber private Map<String, String> mHeaders; 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 79fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong // all possible internal states 80fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong private static final int STATE_ERROR = -1; 81fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong private static final int STATE_IDLE = 0; 82fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong private static final int STATE_PREPARING = 1; 83fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong private static final int STATE_PREPARED = 2; 84fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong private static final int STATE_PLAYING = 3; 85fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong private static final int STATE_PAUSED = 4; 86fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong private static final int STATE_PLAYBACK_COMPLETED = 5; 87fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong 88fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong // mCurrentState is a VideoView object's current state. 89fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong // mTargetState is the state that a method caller intends to reach. 90fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong // For instance, regardless the VideoView object's current state, 91fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong // calling pause() intends to bring the object to a target state 92fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong // of STATE_PAUSED. 93fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong private int mCurrentState = STATE_IDLE; 94fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong private int mTargetState = STATE_IDLE; 95fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // All the stuff we need for playing and showing a video 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private SurfaceHolder mSurfaceHolder = null; 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private MediaPlayer mMediaPlayer = null; 9913bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen private int mAudioSession; 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mVideoWidth; 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mVideoHeight; 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mSurfaceWidth; 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mSurfaceHeight; 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private MediaController mMediaController; 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private OnCompletionListener mOnCompletionListener; 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private MediaPlayer.OnPreparedListener mOnPreparedListener; 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mCurrentBufferPercentage; 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private OnErrorListener mOnErrorListener; 109a0ba79473b9067e315155718545103bb4f361873James Dong private OnInfoListener mOnInfoListener; 110fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong private int mSeekWhenPrepared; // recording the seek position while preparing 111c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen private boolean mCanPause; 112c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen private boolean mCanSeekBack; 113c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen private boolean mCanSeekForward; 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 115d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** Subtitle rendering widget overlaid on top of the video. */ 116d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private RenderingWidget mSubtitleWidget; 117de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette 118d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** Listener for changes to subtitle data, used to redraw when needed. */ 119d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private RenderingWidget.OnChangedListener mSubtitlesChangedListener; 120de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public VideoView(Context context) { 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super(context); 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project initVideoView(); 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 125256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public VideoView(Context context, AttributeSet attrs) { 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this(context, attrs, 0); 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project initVideoView(); 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 130256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 131617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette public VideoView(Context context, AttributeSet attrs, int defStyleAttr) { 132617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette this(context, attrs, defStyleAttr, 0); 133617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette } 134617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette 135617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette public VideoView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 136617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette super(context, attrs, defStyleAttr, defStyleRes); 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project initVideoView(); 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 1420b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen //Log.i("@@@@", "onMeasure(" + MeasureSpec.toString(widthMeasureSpec) + ", " 1430b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen // + MeasureSpec.toString(heightMeasureSpec) + ")"); 1440b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int width = getDefaultSize(mVideoWidth, widthMeasureSpec); 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int height = getDefaultSize(mVideoHeight, heightMeasureSpec); 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mVideoWidth > 0 && mVideoHeight > 0) { 1480b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen 1490b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); 1500b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); 1510b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); 1520b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); 1530b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen 1540b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen if (widthSpecMode == MeasureSpec.EXACTLY && heightSpecMode == MeasureSpec.EXACTLY) { 1550b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen // the size is fixed 1560b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen width = widthSpecSize; 1570b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen height = heightSpecSize; 1580b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen 1590b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen // for compatibility, we adjust size based on aspect ratio 1600b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen if ( mVideoWidth * height < width * mVideoHeight ) { 1610b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen //Log.i("@@@", "image too wide, correcting"); 1620b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen width = height * mVideoWidth / mVideoHeight; 1630b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen } else if ( mVideoWidth * height > width * mVideoHeight ) { 1640b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen //Log.i("@@@", "image too tall, correcting"); 1650b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen height = width * mVideoHeight / mVideoWidth; 1660b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen } 1670b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen } else if (widthSpecMode == MeasureSpec.EXACTLY) { 1680b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen // only the width is fixed, adjust the height to match aspect ratio if possible 1690b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen width = widthSpecSize; 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project height = width * mVideoHeight / mVideoWidth; 1710b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) { 1720b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen // couldn't match aspect ratio within the constraints 1730b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen height = heightSpecSize; 1740b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen } 1750b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen } else if (heightSpecMode == MeasureSpec.EXACTLY) { 1760b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen // only the height is fixed, adjust the width to match aspect ratio if possible 1770b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen height = heightSpecSize; 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project width = height * mVideoWidth / mVideoHeight; 1790b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) { 1800b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen // couldn't match aspect ratio within the constraints 1810b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen width = widthSpecSize; 1820b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen } 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1840b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen // neither the width nor the height are fixed, try to use actual video size 1850b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen width = mVideoWidth; 1860b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen height = mVideoHeight; 1870b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) { 1880b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen // too tall, decrease both width and height 1890b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen height = heightSpecSize; 1900b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen width = height * mVideoWidth / mVideoHeight; 1910b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen } 1920b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) { 1930b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen // too wide, decrease both width and height 1940b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen width = widthSpecSize; 1950b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen height = width * mVideoHeight / mVideoWidth; 1960b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen } 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1980b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen } else { 1990b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen // no size yet, just adopt the given spec sizes 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setMeasuredDimension(width, height); 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 203256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 2048a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov @Override 2058a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 2068a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov super.onInitializeAccessibilityEvent(event); 2078a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov event.setClassName(VideoView.class.getName()); 2088a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov } 2098a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov 2108a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov @Override 2118a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 2128a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov super.onInitializeAccessibilityNodeInfo(info); 2138a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov info.setClassName(VideoView.class.getName()); 2148a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov } 2158a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov 216c1374e8e1ae6669ffda874445ebf6b14c49d3a9cMarco Nelissen public int resolveAdjustedSize(int desiredSize, int measureSpec) { 217c1374e8e1ae6669ffda874445ebf6b14c49d3a9cMarco Nelissen return getDefaultSize(desiredSize, measureSpec); 218c1374e8e1ae6669ffda874445ebf6b14c49d3a9cMarco Nelissen } 219c1374e8e1ae6669ffda874445ebf6b14c49d3a9cMarco Nelissen 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void initVideoView() { 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVideoWidth = 0; 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVideoHeight = 0; 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getHolder().addCallback(mSHCallback); 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setFocusable(true); 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setFocusableInTouchMode(true); 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project requestFocus(); 228484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar mPendingSubtitleTracks = new Vector<Pair<InputStream, MediaFormat>>(); 229fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mCurrentState = STATE_IDLE; 230fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mTargetState = STATE_IDLE; 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2330e9e3b213e70fd4be044524d2151e8585bf0acd8Ronghua Wu /** 2340e9e3b213e70fd4be044524d2151e8585bf0acd8Ronghua Wu * Sets video path. 2350e9e3b213e70fd4be044524d2151e8585bf0acd8Ronghua Wu * 2360e9e3b213e70fd4be044524d2151e8585bf0acd8Ronghua Wu * @param path the path of the video. 2370e9e3b213e70fd4be044524d2151e8585bf0acd8Ronghua Wu */ 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setVideoPath(String path) { 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setVideoURI(Uri.parse(path)); 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2420e9e3b213e70fd4be044524d2151e8585bf0acd8Ronghua Wu /** 2430e9e3b213e70fd4be044524d2151e8585bf0acd8Ronghua Wu * Sets video URI. 2440e9e3b213e70fd4be044524d2151e8585bf0acd8Ronghua Wu * 2450e9e3b213e70fd4be044524d2151e8585bf0acd8Ronghua Wu * @param uri the URI of the video. 2460e9e3b213e70fd4be044524d2151e8585bf0acd8Ronghua Wu */ 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setVideoURI(Uri uri) { 248256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber setVideoURI(uri, null); 249256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber } 250256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 251256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber /** 2520e9e3b213e70fd4be044524d2151e8585bf0acd8Ronghua Wu * Sets video URI using specific headers. 2530e9e3b213e70fd4be044524d2151e8585bf0acd8Ronghua Wu * 2540e9e3b213e70fd4be044524d2151e8585bf0acd8Ronghua Wu * @param uri the URI of the video. 2550e9e3b213e70fd4be044524d2151e8585bf0acd8Ronghua Wu * @param headers the headers for the URI request. 25648db7834830215a3ee00f31a442a62acf33cabfaRonghua Wu * Note that the cross domain redirection is allowed by default, but that can be 25748db7834830215a3ee00f31a442a62acf33cabfaRonghua Wu * changed with key/value pairs through the headers parameter with 25848db7834830215a3ee00f31a442a62acf33cabfaRonghua Wu * "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value 25948db7834830215a3ee00f31a442a62acf33cabfaRonghua Wu * to disallow or allow cross domain redirection. 260256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber */ 261256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber public void setVideoURI(Uri uri, Map<String, String> headers) { 2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mUri = uri; 263256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber mHeaders = headers; 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSeekWhenPrepared = 0; 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project openVideo(); 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project requestLayout(); 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invalidate(); 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 269256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 270af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar /** 271af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * Adds an external subtitle source file (from the provided input stream.) 272af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * 273af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * Note that a single external subtitle source may contain multiple or no 274af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * supported tracks in it. If the source contained at least one track in 275af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * it, one will receive an {@link MediaPlayer#MEDIA_INFO_METADATA_UPDATE} 276af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * info message. Otherwise, if reading the source takes excessive time, 277af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * one will receive a {@link MediaPlayer#MEDIA_INFO_SUBTITLE_TIMED_OUT} 278af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * message. If the source contained no supported track (including an empty 279af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * source file or null input stream), one will receive a {@link 280af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * MediaPlayer#MEDIA_INFO_UNSUPPORTED_SUBTITLE} message. One can find the 281af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * total number of available tracks using {@link MediaPlayer#getTrackInfo()} 282af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * to see what additional tracks become available after this method call. 283af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * 284af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * @param is input stream containing the subtitle data. It will be 285af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * closed by the media framework. 286af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * @param format the format of the subtitle track(s). Must contain at least 287af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * the mime type ({@link MediaFormat#KEY_MIME}) and the 288af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * language ({@link MediaFormat#KEY_LANGUAGE}) of the file. 289af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * If the file itself contains the language information, 290af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * specify "und" for the language. 291af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar */ 292af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar public void addSubtitleSource(InputStream is, MediaFormat format) { 293af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar if (mMediaPlayer == null) { 294484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar mPendingSubtitleTracks.add(Pair.create(is, format)); 295af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar } else { 296484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar try { 297484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar mMediaPlayer.addSubtitleSource(is, format); 298484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar } catch (IllegalStateException e) { 299484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar mInfoListener.onInfo( 300484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar mMediaPlayer, MediaPlayer.MEDIA_INFO_UNSUPPORTED_SUBTITLE, 0); 301484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar } 302af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar } 303af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar } 304af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar 305484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar private Vector<Pair<InputStream, MediaFormat>> mPendingSubtitleTracks; 306af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar 3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void stopPlayback() { 3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMediaPlayer != null) { 3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaPlayer.stop(); 3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaPlayer.release(); 3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaPlayer = null; 312fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mCurrentState = STATE_IDLE; 313fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mTargetState = STATE_IDLE; 3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void openVideo() { 3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mUri == null || mSurfaceHolder == null) { 3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // not ready for playback just yet, will try again later 3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 32271068f694849353bb99c1906f486fbe29a14c074Marco Nelissen AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); 32371068f694849353bb99c1906f486fbe29a14c074Marco Nelissen am.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); 324fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong 325dddeee6f350673b691b1b9001545a27f9c3d19f0Marco Nelissen // we shouldn't clear the target state, because somebody might have 326dddeee6f350673b691b1b9001545a27f9c3d19f0Marco Nelissen // called start() previously 327dddeee6f350673b691b1b9001545a27f9c3d19f0Marco Nelissen release(false); 3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaPlayer = new MediaPlayer(); 330484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar // TODO: create SubtitleController in MediaPlayer, but we need 331484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar // a context for the subtitle renderers 332d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final Context context = getContext(); 333d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final SubtitleController controller = new SubtitleController( 334d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette context, mMediaPlayer.getMediaTimeProvider(), mMediaPlayer); 335d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette controller.registerRenderer(new WebVttRenderer(context)); 336ba3699b568e656910641b246b27448d92632a389Sungsoo Lim controller.registerRenderer(new TtmlRenderer(context)); 337bdfd91024767893829017918ab565f224ccd35ecChong Zhang controller.registerRenderer(new ClosedCaptionRenderer(context)); 338484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar mMediaPlayer.setSubtitleAnchor(controller, this); 339484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar 34013bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen if (mAudioSession != 0) { 34113bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen mMediaPlayer.setAudioSessionId(mAudioSession); 34213bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen } else { 34313bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen mAudioSession = mMediaPlayer.getAudioSessionId(); 34413bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen } 3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaPlayer.setOnPreparedListener(mPreparedListener); 3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener); 3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaPlayer.setOnCompletionListener(mCompletionListener); 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaPlayer.setOnErrorListener(mErrorListener); 349af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar mMediaPlayer.setOnInfoListener(mInfoListener); 3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener); 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCurrentBufferPercentage = 0; 352256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber mMediaPlayer.setDataSource(mContext, mUri, mHeaders); 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaPlayer.setDisplay(mSurfaceHolder); 3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaPlayer.setScreenOnWhilePlaying(true); 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaPlayer.prepareAsync(); 357af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar 358484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar for (Pair<InputStream, MediaFormat> pending: mPendingSubtitleTracks) { 359484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar try { 360484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar mMediaPlayer.addSubtitleSource(pending.first, pending.second); 361484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar } catch (IllegalStateException e) { 362484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar mInfoListener.onInfo( 363484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar mMediaPlayer, MediaPlayer.MEDIA_INFO_UNSUPPORTED_SUBTITLE, 0); 364484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar } 365af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar } 366af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar 367dddeee6f350673b691b1b9001545a27f9c3d19f0Marco Nelissen // we don't set the target state here either, but preserve the 368dddeee6f350673b691b1b9001545a27f9c3d19f0Marco Nelissen // target state that was there before. 369fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mCurrentState = STATE_PREPARING; 3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project attachMediaController(); 3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException ex) { 372b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project Log.w(TAG, "Unable to open content: " + mUri, ex); 373fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mCurrentState = STATE_ERROR; 374fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mTargetState = STATE_ERROR; 375020d2e3453b98ae435c4c21b849a2fe0a8842be7Andrei Popescu mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); 3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IllegalArgumentException ex) { 378b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project Log.w(TAG, "Unable to open content: " + mUri, ex); 379fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mCurrentState = STATE_ERROR; 380fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mTargetState = STATE_ERROR; 381020d2e3453b98ae435c4c21b849a2fe0a8842be7Andrei Popescu mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); 3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 383af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar } finally { 384484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar mPendingSubtitleTracks.clear(); 3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 387256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setMediaController(MediaController controller) { 3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMediaController != null) { 3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaController.hide(); 3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaController = controller; 3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project attachMediaController(); 3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void attachMediaController() { 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMediaPlayer != null && mMediaController != null) { 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaController.setMediaPlayer(this); 3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View anchorView = this.getParent() instanceof View ? 4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (View)this.getParent() : this; 4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaController.setAnchorView(anchorView); 402fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mMediaController.setEnabled(isInPlaybackState()); 4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 405256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MediaPlayer.OnVideoSizeChangedListener mSizeChangedListener = 4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new MediaPlayer.OnVideoSizeChangedListener() { 4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onVideoSizeChanged(MediaPlayer mp, int width, int height) { 4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVideoWidth = mp.getVideoWidth(); 4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVideoHeight = mp.getVideoHeight(); 4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mVideoWidth != 0 && mVideoHeight != 0) { 4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getHolder().setFixedSize(mVideoWidth, mVideoHeight); 413f5d102ed769ba33cbd48e58c209ece3f1014fe61Teng-Hui Zhu requestLayout(); 4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 417256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener() { 4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onPrepared(MediaPlayer mp) { 420fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mCurrentState = STATE_PREPARED; 421c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen 422c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen // Get the capabilities of the player for this stream 423c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen Metadata data = mp.getMetadata(MediaPlayer.METADATA_ALL, 424c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen MediaPlayer.BYPASS_METADATA_FILTER); 425d44d33b01a2125cfa40153e8399dd39908005004Andreas Huber 426d44d33b01a2125cfa40153e8399dd39908005004Andreas Huber if (data != null) { 427d44d33b01a2125cfa40153e8399dd39908005004Andreas Huber mCanPause = !data.has(Metadata.PAUSE_AVAILABLE) 428d44d33b01a2125cfa40153e8399dd39908005004Andreas Huber || data.getBoolean(Metadata.PAUSE_AVAILABLE); 429d44d33b01a2125cfa40153e8399dd39908005004Andreas Huber mCanSeekBack = !data.has(Metadata.SEEK_BACKWARD_AVAILABLE) 430d44d33b01a2125cfa40153e8399dd39908005004Andreas Huber || data.getBoolean(Metadata.SEEK_BACKWARD_AVAILABLE); 431d44d33b01a2125cfa40153e8399dd39908005004Andreas Huber mCanSeekForward = !data.has(Metadata.SEEK_FORWARD_AVAILABLE) 432d44d33b01a2125cfa40153e8399dd39908005004Andreas Huber || data.getBoolean(Metadata.SEEK_FORWARD_AVAILABLE); 433d44d33b01a2125cfa40153e8399dd39908005004Andreas Huber } else { 4342869e952c65548555a9fc197c1f8ceb5b7470462Andreas Huber mCanPause = mCanSeekBack = mCanSeekForward = true; 435d44d33b01a2125cfa40153e8399dd39908005004Andreas Huber } 436c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen 4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mOnPreparedListener != null) { 4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOnPreparedListener.onPrepared(mMediaPlayer); 4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMediaController != null) { 4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaController.setEnabled(true); 4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVideoWidth = mp.getVideoWidth(); 4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVideoHeight = mp.getVideoHeight(); 445c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen 446fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong int seekToPosition = mSeekWhenPrepared; // mSeekWhenPrepared may be changed after seekTo() call 447fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong if (seekToPosition != 0) { 448fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong seekTo(seekToPosition); 449fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong } 4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mVideoWidth != 0 && mVideoHeight != 0) { 4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //Log.i("@@@@", "video size: " + mVideoWidth +"/"+ mVideoHeight); 4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getHolder().setFixedSize(mVideoWidth, mVideoHeight); 4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSurfaceWidth == mVideoWidth && mSurfaceHeight == mVideoHeight) { 4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // We didn't actually change the size (it was already at the size 4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // we need), so we won't get a "surface changed" callback, so 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // start the video here instead of in the callback. 457fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong if (mTargetState == STATE_PLAYING) { 458aa00e390c191f9b4eaee8ecade88c74571b2b3f3James Dong start(); 4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMediaController != null) { 4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaController.show(); 4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (!isPlaying() && 463fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong (seekToPosition != 0 || getCurrentPosition() > 0)) { 4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMediaController != null) { 4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Show the media controls when we're paused into a video and make 'em stick. 4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaController.show(0); 4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // We don't know the video size yet, but should start anyway. 4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // The video size might be reported to us later. 473fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong if (mTargetState == STATE_PLAYING) { 474aa00e390c191f9b4eaee8ecade88c74571b2b3f3James Dong start(); 4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private MediaPlayer.OnCompletionListener mCompletionListener = 4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new MediaPlayer.OnCompletionListener() { 4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onCompletion(MediaPlayer mp) { 483fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mCurrentState = STATE_PLAYBACK_COMPLETED; 484fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mTargetState = STATE_PLAYBACK_COMPLETED; 4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMediaController != null) { 4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaController.hide(); 4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mOnCompletionListener != null) { 4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOnCompletionListener.onCompletion(mMediaPlayer); 4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 494af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar private MediaPlayer.OnInfoListener mInfoListener = 495af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar new MediaPlayer.OnInfoListener() { 496af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar public boolean onInfo(MediaPlayer mp, int arg1, int arg2) { 497af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar if (mOnInfoListener != null) { 498af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar mOnInfoListener.onInfo(mp, arg1, arg2); 499af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar } 500af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar return true; 501af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar } 502af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar }; 503af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar 5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private MediaPlayer.OnErrorListener mErrorListener = 5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new MediaPlayer.OnErrorListener() { 506c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project public boolean onError(MediaPlayer mp, int framework_err, int impl_err) { 507c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project Log.d(TAG, "Error: " + framework_err + "," + impl_err); 508fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mCurrentState = STATE_ERROR; 509fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mTargetState = STATE_ERROR; 5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMediaController != null) { 5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaController.hide(); 5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* If an error handler has been supplied, use it and finish. */ 5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mOnErrorListener != null) { 516c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (mOnErrorListener.onError(mMediaPlayer, framework_err, impl_err)) { 5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* Otherwise, pop up an error dialog so the user knows that 5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * something bad has happened. Only try and pop up the dialog 5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * if we're attached to a window. When we're going away and no 5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * longer have a window, don't bother showing the user an error. 5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (getWindowToken() != null) { 5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Resources r = mContext.getResources(); 528c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project int messageId; 529c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 530c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (framework_err == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) { 531c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project messageId = com.android.internal.R.string.VideoView_error_text_invalid_progressive_playback; 532c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else { 533c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project messageId = com.android.internal.R.string.VideoView_error_text_unknown; 534c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 535c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new AlertDialog.Builder(mContext) 537c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project .setMessage(messageId) 5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project .setPositiveButton(com.android.internal.R.string.VideoView_error_button, 5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new DialogInterface.OnClickListener() { 5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onClick(DialogInterface dialog, int whichButton) { 5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* If we get here, there is no onError listener, so 5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * at least inform them that the video is over. 5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mOnCompletionListener != null) { 5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOnCompletionListener.onCompletion(mMediaPlayer); 5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }) 5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project .setCancelable(false) 5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project .show(); 5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private MediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener = 5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new MediaPlayer.OnBufferingUpdateListener() { 5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onBufferingUpdate(MediaPlayer mp, int percent) { 5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCurrentBufferPercentage = percent; 5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Register a callback to be invoked when the media file 5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * is loaded and ready to go. 5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param l The callback that will be run 5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setOnPreparedListener(MediaPlayer.OnPreparedListener l) 5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOnPreparedListener = l; 5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Register a callback to be invoked when the end of a media file 5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * has been reached during playback. 5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param l The callback that will be run 5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setOnCompletionListener(OnCompletionListener l) 5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOnCompletionListener = l; 5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Register a callback to be invoked when an error occurs 5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * during playback or setup. If no listener is specified, 5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * or if the listener returned false, VideoView will inform 5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the user of any errors. 5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param l The callback that will be run 5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setOnErrorListener(OnErrorListener l) 5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOnErrorListener = l; 5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 598a0ba79473b9067e315155718545103bb4f361873James Dong /** 599a0ba79473b9067e315155718545103bb4f361873James Dong * Register a callback to be invoked when an informational event 600a0ba79473b9067e315155718545103bb4f361873James Dong * occurs during playback or setup. 601a0ba79473b9067e315155718545103bb4f361873James Dong * 602a0ba79473b9067e315155718545103bb4f361873James Dong * @param l The callback that will be run 603a0ba79473b9067e315155718545103bb4f361873James Dong */ 604a0ba79473b9067e315155718545103bb4f361873James Dong public void setOnInfoListener(OnInfoListener l) { 605a0ba79473b9067e315155718545103bb4f361873James Dong mOnInfoListener = l; 606a0ba79473b9067e315155718545103bb4f361873James Dong } 607a0ba79473b9067e315155718545103bb4f361873James Dong 6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SurfaceHolder.Callback mSHCallback = new SurfaceHolder.Callback() 6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void surfaceChanged(SurfaceHolder holder, int format, 6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int w, int h) 6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSurfaceWidth = w; 6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSurfaceHeight = h; 615fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong boolean isValidState = (mTargetState == STATE_PLAYING); 616fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong boolean hasValidSize = (mVideoWidth == w && mVideoHeight == h); 617fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong if (mMediaPlayer != null && isValidState && hasValidSize) { 6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSeekWhenPrepared != 0) { 619fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong seekTo(mSeekWhenPrepared); 6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 621fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong start(); 6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void surfaceCreated(SurfaceHolder holder) 6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSurfaceHolder = holder; 62869b8d69aadbf0e795f1a1e1adc82c78cf0b9959fAndreas Huber openVideo(); 6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void surfaceDestroyed(SurfaceHolder holder) 6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // after we return from this we can't use the surface any more 6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSurfaceHolder = null; 6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMediaController != null) mMediaController.hide(); 63669b8d69aadbf0e795f1a1e1adc82c78cf0b9959fAndreas Huber release(true); 6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 640fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong /* 641fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong * release the media player in any state 642fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong */ 643dddeee6f350673b691b1b9001545a27f9c3d19f0Marco Nelissen private void release(boolean cleartargetstate) { 644fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong if (mMediaPlayer != null) { 645fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mMediaPlayer.reset(); 646fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mMediaPlayer.release(); 647fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mMediaPlayer = null; 648484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar mPendingSubtitleTracks.clear(); 649fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mCurrentState = STATE_IDLE; 650dddeee6f350673b691b1b9001545a27f9c3d19f0Marco Nelissen if (cleartargetstate) { 651dddeee6f350673b691b1b9001545a27f9c3d19f0Marco Nelissen mTargetState = STATE_IDLE; 652dddeee6f350673b691b1b9001545a27f9c3d19f0Marco Nelissen } 653fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong } 654fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong } 655fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong 6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean onTouchEvent(MotionEvent ev) { 658fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong if (isInPlaybackState() && mMediaController != null) { 6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project toggleMediaControlsVisiblity(); 6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 663256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean onTrackballEvent(MotionEvent ev) { 666fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong if (isInPlaybackState() && mMediaController != null) { 6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project toggleMediaControlsVisiblity(); 6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 671256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean onKeyDown(int keyCode, KeyEvent event) 6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 675fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong boolean isKeyCodeSupported = keyCode != KeyEvent.KEYCODE_BACK && 676fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong keyCode != KeyEvent.KEYCODE_VOLUME_UP && 677fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && 678b0418da0e7594a8c2164a46985c5f1993632e010Jeff Brown keyCode != KeyEvent.KEYCODE_VOLUME_MUTE && 679fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong keyCode != KeyEvent.KEYCODE_MENU && 680fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong keyCode != KeyEvent.KEYCODE_CALL && 681fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong keyCode != KeyEvent.KEYCODE_ENDCALL; 682fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong if (isInPlaybackState() && isKeyCodeSupported && mMediaController != null) { 6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK || 684f8a7ceaef2e7d5cd530c9426bde91b6fa9a40b75Andy Stadler keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) { 6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMediaPlayer.isPlaying()) { 6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pause(); 6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaController.show(); 6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project start(); 6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaController.hide(); 6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 6934d396052deb54399cbadbeb8abd873df6f3af342Jeff Brown } else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) { 694d7db70123fe177e149ae50283e31508f79452f8cChih-Chung Chang if (!mMediaPlayer.isPlaying()) { 6954d396052deb54399cbadbeb8abd873df6f3af342Jeff Brown start(); 6964d396052deb54399cbadbeb8abd873df6f3af342Jeff Brown mMediaController.hide(); 6974d396052deb54399cbadbeb8abd873df6f3af342Jeff Brown } 6984d396052deb54399cbadbeb8abd873df6f3af342Jeff Brown return true; 699256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP 7004d396052deb54399cbadbeb8abd873df6f3af342Jeff Brown || keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) { 701d7db70123fe177e149ae50283e31508f79452f8cChih-Chung Chang if (mMediaPlayer.isPlaying()) { 7024d396052deb54399cbadbeb8abd873df6f3af342Jeff Brown pause(); 7034d396052deb54399cbadbeb8abd873df6f3af342Jeff Brown mMediaController.show(); 7044d396052deb54399cbadbeb8abd873df6f3af342Jeff Brown } 7054d396052deb54399cbadbeb8abd873df6f3af342Jeff Brown return true; 7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project toggleMediaControlsVisiblity(); 7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return super.onKeyDown(keyCode, event); 7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void toggleMediaControlsVisiblity() { 715256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber if (mMediaController.isShowing()) { 7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaController.hide(); 7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaController.show(); 7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 721256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 72213bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen @Override 7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void start() { 724fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong if (isInPlaybackState()) { 725fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mMediaPlayer.start(); 726fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mCurrentState = STATE_PLAYING; 7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 728fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mTargetState = STATE_PLAYING; 7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 730256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 73113bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen @Override 7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void pause() { 733fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong if (isInPlaybackState()) { 7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMediaPlayer.isPlaying()) { 7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaPlayer.pause(); 736fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mCurrentState = STATE_PAUSED; 7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 739fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mTargetState = STATE_PAUSED; 7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 741256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 7422e1818a4d16c3309660f27286c77d8d1eee95a25Gloria Wang public void suspend() { 74369b8d69aadbf0e795f1a1e1adc82c78cf0b9959fAndreas Huber release(false); 7442e1818a4d16c3309660f27286c77d8d1eee95a25Gloria Wang } 7452e1818a4d16c3309660f27286c77d8d1eee95a25Gloria Wang 7462e1818a4d16c3309660f27286c77d8d1eee95a25Gloria Wang public void resume() { 74769b8d69aadbf0e795f1a1e1adc82c78cf0b9959fAndreas Huber openVideo(); 7482e1818a4d16c3309660f27286c77d8d1eee95a25Gloria Wang } 7492e1818a4d16c3309660f27286c77d8d1eee95a25Gloria Wang 75013bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen @Override 7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getDuration() { 752fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong if (isInPlaybackState()) { 753585c07e9ac19060bb242067a72a570cd42c75deaAndreas Huber return mMediaPlayer.getDuration(); 7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 755585c07e9ac19060bb242067a72a570cd42c75deaAndreas Huber 756585c07e9ac19060bb242067a72a570cd42c75deaAndreas Huber return -1; 7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 758256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 75913bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen @Override 7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getCurrentPosition() { 761fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong if (isInPlaybackState()) { 7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mMediaPlayer.getCurrentPosition(); 7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 766256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 76713bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen @Override 7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void seekTo(int msec) { 769fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong if (isInPlaybackState()) { 7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaPlayer.seekTo(msec); 771fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mSeekWhenPrepared = 0; 7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSeekWhenPrepared = msec; 7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 775256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber } 776256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 77713bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen @Override 7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isPlaying() { 779fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong return isInPlaybackState() && mMediaPlayer.isPlaying(); 7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 781256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 78213bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen @Override 7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getBufferPercentage() { 7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMediaPlayer != null) { 7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mCurrentBufferPercentage; 7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 789fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong 790fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong private boolean isInPlaybackState() { 791fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong return (mMediaPlayer != null && 792fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mCurrentState != STATE_ERROR && 793fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mCurrentState != STATE_IDLE && 794fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mCurrentState != STATE_PREPARING); 795fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong } 796c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen 79713bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen @Override 798c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen public boolean canPause() { 799c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen return mCanPause; 800c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen } 801c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen 80213bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen @Override 803c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen public boolean canSeekBackward() { 804c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen return mCanSeekBack; 805c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen } 806c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen 80713bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen @Override 808c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen public boolean canSeekForward() { 809c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen return mCanSeekForward; 810c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen } 81113bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen 81213bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen @Override 81313bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen public int getAudioSessionId() { 81413bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen if (mAudioSession == 0) { 81513bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen MediaPlayer foo = new MediaPlayer(); 81613bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen mAudioSession = foo.getAudioSessionId(); 81713bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen foo.release(); 81813bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen } 81913bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen return mAudioSession; 82013bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen } 821de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette 822de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette @Override 823d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette protected void onAttachedToWindow() { 824d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette super.onAttachedToWindow(); 825de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette 826d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (mSubtitleWidget != null) { 827d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mSubtitleWidget.onAttachedToWindow(); 828de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette } 829de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette } 830de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette 831de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette @Override 832d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette protected void onDetachedFromWindow() { 833d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette super.onDetachedFromWindow(); 834de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette 835d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (mSubtitleWidget != null) { 836d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mSubtitleWidget.onDetachedFromWindow(); 837de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette } 838de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette } 839de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette 840d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette @Override 841d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 842d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette super.onLayout(changed, left, top, right, bottom); 843de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette 844d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (mSubtitleWidget != null) { 845d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette measureAndLayoutSubtitleWidget(); 846de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette } 847de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette } 848de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette 849d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette @Override 850d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void draw(Canvas canvas) { 851d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette super.draw(canvas); 852de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette 853d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (mSubtitleWidget != null) { 854d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int saveCount = canvas.save(); 855d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette canvas.translate(getPaddingLeft(), getPaddingTop()); 856d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mSubtitleWidget.draw(canvas); 857d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette canvas.restoreToCount(saveCount); 858de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette } 859de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette } 860de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette 861de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette /** 862de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette * Forces a measurement and layout pass for all overlaid views. 863de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette * 864d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * @see #setSubtitleWidget(RenderingWidget) 865de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette */ 866d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private void measureAndLayoutSubtitleWidget() { 867d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int width = getWidth() - getPaddingLeft() - getPaddingRight(); 868d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int height = getHeight() - getPaddingTop() - getPaddingBottom(); 869de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette 870d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mSubtitleWidget.setSize(width, height); 871de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette } 872484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar 873484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar /** @hide */ 874484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar @Override 875d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void setSubtitleWidget(RenderingWidget subtitleWidget) { 876d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (mSubtitleWidget == subtitleWidget) { 877484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar return; 878484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar } 879484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar 880d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final boolean attachedToWindow = isAttachedToWindow(); 881d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (mSubtitleWidget != null) { 882d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (attachedToWindow) { 883d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mSubtitleWidget.onDetachedFromWindow(); 884d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 885d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 886d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mSubtitleWidget.setOnChangedListener(null); 887484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar } 888d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 889d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mSubtitleWidget = subtitleWidget; 890d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 891d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (subtitleWidget != null) { 892d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (mSubtitlesChangedListener == null) { 893d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mSubtitlesChangedListener = new RenderingWidget.OnChangedListener() { 894d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette @Override 895d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void onChanged(RenderingWidget renderingWidget) { 896d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette invalidate(); 897d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 898d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette }; 899d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 900d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 901d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setWillNotDraw(false); 902d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette subtitleWidget.setOnChangedListener(mSubtitlesChangedListener); 903d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 904d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (attachedToWindow) { 905d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette subtitleWidget.onAttachedToWindow(); 906d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette requestLayout(); 907d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 908d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } else { 909d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setWillNotDraw(true); 910484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar } 911484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar 912d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette invalidate(); 913d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 91429f5183794efd58a3442aedcf829e3dbcd3fd867Lajos Molnar 91529f5183794efd58a3442aedcf829e3dbcd3fd867Lajos Molnar /** @hide */ 91629f5183794efd58a3442aedcf829e3dbcd3fd867Lajos Molnar @Override 91729f5183794efd58a3442aedcf829e3dbcd3fd867Lajos Molnar public Looper getSubtitleLooper() { 91829f5183794efd58a3442aedcf829e3dbcd3fd867Lajos Molnar return Looper.getMainLooper(); 91929f5183794efd58a3442aedcf829e3dbcd3fd867Lajos Molnar } 9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 921