今天终于把这个给调通了。怪自己太笨。留着
我把三个主要的类公布:先是MediaController
/* * Copyright (C) 2006 The Android Open Source Project * Copyright (C) 2013 YIXIA.COM * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.widget; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.content.Context; import android.graphics.Rect; import android.media.AudioManager; import android.os.Build; import android.os.Handler; import android.os.Message; import android.util.AttributeSet; import android.view.Gravity; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.WindowManager; import android.widget.FrameLayout; import android.widget.ImageButton; import android.widget.PopupWindow; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.TextView; import java.lang.reflect.Method; import com.android.widget.OutlineTextView; import com.example.revideoview.R; //import io.vov.vitamio.utils.Log; /** * 针对普通播放的MediaController * * @author Catherine * */ public class MediaController extends FrameLayout { private static final int sDefaultTimeout = 3000; private static final int FADE_OUT = 1; private static final int SHOW_PROGRESS = 2; private MediaPlayerControl mPlayer; private Context mContext; private PopupWindow mWindow; private int mAnimStyle; private View mAnchor; private View mRoot; private SeekBar mProgress; private TextView mEndTime, mCurrentTime; private TextView mFileName; private OutlineTextView mInfoView; private String mTitle; private long mDuration; private boolean mShowing; private boolean mDragging; private boolean mInstantSeeking = true; private boolean mFromXml = false; private ImageButton mPauseButton; private AudioManager mAM; private OnShownListener mShownListener; private OnHiddenListener mHiddenListener; @SuppressLint("HandlerLeak") private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { long pos; switch (msg.what) { case FADE_OUT: hide(); break; case SHOW_PROGRESS: pos = setProgress(); if (!mDragging && mShowing) { msg = obtainMessage(SHOW_PROGRESS); sendMessageDelayed(msg, 1000 - (pos % 1000)); updatePausePlay(); } break; } } }; private View.OnClickListener mPauseListener = new View.OnClickListener() { public void onClick(View v) { System.out.println("dot the pause"); doPauseResume(); show(sDefaultTimeout); } }; private OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() { public void onStartTrackingTouch(SeekBar bar) { mDragging = true; show(3600000); mHandler.removeMessages(SHOW_PROGRESS); if (mInstantSeeking) mAM.setStreamMute(AudioManager.STREAM_MUSIC, true); if (mInfoView != null) { mInfoView.setText(""); mInfoView.setVisibility(View.VISIBLE); } } public void onProgressChanged(SeekBar bar, int progress, boolean fromuser) { if (!fromuser) return; long newposition = (mDuration * progress) / 1000; String time = StringTools.generateTime(newposition); if (mInstantSeeking) mPlayer.seekTo(newposition); if (mInfoView != null) mInfoView.setText(time); if (mCurrentTime != null) mCurrentTime.setText(time); } public void onStopTrackingTouch(SeekBar bar) { if (!mInstantSeeking) mPlayer.seekTo((mDuration * bar.getProgress()) / 1000); if (mInfoView != null) { mInfoView.setText(""); mInfoView.setVisibility(View.GONE); } show(sDefaultTimeout); mHandler.removeMessages(SHOW_PROGRESS); mAM.setStreamMute(AudioManager.STREAM_MUSIC, false); mDragging = false; mHandler.sendEmptyMessageDelayed(SHOW_PROGRESS, 1000); } }; public MediaController(Context context, AttributeSet attrs) { super(context, attrs); mRoot = this; mFromXml = true; initController(context); } public MediaController(Context context) { super(context); if (!mFromXml && initController(context)) initFloatingWindow(); } private boolean initController(Context context) { mContext = context; mAM = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); return true; } @Override public void onFinishInflate() { if (mRoot != null) initControllerView(mRoot); } private void initFloatingWindow() { mWindow = new PopupWindow(mContext); mWindow.setFocusable(false); mWindow.setBackgroundDrawable(null); mWindow.setOutsideTouchable(true); mAnimStyle = android.R.style.Animation; } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) public void setWindowLayoutType() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { try { mAnchor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); Method setWindowLayoutType = PopupWindow.class.getMethod( "setWindowLayoutType", new Class[] { int.class }); setWindowLayoutType .invoke(mWindow, WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG); } catch (Exception e) { // Log.e("setWindowLayoutType", e); } } } /** * Set the view that acts as the anchor for the control view. This can for * example be a VideoView, or your Activity's main view. * * @param view * The view to which to anchor the controller when it is visible. */ public void setAnchorView(View view) { mAnchor = view; if (!mFromXml) { removeAllViews(); mRoot = makeControllerView(); mWindow.setContentView(mRoot); mWindow.setWidth(LayoutParams.MATCH_PARENT); mWindow.setHeight(LayoutParams.WRAP_CONTENT); } initControllerView(mRoot); } /** * Create the view that holds the widgets that control playback. Derived * classes can override this to create their own. * * @return The controller view. */ protected View makeControllerView() { return ((LayoutInflater) mContext .getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate( R.layout.mediacontroller, this); } private void initControllerView(View v) { mPauseButton = (ImageButton) v .findViewById(R.id.mediacontroller_play_pause); if (mPauseButton != null) { mPauseButton.requestFocus(); mPauseButton.setOnClickListener(mPauseListener); } mProgress = (SeekBar) v.findViewById(R.id.mediacontroller_seekbar); if (mProgress != null) { if (mProgress instanceof SeekBar) { SeekBar seeker = (SeekBar) mProgress; seeker.setOnSeekBarChangeListener(mSeekListener); seeker.setThumbOffset(1); } mProgress.setMax(1000); } mEndTime = (TextView) v.findViewById(R.id.mediacontroller_time_total); mCurrentTime = (TextView) v .findViewById(R.id.mediacontroller_time_current); mFileName = (TextView) v.findViewById(R.id.mediacontroller_file_name); if (mFileName != null) mFileName.setText(mTitle); } public void setMediaPlayer(MediaPlayerControl player) { mPlayer = player; updatePausePlay(); } /** * Control the action when the seekbar dragged by user * * @param seekWhenDragging * True the media will seek periodically */ public void setInstantSeeking(boolean seekWhenDragging) { mInstantSeeking = seekWhenDragging; } public void show() { show(sDefaultTimeout); } /** * Set the content of the file_name TextView * * @param name */ public void setFileName(String name) { mTitle = name; if (mFileName != null) mFileName.setText(mTitle); } /** * Set the View to hold some information when interact with the * MediaController * * @param v */ public void setInfoView(OutlineTextView v) { mInfoView = v; } private void disableUnsupportedButtons() { try { if (mPauseButton != null && !mPlayer.canPause()) mPauseButton.setEnabled(true); } catch (IncompatibleClassChangeError ex) { } } /** * <p> * Change the animation style resource for this controller. * </p> * <p/> * <p> * If the controller is showing, calling this method will take effect only * the next time the controller is shown. * </p> * * @param animationStyle * animation style to use when the controller appears and * disappears. Set to -1 for the default animation, 0 for no * animation, or a resource identifier for an explicit animation. */ public void setAnimationStyle(int animationStyle) { mAnimStyle = animationStyle; } /** * Show the controller on screen. It will go away automatically after * 'timeout' milliseconds of inactivity. * * @param timeout * The timeout in milliseconds. Use 0 to show the controller * until hide() is called. */ public void show(int timeout) { if (!mShowing && mAnchor != null && mAnchor.getWindowToken() != null) { if (mPauseButton != null) mPauseButton.requestFocus(); disableUnsupportedButtons(); if (mFromXml) { setVisibility(View.VISIBLE); } else { int[] location = new int[2]; mAnchor.getLocationOnScreen(location); Rect anchorRect = new Rect(location[0], location[1], location[0] + mAnchor.getWidth(), location[1] + mAnchor.getHeight()); mWindow.setAnimationStyle(mAnimStyle); setWindowLayoutType(); mWindow.showAtLocation(mAnchor, Gravity.NO_GRAVITY, anchorRect.left, anchorRect.bottom); } mShowing = true; if (mShownListener != null) mShownListener.onShown(); } updatePausePlay(); mHandler.sendEmptyMessage(SHOW_PROGRESS); if (timeout != 0) { mHandler.removeMessages(FADE_OUT); mHandler.sendMessageDelayed(mHandler.obtainMessage(FADE_OUT), timeout); } } public boolean isShowing() { return mShowing; } public void hide() { if (mAnchor == null) return; if (mShowing) { try { mHandler.removeMessages(SHOW_PROGRESS); if (mFromXml) setVisibility(View.GONE); else mWindow.dismiss(); } catch (IllegalArgumentException ex) { // Log.d("MediaController already removed"); } mShowing = false; if (mHiddenListener != null) mHiddenListener.onHidden(); } } public void setOnShownListener(OnShownListener l) { mShownListener = l; } public void setOnHiddenListener(OnHiddenListener l) { mHiddenListener = l; } private long setProgress() { if (mPlayer == null || mDragging) return 0; long position = mPlayer.getCurrentPosition(); long duration = mPlayer.getDuration(); if (mProgress != null) { if (duration > 0) { long pos = 1000L * position / duration; mProgress.setProgress((int) pos); } int percent = mPlayer.getBufferPercentage(); mProgress.setSecondaryProgress(percent * 10); } mDuration = duration; if (mEndTime != null) mEndTime.setText(StringTools.generateTime(mDuration)); if (mCurrentTime != null) mCurrentTime.setText(StringTools.generateTime(position)); return position; } @Override public boolean onTouchEvent(MotionEvent event) { show(sDefaultTimeout); return true; } @Override public boolean onTrackballEvent(MotionEvent ev) { show(sDefaultTimeout); return false; } @Override public boolean dispatchKeyEvent(KeyEvent event) { System.out.println("this is dispatchKeyEvent"); int keyCode = event.getKeyCode(); if (event.getRepeatCount() == 0 && (keyCode == KeyEvent.KEYCODE_HEADSETHOOK || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || keyCode == KeyEvent.KEYCODE_SPACE)) { doPauseResume(); show(sDefaultTimeout); if (mPauseButton != null) mPauseButton.requestFocus(); return true; } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP) { if (mPlayer.isPlaying()) { mPlayer.pause(); updatePausePlay(); } return true; } else if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU) { hide(); return true; } else { show(sDefaultTimeout); } return super.dispatchKeyEvent(event); } private void updatePausePlay() { if (mRoot == null || mPauseButton == null) return; if (mPlayer.isPlaying()) mPauseButton .setImageResource(R.drawable.mediacontroller_pause_button); else mPauseButton .setImageResource(R.drawable.mediacontroller_play_button); } private void doPauseResume() { if (mPlayer.isPlaying()) mPlayer.pause(); else mPlayer.start(); updatePausePlay(); } @Override public void setEnabled(boolean enabled) { if (mPauseButton != null) mPauseButton.setEnabled(enabled); if (mProgress != null) mProgress.setEnabled(enabled); disableUnsupportedButtons(); super.setEnabled(enabled); } public interface OnShownListener { public void onShown(); } public interface OnHiddenListener { public void onHidden(); } public interface MediaPlayerControl { void start(); void pause(); long getDuration(); long getCurrentPosition(); void seekTo(long pos); boolean isPlaying(); int getBufferPercentage(); boolean canPause(); boolean canSeekBackward(); boolean canSeekForward(); } }
package com.android.widget; import java.io.IOException; import com.android.widget.CustomProgressDialog; import com.android.widget.MediaController.MediaPlayerControl; import android.content.Context; import android.content.res.Resources; import android.graphics.Rect; import android.media.AudioManager; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; import android.media.MediaPlayer.OnErrorListener; import android.util.AttributeSet; import android.view.Gravity; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.view.ViewGroup.LayoutParams; import android.widget.FrameLayout; /** * 针对普通播放的VideoView * * @author Catherine * */ public class VideoView extends SurfaceView implements MediaPlayerControl, View.OnClickListener { private Context mContext; private String mUri = ""; private int mDuration; // All the stuff we need for playing and showing a video private SurfaceHolder mSurfaceHolder = null; private MediaPlayer mMediaPlayer = null; private boolean mIsPrepared; public static int mVideoWidth; public static int mVideoHeight; private int mSurfaceWidth; private int mSurfaceHeight; private MediaController mMediaController; public OnCompletionListener mOnCompletionListener; private MediaPlayer.OnPreparedListener mOnPreparedListener; private int mCurrentBufferPercentage; private OnErrorListener mOnErrorListener; private boolean mStartWhenPrepared; private int mSeekWhenPrepared; private MySizeChangeLinstener mMyChangeLinstener; public int getVideoWidth() { return mVideoWidth; } public int getVideoHeight() { return mVideoHeight; } public void setVideoScale(int width, int height) { LayoutParams lp = getLayoutParams(); lp.height = height; lp.width = width; setLayoutParams(lp); } public interface MySizeChangeLinstener { public void doMyThings(); } public void setMySizeChangeLinstener(MySizeChangeLinstener l) { mMyChangeLinstener = l; } public VideoView(Context context) { super(context); mContext = context; initVideoView(); } public VideoView(Context context, AttributeSet attrs) { this(context, attrs, 0); mContext = context; initVideoView(); } public VideoView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); mContext = context; initVideoView(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // Log.i("@@@@", "onMeasure"); int width = getDefaultSize(mVideoWidth, widthMeasureSpec); int height = getDefaultSize(mVideoHeight, heightMeasureSpec); setMeasuredDimension(width, height); } public void setVideofullScale(int width, int height) { FrameLayout.LayoutParams lp = (android.widget.FrameLayout.LayoutParams) getLayoutParams(); lp.height = height; lp.width = width; lp.setMargins(0, 0, 0, 0); setLayoutParams(lp); getHolder().setFixedSize(width, height); } public void setVideoDefaultScale(int width, int height) { FrameLayout.LayoutParams lp = (android.widget.FrameLayout.LayoutParams) getLayoutParams(); lp.height = height; lp.width = width; lp.setMargins(258, 85, 0, 0); setLayoutParams(lp); getHolder().setFixedSize(width, height); } public int resolveAdjustedSize(int desiredSize, int measureSpec) { int result = desiredSize; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); switch (specMode) { case MeasureSpec.UNSPECIFIED: result = desiredSize; break; case MeasureSpec.AT_MOST: result = Math.min(desiredSize, specSize); break; case MeasureSpec.EXACTLY: // No choice. Do what we are told. result = specSize; break; } return result; } private CustomProgressDialog dialog; private WindowManager wm; private void initVideoView() { mVideoWidth = 0; mVideoHeight = 0; getHolder().addCallback(mSHCallback); getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); setFocusable(true); setFocusableInTouchMode(true); requestFocus(); dialog = new CustomProgressDialog(mContext); } public void setVideoPath(String path) { setVideoURI(path); } public void setVideoURI(String uri) { mUri = uri; mStartWhenPrepared = false; mSeekWhenPrepared = 0; openVideo(); requestLayout(); invalidate(); } public void stopPlayback() { if (mMediaPlayer != null) { mMediaPlayer.stop(); mMediaPlayer.release(); mMediaPlayer = null; } } private void openVideo() { if (mUri == null || mSurfaceHolder == null) { return; } if (mMediaPlayer != null) { mMediaPlayer.reset(); mMediaPlayer.release(); mMediaPlayer = null; } try { mMediaPlayer = new MediaPlayer(); mMediaPlayer.setOnPreparedListener(mPreparedListener); mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener); mMediaPlayer.setOnInfoListener(mInfoListener); mIsPrepared = false; mDuration = -1; mMediaPlayer.setOnCompletionListener(mCompletionListener); mMediaPlayer.setOnErrorListener(mErrorListener); mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener); mCurrentBufferPercentage = 0; mMediaPlayer.setDataSource(mUri); mMediaPlayer.setDisplay(mSurfaceHolder); mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mMediaPlayer.setScreenOnWhilePlaying(true); mMediaPlayer.prepareAsync(); attachMediaController(); } catch (IOException ex) { return; } catch (IllegalArgumentException ex) { return; } } MediaPlayer.OnInfoListener mInfoListener = new MediaPlayer.OnInfoListener() { @Override public boolean onInfo(MediaPlayer mp, int what, int extra) { WindowManager.LayoutParams params = new WindowManager.LayoutParams(); params.gravity = Gravity.CENTER; params.width = LayoutParams.WRAP_CONTENT; params.height = LayoutParams.WRAP_CONTENT; switch (what) { case MediaPlayer.MEDIA_INFO_BUFFERING_START: if (dialog != null && !dialog.isShowing()) { dialog.show(); } break; case MediaPlayer.MEDIA_INFO_BUFFERING_END: if (dialog != null && dialog.isShowing()) { dialog.cancel(); } break; case MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START: if (dialog != null && dialog.isShowing()) { dialog.cancel(); } break; } return true; } }; public void setMediaController(MediaController controller) { if (mMediaController != null) { mMediaController.hide(); } mMediaController = controller; attachMediaController(); } private void attachMediaController() { if (mMediaPlayer != null && mMediaController != null) { mMediaController.setMediaPlayer(this); View anchorView = this.getParent() instanceof View ? (View) this .getParent() : this; mMediaController.setAnchorView(anchorView); mMediaController.setEnabled(mIsPrepared); } } MediaPlayer.OnVideoSizeChangedListener mSizeChangedListener = new MediaPlayer.OnVideoSizeChangedListener() { public void onVideoSizeChanged(MediaPlayer mp, int width, int height) { mVideoWidth = mp.getVideoWidth(); mVideoHeight = mp.getVideoHeight(); if (mMyChangeLinstener != null) { mMyChangeLinstener.doMyThings(); } if (mVideoWidth != 0 && mVideoHeight != 0) { getHolder().setFixedSize(mVideoWidth, mVideoHeight); } } }; MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener() { public void onPrepared(MediaPlayer mp) { // briefly show the mediacontroller mIsPrepared = true; if (mOnPreparedListener != null) { mOnPreparedListener.onPrepared(mMediaPlayer); } if (mMediaController != null) { mMediaController.setEnabled(true); } mVideoWidth = mp.getVideoWidth(); mVideoHeight = mp.getVideoHeight(); if (mVideoWidth != 0 && mVideoHeight != 0) { // Log.i("@@@@", "video size: " + mVideoWidth +"/"+ // mVideoHeight); getHolder().setFixedSize(mVideoWidth, mVideoHeight); if (mSurfaceWidth == mVideoWidth && mSurfaceHeight == mVideoHeight) { // We didn't actually change the size (it was already at the // size // we need), so we won't get a "surface changed" callback, // so // start the video here instead of in the callback. if (mSeekWhenPrepared != 0) { mMediaPlayer.seekTo(mSeekWhenPrepared); mSeekWhenPrepared = 0; } if (mStartWhenPrepared) { mMediaPlayer.start(); mStartWhenPrepared = false; if (mMediaController != null) { mMediaController.show(); } } else if (!isPlaying() && (mSeekWhenPrepared != 0 || getCurrentPosition() > 0)) { if (mMediaController != null) { // Show the media controls when we're paused into a // video and make 'em stick. mMediaController.show(0); } } } } else { // We don't know the video size yet, but should start anyway. // The video size might be reported to us later. if (mSeekWhenPrepared != 0) { mMediaPlayer.seekTo(mSeekWhenPrepared); mSeekWhenPrepared = 0; } if (mStartWhenPrepared) { mMediaPlayer.start(); mStartWhenPrepared = false; } } } }; private MediaPlayer.OnCompletionListener mCompletionListener = new MediaPlayer.OnCompletionListener() { public void onCompletion(MediaPlayer mp) { if (mMediaController != null) { mMediaController.hide(); } if (mOnCompletionListener != null) { mOnCompletionListener.onCompletion(mMediaPlayer); } } }; private MediaPlayer.OnErrorListener mErrorListener = new MediaPlayer.OnErrorListener() { public boolean onError(MediaPlayer mp, int framework_err, int impl_err) { if (mMediaController != null) { mMediaController.hide(); } /* If an error handler has been supplied, use it and finish. */ if (mOnErrorListener != null) { if (mOnErrorListener.onError(mMediaPlayer, framework_err, impl_err)) { return true; } } if (getWindowToken() != null) { Resources r = mContext.getResources(); int messageId; } return true; } }; private MediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener = new MediaPlayer.OnBufferingUpdateListener() { public void onBufferingUpdate(MediaPlayer mp, int percent) { mCurrentBufferPercentage = percent; } }; /** * Register a callback to be invoked when the media file is loaded and ready * to go. * * @param l * The callback that will be run */ public void setOnPreparedListener(MediaPlayer.OnPreparedListener l) { mOnPreparedListener = l; } /** * Register a callback to be invoked when the end of a media file has been * reached during playback. * * @param l * The callback that will be run */ public void setOnCompletionListener(OnCompletionListener l) { mOnCompletionListener = l; } /** * Register a callback to be invoked when an error occurs during playback or * setup. If no listener is specified, or if the listener returned false, * VideoView will inform the user of any errors. * * @param l * The callback that will be run */ public void setOnErrorListener(OnErrorListener l) { mOnErrorListener = l; } SurfaceHolder.Callback mSHCallback = new SurfaceHolder.Callback() { public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { mSurfaceWidth = w; mSurfaceHeight = h; if (mMediaPlayer != null && mIsPrepared && mVideoWidth == w && mVideoHeight == h) { if (mSeekWhenPrepared != 0) { mMediaPlayer.seekTo(mSeekWhenPrepared); mSeekWhenPrepared = 0; } mMediaPlayer.start(); if (mMediaController != null) { mMediaController.show(); } } } public void surfaceCreated(SurfaceHolder holder) { mSurfaceHolder = holder; openVideo(); } public void surfaceDestroyed(SurfaceHolder holder) { // after we return from this we can't use the surface any more mSurfaceHolder = null; if (mMediaController != null) mMediaController.hide(); if (mMediaPlayer != null) { mMediaPlayer.reset(); mMediaPlayer.release(); mMediaPlayer = null; } } }; @Override public boolean onTouchEvent(MotionEvent ev) { if (mIsPrepared && mMediaPlayer != null && mMediaController != null) { toggleMediaControlsVisiblity(); } return false; } @Override public boolean onTrackballEvent(MotionEvent ev) { if (mIsPrepared && mMediaPlayer != null && mMediaController != null) { toggleMediaControlsVisiblity(); } return false; } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { System.out.println("this is videoview keyevent"); if (mIsPrepared && keyCode != KeyEvent.KEYCODE_BACK && keyCode != KeyEvent.KEYCODE_VOLUME_UP && keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_MENU && keyCode != KeyEvent.KEYCODE_CALL && keyCode != KeyEvent.KEYCODE_ENDCALL && mMediaPlayer != null && mMediaController != null) { if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { if (mMediaPlayer.isPlaying()) { pause(); mMediaController.show(); } else { start(); mMediaController.hide(); } return true; } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP && mMediaPlayer.isPlaying()) { pause(); mMediaController.show(); } else { toggleMediaControlsVisiblity(); } } return false; } private void toggleMediaControlsVisiblity() { // if (mMediaController.isShowing()) { // mMediaController.hide(); // } else { mMediaController.show(); if (mMediaController.isShowing() && mMediaPlayer.isPlaying()) { pause(); } else { start(); } // } } public void start() { if (mMediaPlayer != null && mIsPrepared) { mMediaPlayer.start(); mStartWhenPrepared = false; } else { mStartWhenPrepared = true; } } public void pause() { if (mMediaPlayer != null && mIsPrepared) { if (mMediaPlayer.isPlaying()) { mMediaPlayer.pause(); } } mStartWhenPrepared = false; } public long getDuration() { if (mMediaPlayer != null && mIsPrepared) { if (mDuration > 0) { return mDuration; } mDuration = mMediaPlayer.getDuration(); return mDuration; } mDuration = -1; return mDuration; } public long getCurrentPosition() { if (mMediaPlayer != null && mIsPrepared) { return mMediaPlayer.getCurrentPosition(); } return 0; } public void seekTo(int msec) { if (mMediaPlayer != null && mIsPrepared) { mMediaPlayer.seekTo(msec); } else { mSeekWhenPrepared = msec; } } public boolean isPlaying() { if (mMediaPlayer != null && mIsPrepared) { return mMediaPlayer.isPlaying(); } return false; } public int getBufferPercentage() { if (mMediaPlayer != null) { return mCurrentBufferPercentage; } return 0; } public final static int A_DEFALT = 0; // 原始比例 public final static int A_4X3 = 1; public final static int A_16X9 = 2; public final static int A_RAW = 4; // 原始大小 /** * 全屏状态才可以使用选择比例 * * @param flg */ public void selectScales(int flg) { if (getWindowToken() != null) { Rect rect = new Rect(); getWindowVisibleDisplayFrame(rect); double height = rect.bottom - rect.top; double width = rect.right - rect.left; if (height <= 0.0 || width <= 0.0 || mVideoHeight <= 0.0 || mVideoWidth <= 0.0) { return; } ViewGroup.LayoutParams param = getLayoutParams(); switch (flg) { case A_DEFALT: if (width / height >= mVideoWidth / mVideoHeight) { // // 屏幕 宽了以屏幕高为基础 param.height = (int) height; param.width = (int) (mVideoWidth * height / mVideoHeight); } else { // 屏幕 高了 以宽为基础 param.width = (int) width; param.height = (int) (mVideoHeight * width / mVideoWidth); } setLayoutParams(param); break; case A_4X3: if (width / height >= 4.0 / 3.0) { // 屏幕 宽了 以屏幕高为基础 param.height = (int) height; param.width = (int) (4 * height / 3); } else { // 屏幕 高了 以宽为基础 param.width = (int) width; param.height = (int) (3 * width / 4); } setLayoutParams(param); break; case A_16X9: if (width / height >= 16.0 / 9.0) { // 屏幕 宽了 以屏幕高为基础 param.height = (int) height; param.width = (int) (16 * height / 9); } else { // 屏幕 高了 以宽为基础 param.width = (int) width; param.height = (int) (9 * width / 16); } setLayoutParams(param); break; } } } @Override public boolean canPause() { // TODO Auto-generated method stub return false; } @Override public boolean canSeekBackward() { // TODO Auto-generated method stub return false; } @Override public boolean canSeekForward() { // TODO Auto-generated method stub return false; } @Override public void seekTo(long pos) { if (mMediaPlayer != null && mIsPrepared) { mMediaPlayer.seekTo((int) pos); } else { mSeekWhenPrepared = (int) pos; } } @Override public void onClick(View v) { System.out.println("this is pause"); } }
然后:
自定义的VideoView:
,最后才是主要类“基本上完全了,想要更深,自己DIY即可:
package com.example.revideoview; import java.io.File; import com.android.widget.CustomProgressDialog; import com.android.widget.VodCtrTop; import com.android.widget.MediaController; import com.android.widget.StringTools; import com.android.widget.VideoView; import android.app.Activity; import android.content.Context; import android.graphics.PixelFormat; import android.graphics.drawable.BitmapDrawable; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; import android.media.MediaPlayer.OnErrorListener; import android.media.MediaPlayer.OnPreparedListener; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.MessageQueue.IdleHandler; import android.util.DisplayMetrics; import android.view.Gravity; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.WindowManager; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.PopupWindow; import android.widget.TextView; import android.widget.RelativeLayout.LayoutParams; /** * * @author Catherine * */ public class MainActivity extends Activity { VideoView videoView; MediaController mMediaController; public static MainActivity instance; String title; String numText; int resourceId; String path; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); instance = this; path = Environment.getExternalStorageDirectory() + "/c234b_08_hd_h264_1280_720.mp4"; System.out.println("the path is===>" + path); File file = new File(path); if (file.exists()) { // tvTitle = (TextView) findViewById(R.id.title); videoView = (VideoView) findViewById(R.id.myVideoView); videoView.setOnCompletionListener(new OnCompletionListener() { @Override public void onCompletion(MediaPlayer arg0) { finish(); } }); resourceId = R.drawable.ic_launcher; setDataSource(path); initControlView(); initOperatHintPop(); setMediaPlayer(); Looper.myQueue().addIdleHandler(new IdleHandler() { @Override public boolean queueIdle() { if (ctrTop != null && videoView.isPlaying()) { showCtrTop(); } return false; } }); } else { System.out.println("文件不存在"); } } int btn_judge = 0; private void showCtrTop() { ctrTop.showAtLocation(videoView, Gravity.TOP, 0, 0); ctrTop.setSourceTag(resourceId); if (StringTools.isNullOrEmpty(numText)) { ctrTop.setVideoName(title); } else { ctrTop.setVideoName(title + "(" + numText + ")"); } } VodCtrTop ctrTop; // VodCtrBot ctrBot; private PopupWindow hintPop; private ImageView hintPopImg; private void initControlView() { // ctrBot = new VodCtrBot(this, videoView, new Handler() { // }); ctrTop = new VodCtrTop(this, new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); } }); } private void initOperatHintPop() { hintPop = new PopupWindow(); hintPopImg = new ImageView(this); hintPop.setWindowLayoutMode( android.view.ViewGroup.LayoutParams.MATCH_PARENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT); hintPop.setBackgroundDrawable(new BitmapDrawable()); WindowManager.LayoutParams localLayoutParams = new WindowManager.LayoutParams( android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT); this.hintPopImg.setLayoutParams(localLayoutParams); this.hintPop.setContentView(this.hintPopImg); } private void setMediaPlayer() { // 全屏之后设置进度条 mMediaController = new MediaController(this); videoView.setMediaController(mMediaController); mMediaController.show(); } @Override protected void onResume() { // setDataSource(url, title); super.onResume(); // getCookies(); } public WindowManager windowManager; private Handler handler; private OverlayThread overlayThread; private LinearLayout overlay_ll; public TextView overlay; private Handler mHandler = new Handler() { public void handleMessage(Message msg) { if (msg.what == 0) { } }; }; public void initOverlay() { handler = new Handler(); overlayThread = new OverlayThread(); final LayoutInflater inflater = LayoutInflater.from(instance); overlay_ll = (LinearLayout) inflater.inflate(R.layout.overlay, null); overlay = (TextView) overlay_ll.findViewById(R.id.tv_center); final WindowManager.LayoutParams lp = new WindowManager.LayoutParams( LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_APPLICATION, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, PixelFormat.TRANSLUCENT); windowManager = (WindowManager) instance .getSystemService(Context.WINDOW_SERVICE); windowManager.addView(overlay_ll, lp); // windowManager.addView(overlay_bottom, lp); } /** * 设置overlay不可见 * * */ class OverlayThread implements Runnable { @Override public void run() { overlay_ll.setVisibility(View.GONE); } } public void setDataSource(String url) { playVideo(url); } /** * 获取屏幕的宽和高 */ private void getScreenSize() { DisplayMetrics dm = new DisplayMetrics(); this.getWindowManager().getDefaultDisplay().getMetrics(dm); // VitaVideoView.mVideoWidth = dm.widthPixels; // VitaVideoView.mVideoHeight = dm.heightPixels; } public void playVideo(String url) { Message msg = new Message(); msg.what = 0; // 发送一个隐藏的消息 mHandler.sendMessageDelayed(msg, 5 * 1000); videoView.setVideoPath(url); // 展示一个进度 final CustomProgressDialog dialog = new CustomProgressDialog(instance); if (!dialog.isShowing()) { dialog.show(); } videoView.setOnPreparedListener(new OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { // 取消进度 if (null != dialog) { dialog.cancel(); } // setMediaPlayer(); videoView.start(); } }); videoView.requestFocus(); } int playNum = 0; int titleNum = 0; // protected void exitApp() { UserDialogRunnable userRun = new UserDialogRunnable(); new Handler().postDelayed(userRun, 300L); } class UserDialogRunnable implements Runnable { @Override public void run() { finish(); overridePendingTransition(R.anim.hyperspace_in, R.anim.hyperspace_out); // android.os.Process.killProcess(android.os.Process.myPid()); } } public boolean onKeyDown(int keyCode, KeyEvent event) { System.out.println("this is mainactivity onKeyDown"); switch (keyCode) { case KeyEvent.KEYCODE_DPAD_CENTER: System.out.println("this is mainactivity keyevent"); // mMediaController.show(); if (videoView.isPlaying()) { // 暂停 videoView.pause(); // 展示暂停 hintPopImg.setImageResource(R.drawable.osd_pause); hintPop.showAtLocation(videoView, 17, 0, 0); } else { hintPop.dismiss(); videoView.start(); } break; case KeyEvent.KEYCODE_DPAD_LEFT: // mMediaController.show(); showCtrTop(); // ctrBot.show(); // if (event.getRepeatCount() == 0 && event.getEventTime() > 2 * // 1000) { // videoBack(); // } return false; case KeyEvent.KEYCODE_DPAD_RIGHT: mMediaController.show(); showCtrTop(); return false; case KeyEvent.KEYCODE_BACK: finish(); // return true; case KeyEvent.KEYCODE_MENU: return true; } return false; }; public boolean onTouchEvent(android.view.MotionEvent event) { return false; }; Handler menuHandler = new Handler(); int addOrbackNum = 30 * 1000; // private void videoBack() { // long pos = videoView.getCurrentPosition(); // pos -= addOrbackNum; // videoView.seekTo(pos); // } // // private void videoAdd() { // long pos = videoView.getCurrentPosition(); // pos += addOrbackNum; // videoView.seekTo(pos); // } public void changeScales(int whatMode) { videoView.selectScales(whatMode); } OnErrorListener errorListener = new OnErrorListener() { @Override public boolean onError(MediaPlayer mp, int what, int extra) { return true; } }; protected void onDestroy() { if (ctrTop != null) { ctrTop.dismiss(); } if (hintPop != null) { hintPop.dismiss(); } super.onDestroy(); }; }
具体源码,可以看我的文件里面的“自定义Videoview.jar”
里面也有继承TextView,以及Toast以及Processbar。。。。可参考
当然,这个给出一个灵感链接:http://blog.sina.com.cn/s/blog_640b806d0100q2wo.html#commonComment