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.Intent; 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.Resources; 24de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viveretteimport android.graphics.Canvas; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.media.AudioManager; 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; 34484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnarimport android.media.WebVttRenderer; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Uri; 3629f5183794efd58a3442aedcf829e3dbcd3fd867Lajos Molnarimport android.os.Looper; 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log; 39484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnarimport android.util.Pair; 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.KeyEvent; 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.MotionEvent; 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.SurfaceHolder; 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.SurfaceView; 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.View; 458a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganovimport android.view.accessibility.AccessibilityEvent; 468a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganovimport android.view.accessibility.AccessibilityNodeInfo; 47a8381dfc5ee60dcf99dfd16a840f746cd7cb42abOwen Linimport android.widget.MediaController.MediaPlayerControl; 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException; 50af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnarimport java.io.InputStream; 51256430093679e1d62b54fb0c852126e54d162f6fAndreas Huberimport java.util.Map; 52af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnarimport java.util.Vector; 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Displays a video file. The VideoView class 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * can load images from various sources (such as resources or content 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * providers), takes care of computing its measurement from the video so that 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * it can be used in any layout manager, and provides various display options 597e11b16b9f8896170d492240a5fd50c8bd04105dLajos Molnar * such as scaling and tinting.<p> 607e11b16b9f8896170d492240a5fd50c8bd04105dLajos Molnar * 617e11b16b9f8896170d492240a5fd50c8bd04105dLajos Molnar * <em>Note: VideoView does not retain its full state when going into the 627e11b16b9f8896170d492240a5fd50c8bd04105dLajos Molnar * background.</em> In particular, it does not restore the current play state, 637e11b16b9f8896170d492240a5fd50c8bd04105dLajos Molnar * play position, selected tracks, or any subtitle tracks added via 647e11b16b9f8896170d492240a5fd50c8bd04105dLajos Molnar * {@link #addSubtitleSource addSubtitleSource()}. Applications should 657e11b16b9f8896170d492240a5fd50c8bd04105dLajos Molnar * save and restore these on their own in 667e11b16b9f8896170d492240a5fd50c8bd04105dLajos Molnar * {@link android.app.Activity#onSaveInstanceState} and 677e11b16b9f8896170d492240a5fd50c8bd04105dLajos Molnar * {@link android.app.Activity#onRestoreInstanceState}.<p> 687e11b16b9f8896170d492240a5fd50c8bd04105dLajos Molnar * Also note that the audio session id (from {@link #getAudioSessionId}) may 697e11b16b9f8896170d492240a5fd50c8bd04105dLajos Molnar * change from its previously returned value when the VideoView is restored. 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 71484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnarpublic class VideoView extends SurfaceView 72484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar implements MediaPlayerControl, SubtitleController.Anchor { 73b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project private String TAG = "VideoView"; 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // settable by the client 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Uri mUri; 76256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber private Map<String, String> mHeaders; 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 78fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong // all possible internal states 79fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong private static final int STATE_ERROR = -1; 80fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong private static final int STATE_IDLE = 0; 81fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong private static final int STATE_PREPARING = 1; 82fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong private static final int STATE_PREPARED = 2; 83fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong private static final int STATE_PLAYING = 3; 84fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong private static final int STATE_PAUSED = 4; 85fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong private static final int STATE_PLAYBACK_COMPLETED = 5; 86fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong 87fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong // mCurrentState is a VideoView object's current state. 88fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong // mTargetState is the state that a method caller intends to reach. 89fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong // For instance, regardless the VideoView object's current state, 90fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong // calling pause() intends to bring the object to a target state 91fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong // of STATE_PAUSED. 92fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong private int mCurrentState = STATE_IDLE; 93fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong private int mTargetState = STATE_IDLE; 94fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // All the stuff we need for playing and showing a video 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private SurfaceHolder mSurfaceHolder = null; 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private MediaPlayer mMediaPlayer = null; 9813bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen private int mAudioSession; 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mVideoWidth; 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mVideoHeight; 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mSurfaceWidth; 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mSurfaceHeight; 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private MediaController mMediaController; 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private OnCompletionListener mOnCompletionListener; 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private MediaPlayer.OnPreparedListener mOnPreparedListener; 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mCurrentBufferPercentage; 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private OnErrorListener mOnErrorListener; 108a0ba79473b9067e315155718545103bb4f361873James Dong private OnInfoListener mOnInfoListener; 109fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong private int mSeekWhenPrepared; // recording the seek position while preparing 110c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen private boolean mCanPause; 111c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen private boolean mCanSeekBack; 112c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen private boolean mCanSeekForward; 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 114d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** Subtitle rendering widget overlaid on top of the video. */ 115d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private RenderingWidget mSubtitleWidget; 116de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette 117d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette /** Listener for changes to subtitle data, used to redraw when needed. */ 118d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private RenderingWidget.OnChangedListener mSubtitlesChangedListener; 119de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public VideoView(Context context) { 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super(context); 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project initVideoView(); 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 124256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public VideoView(Context context, AttributeSet attrs) { 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this(context, attrs, 0); 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project initVideoView(); 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 129256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public VideoView(Context context, AttributeSet attrs, int defStyle) { 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super(context, attrs, defStyle); 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project initVideoView(); 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 1370b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen //Log.i("@@@@", "onMeasure(" + MeasureSpec.toString(widthMeasureSpec) + ", " 1380b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen // + MeasureSpec.toString(heightMeasureSpec) + ")"); 1390b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int width = getDefaultSize(mVideoWidth, widthMeasureSpec); 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int height = getDefaultSize(mVideoHeight, heightMeasureSpec); 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mVideoWidth > 0 && mVideoHeight > 0) { 1430b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen 1440b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); 1450b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); 1460b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); 1470b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); 1480b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen 1490b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen if (widthSpecMode == MeasureSpec.EXACTLY && heightSpecMode == MeasureSpec.EXACTLY) { 1500b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen // the size is fixed 1510b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen width = widthSpecSize; 1520b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen height = heightSpecSize; 1530b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen 1540b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen // for compatibility, we adjust size based on aspect ratio 1550b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen if ( mVideoWidth * height < width * mVideoHeight ) { 1560b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen //Log.i("@@@", "image too wide, correcting"); 1570b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen width = height * mVideoWidth / mVideoHeight; 1580b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen } else if ( mVideoWidth * height > width * mVideoHeight ) { 1590b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen //Log.i("@@@", "image too tall, correcting"); 1600b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen height = width * mVideoHeight / mVideoWidth; 1610b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen } 1620b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen } else if (widthSpecMode == MeasureSpec.EXACTLY) { 1630b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen // only the width is fixed, adjust the height to match aspect ratio if possible 1640b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen width = widthSpecSize; 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project height = width * mVideoHeight / mVideoWidth; 1660b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) { 1670b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen // couldn't match aspect ratio within the constraints 1680b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen height = heightSpecSize; 1690b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen } 1700b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen } else if (heightSpecMode == MeasureSpec.EXACTLY) { 1710b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen // only the height is fixed, adjust the width to match aspect ratio if possible 1720b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen height = heightSpecSize; 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project width = height * mVideoWidth / mVideoHeight; 1740b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) { 1750b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen // couldn't match aspect ratio within the constraints 1760b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen width = widthSpecSize; 1770b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen } 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1790b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen // neither the width nor the height are fixed, try to use actual video size 1800b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen width = mVideoWidth; 1810b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen height = mVideoHeight; 1820b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) { 1830b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen // too tall, decrease both width and height 1840b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen height = heightSpecSize; 1850b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen width = height * mVideoWidth / mVideoHeight; 1860b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen } 1870b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) { 1880b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen // too wide, decrease both width and height 1890b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen width = widthSpecSize; 1900b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen height = width * mVideoHeight / mVideoWidth; 1910b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen } 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1930b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen } else { 1940b2d87237ed53b94dc2216a42942d35788d3307bMarco Nelissen // no size yet, just adopt the given spec sizes 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setMeasuredDimension(width, height); 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 198256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 1998a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov @Override 2008a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 2018a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov super.onInitializeAccessibilityEvent(event); 2028a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov event.setClassName(VideoView.class.getName()); 2038a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov } 2048a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov 2058a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov @Override 2068a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 2078a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov super.onInitializeAccessibilityNodeInfo(info); 2088a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov info.setClassName(VideoView.class.getName()); 2098a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov } 2108a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov 211c1374e8e1ae6669ffda874445ebf6b14c49d3a9cMarco Nelissen public int resolveAdjustedSize(int desiredSize, int measureSpec) { 212c1374e8e1ae6669ffda874445ebf6b14c49d3a9cMarco Nelissen return getDefaultSize(desiredSize, measureSpec); 213c1374e8e1ae6669ffda874445ebf6b14c49d3a9cMarco Nelissen } 214c1374e8e1ae6669ffda874445ebf6b14c49d3a9cMarco Nelissen 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void initVideoView() { 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVideoWidth = 0; 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVideoHeight = 0; 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getHolder().addCallback(mSHCallback); 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setFocusable(true); 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setFocusableInTouchMode(true); 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project requestFocus(); 223484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar mPendingSubtitleTracks = new Vector<Pair<InputStream, MediaFormat>>(); 224fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mCurrentState = STATE_IDLE; 225fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mTargetState = STATE_IDLE; 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setVideoPath(String path) { 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setVideoURI(Uri.parse(path)); 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setVideoURI(Uri uri) { 233256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber setVideoURI(uri, null); 234256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber } 235256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 236256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber /** 237256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber * @hide 238256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber */ 239256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber public void setVideoURI(Uri uri, Map<String, String> headers) { 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mUri = uri; 241256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber mHeaders = headers; 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSeekWhenPrepared = 0; 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project openVideo(); 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project requestLayout(); 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project invalidate(); 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 247256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 248af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar /** 249af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * Adds an external subtitle source file (from the provided input stream.) 250af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * 251af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * Note that a single external subtitle source may contain multiple or no 252af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * supported tracks in it. If the source contained at least one track in 253af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * it, one will receive an {@link MediaPlayer#MEDIA_INFO_METADATA_UPDATE} 254af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * info message. Otherwise, if reading the source takes excessive time, 255af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * one will receive a {@link MediaPlayer#MEDIA_INFO_SUBTITLE_TIMED_OUT} 256af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * message. If the source contained no supported track (including an empty 257af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * source file or null input stream), one will receive a {@link 258af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * MediaPlayer#MEDIA_INFO_UNSUPPORTED_SUBTITLE} message. One can find the 259af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * total number of available tracks using {@link MediaPlayer#getTrackInfo()} 260af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * to see what additional tracks become available after this method call. 261af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * 262af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * @param is input stream containing the subtitle data. It will be 263af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * closed by the media framework. 264af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * @param format the format of the subtitle track(s). Must contain at least 265af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * the mime type ({@link MediaFormat#KEY_MIME}) and the 266af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * language ({@link MediaFormat#KEY_LANGUAGE}) of the file. 267af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * If the file itself contains the language information, 268af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar * specify "und" for the language. 269af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar */ 270af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar public void addSubtitleSource(InputStream is, MediaFormat format) { 271af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar if (mMediaPlayer == null) { 272484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar mPendingSubtitleTracks.add(Pair.create(is, format)); 273af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar } else { 274484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar try { 275484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar mMediaPlayer.addSubtitleSource(is, format); 276484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar } catch (IllegalStateException e) { 277484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar mInfoListener.onInfo( 278484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar mMediaPlayer, MediaPlayer.MEDIA_INFO_UNSUPPORTED_SUBTITLE, 0); 279484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar } 280af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar } 281af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar } 282af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar 283484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar private Vector<Pair<InputStream, MediaFormat>> mPendingSubtitleTracks; 284af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void stopPlayback() { 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMediaPlayer != null) { 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaPlayer.stop(); 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaPlayer.release(); 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaPlayer = null; 290fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mCurrentState = STATE_IDLE; 291fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mTargetState = STATE_IDLE; 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void openVideo() { 2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mUri == null || mSurfaceHolder == null) { 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // not ready for playback just yet, will try again later 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 300256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber // Tell the music playback service to pause 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // TODO: these constants need to be published somewhere in the framework. 3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Intent i = new Intent("com.android.music.musicservicecommand"); 3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i.putExtra("command", "pause"); 3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.sendBroadcast(i); 305fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong 306dddeee6f350673b691b1b9001545a27f9c3d19f0Marco Nelissen // we shouldn't clear the target state, because somebody might have 307dddeee6f350673b691b1b9001545a27f9c3d19f0Marco Nelissen // called start() previously 308dddeee6f350673b691b1b9001545a27f9c3d19f0Marco Nelissen release(false); 3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaPlayer = new MediaPlayer(); 311484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar // TODO: create SubtitleController in MediaPlayer, but we need 312484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar // a context for the subtitle renderers 313d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final Context context = getContext(); 314d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final SubtitleController controller = new SubtitleController( 315d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette context, mMediaPlayer.getMediaTimeProvider(), mMediaPlayer); 316d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette controller.registerRenderer(new WebVttRenderer(context)); 317484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar mMediaPlayer.setSubtitleAnchor(controller, this); 318484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar 31913bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen if (mAudioSession != 0) { 32013bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen mMediaPlayer.setAudioSessionId(mAudioSession); 32113bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen } else { 32213bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen mAudioSession = mMediaPlayer.getAudioSessionId(); 32313bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen } 3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaPlayer.setOnPreparedListener(mPreparedListener); 3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener); 3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaPlayer.setOnCompletionListener(mCompletionListener); 3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaPlayer.setOnErrorListener(mErrorListener); 328af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar mMediaPlayer.setOnInfoListener(mInfoListener); 3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener); 3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCurrentBufferPercentage = 0; 331256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber mMediaPlayer.setDataSource(mContext, mUri, mHeaders); 3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaPlayer.setDisplay(mSurfaceHolder); 3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); 3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaPlayer.setScreenOnWhilePlaying(true); 3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaPlayer.prepareAsync(); 336af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar 337484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar for (Pair<InputStream, MediaFormat> pending: mPendingSubtitleTracks) { 338484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar try { 339484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar mMediaPlayer.addSubtitleSource(pending.first, pending.second); 340484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar } catch (IllegalStateException e) { 341484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar mInfoListener.onInfo( 342484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar mMediaPlayer, MediaPlayer.MEDIA_INFO_UNSUPPORTED_SUBTITLE, 0); 343484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar } 344af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar } 345af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar 346dddeee6f350673b691b1b9001545a27f9c3d19f0Marco Nelissen // we don't set the target state here either, but preserve the 347dddeee6f350673b691b1b9001545a27f9c3d19f0Marco Nelissen // target state that was there before. 348fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mCurrentState = STATE_PREPARING; 3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project attachMediaController(); 3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException ex) { 351b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project Log.w(TAG, "Unable to open content: " + mUri, ex); 352fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mCurrentState = STATE_ERROR; 353fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mTargetState = STATE_ERROR; 354020d2e3453b98ae435c4c21b849a2fe0a8842be7Andrei Popescu mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IllegalArgumentException ex) { 357b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project Log.w(TAG, "Unable to open content: " + mUri, ex); 358fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mCurrentState = STATE_ERROR; 359fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mTargetState = STATE_ERROR; 360020d2e3453b98ae435c4c21b849a2fe0a8842be7Andrei Popescu mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); 3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 362af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar } finally { 363484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar mPendingSubtitleTracks.clear(); 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 366256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setMediaController(MediaController controller) { 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMediaController != null) { 3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaController.hide(); 3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaController = controller; 3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project attachMediaController(); 3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void attachMediaController() { 3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMediaPlayer != null && mMediaController != null) { 3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaController.setMediaPlayer(this); 3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View anchorView = this.getParent() instanceof View ? 3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (View)this.getParent() : this; 3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaController.setAnchorView(anchorView); 381fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mMediaController.setEnabled(isInPlaybackState()); 3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 384256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MediaPlayer.OnVideoSizeChangedListener mSizeChangedListener = 3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new MediaPlayer.OnVideoSizeChangedListener() { 3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onVideoSizeChanged(MediaPlayer mp, int width, int height) { 3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVideoWidth = mp.getVideoWidth(); 3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVideoHeight = mp.getVideoHeight(); 3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mVideoWidth != 0 && mVideoHeight != 0) { 3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getHolder().setFixedSize(mVideoWidth, mVideoHeight); 392f5d102ed769ba33cbd48e58c209ece3f1014fe61Teng-Hui Zhu requestLayout(); 3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 396256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener() { 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onPrepared(MediaPlayer mp) { 399fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mCurrentState = STATE_PREPARED; 400c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen 401c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen // Get the capabilities of the player for this stream 402c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen Metadata data = mp.getMetadata(MediaPlayer.METADATA_ALL, 403c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen MediaPlayer.BYPASS_METADATA_FILTER); 404d44d33b01a2125cfa40153e8399dd39908005004Andreas Huber 405d44d33b01a2125cfa40153e8399dd39908005004Andreas Huber if (data != null) { 406d44d33b01a2125cfa40153e8399dd39908005004Andreas Huber mCanPause = !data.has(Metadata.PAUSE_AVAILABLE) 407d44d33b01a2125cfa40153e8399dd39908005004Andreas Huber || data.getBoolean(Metadata.PAUSE_AVAILABLE); 408d44d33b01a2125cfa40153e8399dd39908005004Andreas Huber mCanSeekBack = !data.has(Metadata.SEEK_BACKWARD_AVAILABLE) 409d44d33b01a2125cfa40153e8399dd39908005004Andreas Huber || data.getBoolean(Metadata.SEEK_BACKWARD_AVAILABLE); 410d44d33b01a2125cfa40153e8399dd39908005004Andreas Huber mCanSeekForward = !data.has(Metadata.SEEK_FORWARD_AVAILABLE) 411d44d33b01a2125cfa40153e8399dd39908005004Andreas Huber || data.getBoolean(Metadata.SEEK_FORWARD_AVAILABLE); 412d44d33b01a2125cfa40153e8399dd39908005004Andreas Huber } else { 4132869e952c65548555a9fc197c1f8ceb5b7470462Andreas Huber mCanPause = mCanSeekBack = mCanSeekForward = true; 414d44d33b01a2125cfa40153e8399dd39908005004Andreas Huber } 415c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen 4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mOnPreparedListener != null) { 4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOnPreparedListener.onPrepared(mMediaPlayer); 4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMediaController != null) { 4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaController.setEnabled(true); 4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVideoWidth = mp.getVideoWidth(); 4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVideoHeight = mp.getVideoHeight(); 424c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen 425fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong int seekToPosition = mSeekWhenPrepared; // mSeekWhenPrepared may be changed after seekTo() call 426fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong if (seekToPosition != 0) { 427fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong seekTo(seekToPosition); 428fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong } 4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mVideoWidth != 0 && mVideoHeight != 0) { 4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //Log.i("@@@@", "video size: " + mVideoWidth +"/"+ mVideoHeight); 4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getHolder().setFixedSize(mVideoWidth, mVideoHeight); 4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSurfaceWidth == mVideoWidth && mSurfaceHeight == mVideoHeight) { 4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // We didn't actually change the size (it was already at the size 4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // we need), so we won't get a "surface changed" callback, so 4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // start the video here instead of in the callback. 436fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong if (mTargetState == STATE_PLAYING) { 437aa00e390c191f9b4eaee8ecade88c74571b2b3f3James Dong start(); 4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMediaController != null) { 4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaController.show(); 4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (!isPlaying() && 442fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong (seekToPosition != 0 || getCurrentPosition() > 0)) { 4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMediaController != null) { 4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Show the media controls when we're paused into a video and make 'em stick. 4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaController.show(0); 4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // We don't know the video size yet, but should start anyway. 4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // The video size might be reported to us later. 452fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong if (mTargetState == STATE_PLAYING) { 453aa00e390c191f9b4eaee8ecade88c74571b2b3f3James Dong start(); 4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private MediaPlayer.OnCompletionListener mCompletionListener = 4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new MediaPlayer.OnCompletionListener() { 4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onCompletion(MediaPlayer mp) { 462fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mCurrentState = STATE_PLAYBACK_COMPLETED; 463fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mTargetState = STATE_PLAYBACK_COMPLETED; 4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMediaController != null) { 4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaController.hide(); 4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mOnCompletionListener != null) { 4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOnCompletionListener.onCompletion(mMediaPlayer); 4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 473af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar private MediaPlayer.OnInfoListener mInfoListener = 474af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar new MediaPlayer.OnInfoListener() { 475af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar public boolean onInfo(MediaPlayer mp, int arg1, int arg2) { 476af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar if (mOnInfoListener != null) { 477af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar mOnInfoListener.onInfo(mp, arg1, arg2); 478af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar } 479af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar return true; 480af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar } 481af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar }; 482af309824350d6b2fd38e19ef9104211e5ba132e8Lajos Molnar 4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private MediaPlayer.OnErrorListener mErrorListener = 4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new MediaPlayer.OnErrorListener() { 485c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project public boolean onError(MediaPlayer mp, int framework_err, int impl_err) { 486c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project Log.d(TAG, "Error: " + framework_err + "," + impl_err); 487fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mCurrentState = STATE_ERROR; 488fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mTargetState = STATE_ERROR; 4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMediaController != null) { 4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaController.hide(); 4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* If an error handler has been supplied, use it and finish. */ 4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mOnErrorListener != null) { 495c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (mOnErrorListener.onError(mMediaPlayer, framework_err, impl_err)) { 4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* Otherwise, pop up an error dialog so the user knows that 5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * something bad has happened. Only try and pop up the dialog 5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * if we're attached to a window. When we're going away and no 5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * longer have a window, don't bother showing the user an error. 5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (getWindowToken() != null) { 5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Resources r = mContext.getResources(); 507c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project int messageId; 508c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 509c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (framework_err == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) { 510c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project messageId = com.android.internal.R.string.VideoView_error_text_invalid_progressive_playback; 511c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } else { 512c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project messageId = com.android.internal.R.string.VideoView_error_text_unknown; 513c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project } 514c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project 5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new AlertDialog.Builder(mContext) 516c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project .setMessage(messageId) 5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project .setPositiveButton(com.android.internal.R.string.VideoView_error_button, 5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new DialogInterface.OnClickListener() { 5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onClick(DialogInterface dialog, int whichButton) { 5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* If we get here, there is no onError listener, so 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * at least inform them that the video is over. 5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mOnCompletionListener != null) { 5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOnCompletionListener.onCompletion(mMediaPlayer); 5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }) 5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project .setCancelable(false) 5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project .show(); 5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private MediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener = 5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new MediaPlayer.OnBufferingUpdateListener() { 5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onBufferingUpdate(MediaPlayer mp, int percent) { 5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCurrentBufferPercentage = percent; 5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Register a callback to be invoked when the media file 5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * is loaded and ready to go. 5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param l The callback that will be run 5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setOnPreparedListener(MediaPlayer.OnPreparedListener l) 5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOnPreparedListener = l; 5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Register a callback to be invoked when the end of a media file 5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * has been reached during playback. 5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param l The callback that will be run 5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setOnCompletionListener(OnCompletionListener l) 5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOnCompletionListener = l; 5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Register a callback to be invoked when an error occurs 5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * during playback or setup. If no listener is specified, 5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * or if the listener returned false, VideoView will inform 5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the user of any errors. 5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param l The callback that will be run 5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setOnErrorListener(OnErrorListener l) 5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOnErrorListener = l; 5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 577a0ba79473b9067e315155718545103bb4f361873James Dong /** 578a0ba79473b9067e315155718545103bb4f361873James Dong * Register a callback to be invoked when an informational event 579a0ba79473b9067e315155718545103bb4f361873James Dong * occurs during playback or setup. 580a0ba79473b9067e315155718545103bb4f361873James Dong * 581a0ba79473b9067e315155718545103bb4f361873James Dong * @param l The callback that will be run 582a0ba79473b9067e315155718545103bb4f361873James Dong */ 583a0ba79473b9067e315155718545103bb4f361873James Dong public void setOnInfoListener(OnInfoListener l) { 584a0ba79473b9067e315155718545103bb4f361873James Dong mOnInfoListener = l; 585a0ba79473b9067e315155718545103bb4f361873James Dong } 586a0ba79473b9067e315155718545103bb4f361873James Dong 5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SurfaceHolder.Callback mSHCallback = new SurfaceHolder.Callback() 5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void surfaceChanged(SurfaceHolder holder, int format, 5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int w, int h) 5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSurfaceWidth = w; 5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSurfaceHeight = h; 594fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong boolean isValidState = (mTargetState == STATE_PLAYING); 595fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong boolean hasValidSize = (mVideoWidth == w && mVideoHeight == h); 596fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong if (mMediaPlayer != null && isValidState && hasValidSize) { 5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSeekWhenPrepared != 0) { 598fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong seekTo(mSeekWhenPrepared); 5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 600fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong start(); 6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void surfaceCreated(SurfaceHolder holder) 6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSurfaceHolder = holder; 60769b8d69aadbf0e795f1a1e1adc82c78cf0b9959fAndreas Huber openVideo(); 6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void surfaceDestroyed(SurfaceHolder holder) 6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // after we return from this we can't use the surface any more 6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSurfaceHolder = null; 6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMediaController != null) mMediaController.hide(); 61569b8d69aadbf0e795f1a1e1adc82c78cf0b9959fAndreas Huber release(true); 6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 619fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong /* 620fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong * release the media player in any state 621fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong */ 622dddeee6f350673b691b1b9001545a27f9c3d19f0Marco Nelissen private void release(boolean cleartargetstate) { 623fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong if (mMediaPlayer != null) { 624fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mMediaPlayer.reset(); 625fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mMediaPlayer.release(); 626fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mMediaPlayer = null; 627484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar mPendingSubtitleTracks.clear(); 628fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mCurrentState = STATE_IDLE; 629dddeee6f350673b691b1b9001545a27f9c3d19f0Marco Nelissen if (cleartargetstate) { 630dddeee6f350673b691b1b9001545a27f9c3d19f0Marco Nelissen mTargetState = STATE_IDLE; 631dddeee6f350673b691b1b9001545a27f9c3d19f0Marco Nelissen } 632fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong } 633fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong } 634fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong 6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean onTouchEvent(MotionEvent ev) { 637fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong if (isInPlaybackState() && mMediaController != null) { 6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project toggleMediaControlsVisiblity(); 6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 642256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean onTrackballEvent(MotionEvent ev) { 645fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong if (isInPlaybackState() && mMediaController != null) { 6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project toggleMediaControlsVisiblity(); 6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 650256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean onKeyDown(int keyCode, KeyEvent event) 6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 654fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong boolean isKeyCodeSupported = keyCode != KeyEvent.KEYCODE_BACK && 655fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong keyCode != KeyEvent.KEYCODE_VOLUME_UP && 656fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && 657b0418da0e7594a8c2164a46985c5f1993632e010Jeff Brown keyCode != KeyEvent.KEYCODE_VOLUME_MUTE && 658fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong keyCode != KeyEvent.KEYCODE_MENU && 659fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong keyCode != KeyEvent.KEYCODE_CALL && 660fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong keyCode != KeyEvent.KEYCODE_ENDCALL; 661fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong if (isInPlaybackState() && isKeyCodeSupported && mMediaController != null) { 6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK || 663f8a7ceaef2e7d5cd530c9426bde91b6fa9a40b75Andy Stadler keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) { 6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMediaPlayer.isPlaying()) { 6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pause(); 6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaController.show(); 6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project start(); 6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaController.hide(); 6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 6724d396052deb54399cbadbeb8abd873df6f3af342Jeff Brown } else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) { 673d7db70123fe177e149ae50283e31508f79452f8cChih-Chung Chang if (!mMediaPlayer.isPlaying()) { 6744d396052deb54399cbadbeb8abd873df6f3af342Jeff Brown start(); 6754d396052deb54399cbadbeb8abd873df6f3af342Jeff Brown mMediaController.hide(); 6764d396052deb54399cbadbeb8abd873df6f3af342Jeff Brown } 6774d396052deb54399cbadbeb8abd873df6f3af342Jeff Brown return true; 678256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP 6794d396052deb54399cbadbeb8abd873df6f3af342Jeff Brown || keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) { 680d7db70123fe177e149ae50283e31508f79452f8cChih-Chung Chang if (mMediaPlayer.isPlaying()) { 6814d396052deb54399cbadbeb8abd873df6f3af342Jeff Brown pause(); 6824d396052deb54399cbadbeb8abd873df6f3af342Jeff Brown mMediaController.show(); 6834d396052deb54399cbadbeb8abd873df6f3af342Jeff Brown } 6844d396052deb54399cbadbeb8abd873df6f3af342Jeff Brown return true; 6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project toggleMediaControlsVisiblity(); 6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return super.onKeyDown(keyCode, event); 6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void toggleMediaControlsVisiblity() { 694256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber if (mMediaController.isShowing()) { 6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaController.hide(); 6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaController.show(); 6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 700256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 70113bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen @Override 7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void start() { 703fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong if (isInPlaybackState()) { 704fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mMediaPlayer.start(); 705fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mCurrentState = STATE_PLAYING; 7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 707fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mTargetState = STATE_PLAYING; 7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 709256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 71013bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen @Override 7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void pause() { 712fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong if (isInPlaybackState()) { 7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMediaPlayer.isPlaying()) { 7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaPlayer.pause(); 715fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mCurrentState = STATE_PAUSED; 7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 718fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mTargetState = STATE_PAUSED; 7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 720256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 7212e1818a4d16c3309660f27286c77d8d1eee95a25Gloria Wang public void suspend() { 72269b8d69aadbf0e795f1a1e1adc82c78cf0b9959fAndreas Huber release(false); 7232e1818a4d16c3309660f27286c77d8d1eee95a25Gloria Wang } 7242e1818a4d16c3309660f27286c77d8d1eee95a25Gloria Wang 7252e1818a4d16c3309660f27286c77d8d1eee95a25Gloria Wang public void resume() { 72669b8d69aadbf0e795f1a1e1adc82c78cf0b9959fAndreas Huber openVideo(); 7272e1818a4d16c3309660f27286c77d8d1eee95a25Gloria Wang } 7282e1818a4d16c3309660f27286c77d8d1eee95a25Gloria Wang 72913bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen @Override 7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getDuration() { 731fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong if (isInPlaybackState()) { 732585c07e9ac19060bb242067a72a570cd42c75deaAndreas Huber return mMediaPlayer.getDuration(); 7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 734585c07e9ac19060bb242067a72a570cd42c75deaAndreas Huber 735585c07e9ac19060bb242067a72a570cd42c75deaAndreas Huber return -1; 7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 737256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 73813bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen @Override 7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getCurrentPosition() { 740fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong if (isInPlaybackState()) { 7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mMediaPlayer.getCurrentPosition(); 7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 745256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 74613bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen @Override 7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void seekTo(int msec) { 748fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong if (isInPlaybackState()) { 7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaPlayer.seekTo(msec); 750fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mSeekWhenPrepared = 0; 7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSeekWhenPrepared = msec; 7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 754256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber } 755256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 75613bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen @Override 7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isPlaying() { 758fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong return isInPlaybackState() && mMediaPlayer.isPlaying(); 7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 760256430093679e1d62b54fb0c852126e54d162f6fAndreas Huber 76113bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen @Override 7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getBufferPercentage() { 7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMediaPlayer != null) { 7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mCurrentBufferPercentage; 7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 768fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong 769fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong private boolean isInPlaybackState() { 770fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong return (mMediaPlayer != null && 771fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mCurrentState != STATE_ERROR && 772fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mCurrentState != STATE_IDLE && 773fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong mCurrentState != STATE_PREPARING); 774fdf3ac6cdc370d7dedca463dddd697a1bed79a9cJames Dong } 775c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen 77613bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen @Override 777c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen public boolean canPause() { 778c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen return mCanPause; 779c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen } 780c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen 78113bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen @Override 782c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen public boolean canSeekBackward() { 783c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen return mCanSeekBack; 784c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen } 785c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen 78613bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen @Override 787c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen public boolean canSeekForward() { 788c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen return mCanSeekForward; 789c818b141ee97a7a26fe069456d4b662d06c9eaeaMarco Nelissen } 79013bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen 79113bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen @Override 79213bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen public int getAudioSessionId() { 79313bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen if (mAudioSession == 0) { 79413bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen MediaPlayer foo = new MediaPlayer(); 79513bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen mAudioSession = foo.getAudioSessionId(); 79613bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen foo.release(); 79713bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen } 79813bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen return mAudioSession; 79913bfebd6b70ebfd8ad0d1aa24a92178ebff3565bMarco Nelissen } 800de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette 801de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette @Override 802d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette protected void onAttachedToWindow() { 803d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette super.onAttachedToWindow(); 804de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette 805d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (mSubtitleWidget != null) { 806d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mSubtitleWidget.onAttachedToWindow(); 807de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette } 808de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette } 809de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette 810de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette @Override 811d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette protected void onDetachedFromWindow() { 812d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette super.onDetachedFromWindow(); 813de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette 814d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (mSubtitleWidget != null) { 815d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mSubtitleWidget.onDetachedFromWindow(); 816de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette } 817de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette } 818de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette 819d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette @Override 820d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 821d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette super.onLayout(changed, left, top, right, bottom); 822de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette 823d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (mSubtitleWidget != null) { 824d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette measureAndLayoutSubtitleWidget(); 825de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette } 826de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette } 827de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette 828d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette @Override 829d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void draw(Canvas canvas) { 830d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette super.draw(canvas); 831de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette 832d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (mSubtitleWidget != null) { 833d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int saveCount = canvas.save(); 834d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette canvas.translate(getPaddingLeft(), getPaddingTop()); 835d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mSubtitleWidget.draw(canvas); 836d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette canvas.restoreToCount(saveCount); 837de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette } 838de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette } 839de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette 840de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette /** 841de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette * Forces a measurement and layout pass for all overlaid views. 842de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette * 843d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette * @see #setSubtitleWidget(RenderingWidget) 844de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette */ 845d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette private void measureAndLayoutSubtitleWidget() { 846d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int width = getWidth() - getPaddingLeft() - getPaddingRight(); 847d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final int height = getHeight() - getPaddingTop() - getPaddingBottom(); 848de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette 849d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mSubtitleWidget.setSize(width, height); 850de213f708fc715c85f806fe5f4a7552e8b363bf9Alan Viverette } 851484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar 852484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar /** @hide */ 853484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar @Override 854d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void setSubtitleWidget(RenderingWidget subtitleWidget) { 855d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (mSubtitleWidget == subtitleWidget) { 856484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar return; 857484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar } 858484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar 859d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette final boolean attachedToWindow = isAttachedToWindow(); 860d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (mSubtitleWidget != null) { 861d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (attachedToWindow) { 862d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mSubtitleWidget.onDetachedFromWindow(); 863d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 864d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 865d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mSubtitleWidget.setOnChangedListener(null); 866484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar } 867d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 868d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mSubtitleWidget = subtitleWidget; 869d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 870d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (subtitleWidget != null) { 871d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (mSubtitlesChangedListener == null) { 872d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette mSubtitlesChangedListener = new RenderingWidget.OnChangedListener() { 873d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette @Override 874d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette public void onChanged(RenderingWidget renderingWidget) { 875d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette invalidate(); 876d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 877d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette }; 878d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 879d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 880d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setWillNotDraw(false); 881d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette subtitleWidget.setOnChangedListener(mSubtitlesChangedListener); 882d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette 883d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette if (attachedToWindow) { 884d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette subtitleWidget.onAttachedToWindow(); 885d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette requestLayout(); 886d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 887d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } else { 888d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette setWillNotDraw(true); 889484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar } 890484ff7a92298eaeb5e7edc39895b3a26bed704b3Lajos Molnar 891d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette invalidate(); 892d43daf361e993457e64eeeddab6d1a0ebc828c99Alan Viverette } 89329f5183794efd58a3442aedcf829e3dbcd3fd867Lajos Molnar 89429f5183794efd58a3442aedcf829e3dbcd3fd867Lajos Molnar /** @hide */ 89529f5183794efd58a3442aedcf829e3dbcd3fd867Lajos Molnar @Override 89629f5183794efd58a3442aedcf829e3dbcd3fd867Lajos Molnar public Looper getSubtitleLooper() { 89729f5183794efd58a3442aedcf829e3dbcd3fd867Lajos Molnar return Looper.getMainLooper(); 89829f5183794efd58a3442aedcf829e3dbcd3fd867Lajos Molnar } 8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 900