[教程]共享本机代理给其他设备

由于某些众所周知的原因,本文风格可能有些委婉,还请各位谅解。

     有些代理程序只能给本机使用,比如那些默认地址是localhost:port这样的,要把这种只针对本地的代理共享给其他设备尤其是iphone,touch,ipad,android等移动设备就有些麻烦了。笔者认为其中一个可行的方法就是搭建一个服务器,比如apache之类的,再设法把网络请求通过本机的代理发送(大概就是这个意思吧,我也描述不太好)。但是我只实现了搭建服务器这一块,不知道怎么实现后面那部分,要是高手看到这还请多多指教。

    好了言归正传,既然有难度的弄不明白,总有简单的方法,只需要Charles Web Debugging Proxy这个软件即可实现。这个软件夸Mac Linux Windows三大平台,有30天试用期,希望广大同学多多支持正版。

    软件针对本文的使用方法:菜单:Proxy  >>  External Proxy Settings…,勾选 Use External Proxy Serves,在下面即可设置代理,注意到这里还可以设置socks代理,因此可以通过Charles把代理共享给不支持socks代理的设备。

    在Proxy >> Proxy Settiongs下面可以设置对外的端口,默认是8888,设置好之后就可以把代理共享给其他设备了。

Have Fun

-以上-

Android Dev:VideoView源代码浅析及拓展应用

做Android开发不免要涉及到编写媒体播放器,对于初学者来说用MediaPlayer实现一个具有基本功能的播放器(有进度条,可以通过进度条上的按钮进行控制)还是有一定难度的,幸好Android还提供了一个VideoView类,借用该类可以快速实现简单的媒体播放功能,其源代码如下(单击右边那个箭头展开):

  1. /*
  2.  * Copyright (C) 2006 The Android Open Source Project
  3.  *
  4.  * Licensed under the Apache License, Version 2.0 (the "License");
  5.  * you may not use this file except in compliance with the License.
  6.  * You may obtain a copy of the License at
  7.  *
  8.  *      http://www.apache.org/licenses/LICENSE-2.0
  9.  *
  10.  * Unless required by applicable law or agreed to in writing, software
  11.  * distributed under the License is distributed on an "AS IS" BASIS,
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13.  * See the License for the specific language governing permissions and
  14.  * limitations under the License.
  15.  */
  16.  
  17. package android.widget;
  18.  
  19. import android.app.AlertDialog;
  20. import android.content.Context;
  21. import android.content.DialogInterface;
  22. import android.content.Intent;
  23. import android.content.res.Resources;
  24. import android.media.AudioManager;
  25. import android.media.MediaPlayer;
  26. import android.media.Metadata;
  27. import android.media.MediaPlayer.OnCompletionListener;
  28. import android.media.MediaPlayer.OnErrorListener;
  29. import android.net.Uri;
  30. import android.os.PowerManager;
  31. import android.util.AttributeSet;
  32. import android.util.Log;
  33. import android.view.KeyEvent;
  34. import android.view.MotionEvent;
  35. import android.view.SurfaceHolder;
  36. import android.view.SurfaceView;
  37. import android.view.View;
  38. import android.widget.MediaController.*;
  39.  
  40. import java.io.IOException;
  41. import java.util.Map;
  42.  
  43. /**
  44.  * Displays a video file.  The VideoView class
  45.  * can load images from various sources (such as resources or content
  46.  * providers), takes care of computing its measurement from the video so that
  47.  * it can be used in any layout manager, and provides various display options
  48.  * such as scaling and tinting.
  49.  */
  50. public class VideoView extends SurfaceView implements MediaPlayerControl {
  51.     private String TAG = "VideoView";
  52.     // settable by the client
  53.     private Uri         mUri;
  54.     private Map<string, string=""> mHeaders;
  55.     private int         mDuration;
  56.  
  57.     // all possible internal states
  58.     private static final int STATE_ERROR              = -1;
  59.     private static final int STATE_IDLE               = 0;
  60.     private static final int STATE_PREPARING          = 1;
  61.     private static final int STATE_PREPARED           = 2;
  62.     private static final int STATE_PLAYING            = 3;
  63.     private static final int STATE_PAUSED             = 4;
  64.     private static final int STATE_PLAYBACK_COMPLETED = 5;
  65.     private static final int STATE_SUSPEND            = 6;
  66.     private static final int STATE_RESUME             = 7;
  67.     private static final int STATE_SUSPEND_UNSUPPORTED = 8;
  68.  
  69.     // mCurrentState is a VideoView object&#39;s current state.
  70.     // mTargetState is the state that a method caller intends to reach.
  71.     // For instance, regardless the VideoView object&#39;s current state,
  72.     // calling pause() intends to bring the object to a target state
  73.     // of STATE_PAUSED.
  74.     private int mCurrentState = STATE_IDLE;
  75.     private int mTargetState  = STATE_IDLE;
  76.  
  77.     // All the stuff we need for playing and showing a video
  78.     private SurfaceHolder mSurfaceHolder = null;
  79.     private MediaPlayer mMediaPlayer = null;
  80.     private int         mVideoWidth;
  81.     private int         mVideoHeight;
  82.     private int         mSurfaceWidth;
  83.     private int         mSurfaceHeight;
  84.     private MediaController mMediaController;
  85.     private OnCompletionListener mOnCompletionListener;
  86.     private MediaPlayer.OnPreparedListener mOnPreparedListener;
  87.     private int         mCurrentBufferPercentage;
  88.     private OnErrorListener mOnErrorListener;
  89.     private int         mSeekWhenPrepared;  // recording the seek position while preparing
  90.     private boolean     mCanPause;
  91.     private boolean     mCanSeekBack;
  92.     private boolean     mCanSeekForward;
  93.     private int         mStateWhenSuspended;  //state before calling suspend()
  94.  
  95.     public VideoView(Context context) {
  96.         super(context);
  97.         initVideoView();
  98.     }
  99.  
  100.     public VideoView(Context context, AttributeSet attrs) {
  101.         this(context, attrs, 0);
  102.         initVideoView();
  103.     }
  104.  
  105.     public VideoView(Context context, AttributeSet attrs, int defStyle) {
  106.         super(context, attrs, defStyle);
  107.         initVideoView();
  108.     }
  109.  
  110.     @Override
  111.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  112.         //Log.i(&quot;@@@@&quot;, &quot;onMeasure&quot;);
  113.         int width = getDefaultSize(mVideoWidth, widthMeasureSpec);
  114.         int height = getDefaultSize(mVideoHeight, heightMeasureSpec);
  115.         if (mVideoWidth &gt; 0 &amp;&amp; mVideoHeight &gt; 0) {
  116.             if ( mVideoWidth * height  &gt; width * mVideoHeight ) {
  117.                 //Log.i(&quot;@@@&quot;, &quot;image too tall, correcting&quot;);
  118.                 height = width * mVideoHeight / mVideoWidth;
  119.             } else if ( mVideoWidth * height  &lt; width * mVideoHeight ) {
  120.                 //Log.i(&quot;@@@&quot;, &quot;image too wide, correcting&quot;);
  121.                 width = height * mVideoWidth / mVideoHeight;
  122.             } else {
  123.                 //Log.i(&quot;@@@&quot;, &quot;aspect ratio is correct: &quot; +
  124.                         //width+&quot;/&quot;+height+&quot;=&quot;+
  125.                         //mVideoWidth+&quot;/&quot;+mVideoHeight);
  126.             }
  127.         }
  128.         //Log.i(&quot;@@@@@@@@@@&quot;, &quot;setting size: &quot; + width + &#39;x&#39; + height);
  129.         setMeasuredDimension(width, height);
  130.     }
  131.  
  132.     public int resolveAdjustedSize(int desiredSize, int measureSpec) {
  133.         int result = desiredSize;
  134.         int specMode = MeasureSpec.getMode(measureSpec);
  135.         int specSize =  MeasureSpec.getSize(measureSpec);
  136.  
  137.         switch (specMode) {
  138.             case MeasureSpec.UNSPECIFIED:
  139.                 /* Parent says we can be as big as we want. Just don&#39;t be larger
  140.                  * than max size imposed on ourselves.
  141.                  */
  142.                 result = desiredSize;
  143.                 break;
  144.  
  145.             case MeasureSpec.AT_MOST:
  146.                 /* Parent says we can be as big as we want, up to specSize.
  147.                  * Don&#39;t be larger than specSize, and don&#39;t be larger than
  148.                  * the max size imposed on ourselves.
  149.                  */
  150.                 result = Math.min(desiredSize, specSize);
  151.                 break;
  152.  
  153.             case MeasureSpec.EXACTLY:
  154.                 // No choice. Do what we are told.
  155.                 result = specSize;
  156.                 break;
  157.         }
  158.         return result;
  159. }
  160.  
  161.     private void initVideoView() {
  162.         mVideoWidth = 0;
  163.         mVideoHeight = 0;
  164.         getHolder().addCallback(mSHCallback);
  165.         getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
  166.         setFocusable(true);
  167.         setFocusableInTouchMode(true);
  168.         requestFocus();
  169.         mCurrentState = STATE_IDLE;
  170.         mTargetState  = STATE_IDLE;
  171.     }
  172.  
  173.     public void setVideoPath(String path) {
  174.         setVideoURI(Uri.parse(path));
  175.     }
  176.  
  177.     public void setVideoURI(Uri uri) {
  178.         setVideoURI(uri, null);
  179.     }
  180.  
  181.     /**
  182.      * @hide
  183.      */
  184.     public void setVideoURI(Uri uri, Map<string, string=""> headers) {
  185.         mUri = uri;
  186.         mHeaders = headers;
  187.         mSeekWhenPrepared = 0;
  188.         openVideo();
  189.         requestLayout();
  190.         invalidate();
  191.     }
  192.  
  193.     public void stopPlayback() {
  194.         if (mMediaPlayer != null) {
  195.             mMediaPlayer.stop();
  196.             mMediaPlayer.release();
  197.             mMediaPlayer = null;
  198.             mCurrentState = STATE_IDLE;
  199.             mTargetState  = STATE_IDLE;
  200.         }
  201.     }
  202.  
  203.     private void openVideo() {
  204.         if (mUri == null || mSurfaceHolder == null) {
  205.             // not ready for playback just yet, will try again later
  206.             return;
  207.         }
  208.         // Tell the music playback service to pause
  209.         // TODO: these constants need to be published somewhere in the framework.
  210.         Intent i = new Intent(&quot;com.android.music.musicservicecommand&quot;);
  211.         i.putExtra(&quot;command&quot;, &quot;pause&quot;);
  212.         mContext.sendBroadcast(i);
  213.  
  214.         // we shouldn&#39;t clear the target state, because somebody might have
  215.         // called start() previously
  216.         release(false);
  217.         try {
  218.             mMediaPlayer = new MediaPlayer();
  219.             mMediaPlayer.setOnPreparedListener(mPreparedListener);
  220.             mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
  221.             mDuration = -1;
  222.             mMediaPlayer.setOnCompletionListener(mCompletionListener);
  223.             mMediaPlayer.setOnErrorListener(mErrorListener);
  224.             mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
  225.             mCurrentBufferPercentage = 0;
  226.             mMediaPlayer.setDataSource(mContext, mUri, mHeaders);
  227.             mMediaPlayer.setDisplay(mSurfaceHolder);
  228.             mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
  229.             mMediaPlayer.setScreenOnWhilePlaying(true);
  230.             mMediaPlayer.prepareAsync();
  231.             // we don&#39;t set the target state here either, but preserve the
  232.             // target state that was there before.
  233.             mCurrentState = STATE_PREPARING;
  234.             attachMediaController();
  235.         } catch (IOException ex) {
  236.             Log.w(TAG, &quot;Unable to open content: &quot; + mUri, ex);
  237.             mCurrentState = STATE_ERROR;
  238.             mTargetState = STATE_ERROR;
  239.             mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
  240.             return;
  241.         } catch (IllegalArgumentException ex) {
  242.             Log.w(TAG, &quot;Unable to open content: &quot; + mUri, ex);
  243.             mCurrentState = STATE_ERROR;
  244.             mTargetState = STATE_ERROR;
  245.             mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
  246.             return;
  247.         }
  248.     }
  249.  
  250.     public void setMediaController(MediaController controller) {
  251.         if (mMediaController != null) {
  252.             mMediaController.hide();
  253.         }
  254.         mMediaController = controller;
  255.         attachMediaController();
  256.     }
  257.  
  258.     private void attachMediaController() {
  259.         if (mMediaPlayer != null &amp;&amp; mMediaController != null) {
  260.             mMediaController.setMediaPlayer(this);
  261.             View anchorView = this.getParent() instanceof View ?
  262.                     (View)this.getParent() : this;
  263.             mMediaController.setAnchorView(anchorView);
  264.             mMediaController.setEnabled(isInPlaybackState());
  265.         }
  266.     }
  267.  
  268.     MediaPlayer.OnVideoSizeChangedListener mSizeChangedListener =
  269.         new MediaPlayer.OnVideoSizeChangedListener() {
  270.             public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
  271.                 mVideoWidth = mp.getVideoWidth();
  272.                 mVideoHeight = mp.getVideoHeight();
  273.                 if (mVideoWidth != 0 &amp;&amp; mVideoHeight != 0) {
  274.                     getHolder().setFixedSize(mVideoWidth, mVideoHeight);
  275.                 }
  276.             }
  277.     };
  278.  
  279.     MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener() {
  280.         public void onPrepared(MediaPlayer mp) {
  281.             mCurrentState = STATE_PREPARED;
  282.  
  283.             // Get the capabilities of the player for this stream
  284.             Metadata data = mp.getMetadata(MediaPlayer.METADATA_ALL,
  285.                                       MediaPlayer.BYPASS_METADATA_FILTER);
  286.  
  287.             if (data != null) {
  288.                 mCanPause = !data.has(Metadata.PAUSE_AVAILABLE)
  289.                         || data.getBoolean(Metadata.PAUSE_AVAILABLE);
  290.                 mCanSeekBack = !data.has(Metadata.SEEK_BACKWARD_AVAILABLE)
  291.                         || data.getBoolean(Metadata.SEEK_BACKWARD_AVAILABLE);
  292.                 mCanSeekForward = !data.has(Metadata.SEEK_FORWARD_AVAILABLE)
  293.                         || data.getBoolean(Metadata.SEEK_FORWARD_AVAILABLE);
  294.             } else {
  295.                 mCanPause = mCanSeekBack = mCanSeekForward = true;
  296.             }
  297.  
  298.             if (mOnPreparedListener != null) {
  299.                 mOnPreparedListener.onPrepared(mMediaPlayer);
  300.             }
  301.             if (mMediaController != null) {
  302.                 mMediaController.setEnabled(true);
  303.             }
  304.             mVideoWidth = mp.getVideoWidth();
  305.             mVideoHeight = mp.getVideoHeight();
  306.  
  307.             int seekToPosition = mSeekWhenPrepared;  // mSeekWhenPrepared may be changed after seekTo() call
  308.             if (seekToPosition != 0) {
  309.                 seekTo(seekToPosition);
  310.             }
  311.             if (mVideoWidth != 0 &amp;&amp; mVideoHeight != 0) {
  312.                 //Log.i(&quot;@@@@&quot;, &quot;video size: &quot; + mVideoWidth +&quot;/&quot;+ mVideoHeight);
  313.                 getHolder().setFixedSize(mVideoWidth, mVideoHeight);
  314.                 if (mSurfaceWidth == mVideoWidth &amp;&amp; mSurfaceHeight == mVideoHeight) {
  315.                     // We didn&#39;t actually change the size (it was already at the size
  316.                     // we need), so we won&#39;t get a &quot;surface changed&quot; callback, so
  317.                     // start the video here instead of in the callback.
  318.                     if (mTargetState == STATE_PLAYING) {
  319.                         start();
  320.                         if (mMediaController != null) {
  321.                             mMediaController.show();
  322.                         }
  323.                     } else if (!isPlaying() &amp;&amp;
  324.                                (seekToPosition != 0 || getCurrentPosition() &gt; 0)) {
  325.                        if (mMediaController != null) {
  326.                            // Show the media controls when we&#39;re paused into a video and make &#39;em stick.
  327.                            mMediaController.show(0);
  328.                        }
  329.                    }
  330.                 }
  331.             } else {
  332.                 // We don&#39;t know the video size yet, but should start anyway.
  333.                 // The video size might be reported to us later.
  334.                 if (mTargetState == STATE_PLAYING) {
  335.                     start();
  336.                 }
  337.             }
  338.         }
  339.     };
  340.  
  341.     private MediaPlayer.OnCompletionListener mCompletionListener =
  342.         new MediaPlayer.OnCompletionListener() {
  343.         public void onCompletion(MediaPlayer mp) {
  344.             mCurrentState = STATE_PLAYBACK_COMPLETED;
  345.             mTargetState = STATE_PLAYBACK_COMPLETED;
  346.             if (mMediaController != null) {
  347.                 mMediaController.hide();
  348.             }
  349.             if (mOnCompletionListener != null) {
  350.                 mOnCompletionListener.onCompletion(mMediaPlayer);
  351.             }
  352.         }
  353.     };
  354.  
  355.     private MediaPlayer.OnErrorListener mErrorListener =
  356.         new MediaPlayer.OnErrorListener() {
  357.         public boolean onError(MediaPlayer mp, int framework_err, int impl_err) {
  358.             Log.d(TAG, &quot;Error: &quot; + framework_err + &quot;,&quot; + impl_err);
  359.             mCurrentState = STATE_ERROR;
  360.             mTargetState = STATE_ERROR;
  361.             if (mMediaController != null) {
  362.                 mMediaController.hide();
  363.             }
  364.  
  365.             /* If an error handler has been supplied, use it and finish. */
  366.             if (mOnErrorListener != null) {
  367.                 if (mOnErrorListener.onError(mMediaPlayer, framework_err, impl_err)) {
  368.                     return true;
  369.                 }
  370.             }
  371.  
  372.             /* Otherwise, pop up an error dialog so the user knows that
  373.              * something bad has happened. Only try and pop up the dialog
  374.              * if we&#39;re attached to a window. When we&#39;re going away and no
  375.              * longer have a window, don&#39;t bother showing the user an error.
  376.              */
  377.             if (getWindowToken() != null) {
  378.                 Resources r = mContext.getResources();
  379.                 int messageId;
  380.  
  381.                 if (framework_err == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) {
  382.                     messageId = com.android.internal.R.string.VideoView_error_text_invalid_progressive_playback;
  383.                 } else {
  384.                     messageId = com.android.internal.R.string.VideoView_error_text_unknown;
  385.                 }
  386.  
  387.                 new AlertDialog.Builder(mContext)
  388.                         .setTitle(com.android.internal.R.string.VideoView_error_title)
  389.                         .setMessage(messageId)
  390.                         .setPositiveButton(com.android.internal.R.string.VideoView_error_button,
  391.                                 new DialogInterface.OnClickListener() {
  392.                                     public void onClick(DialogInterface dialog, int whichButton) {
  393.                                         /* If we get here, there is no onError listener, so
  394.                                          * at least inform them that the video is over.
  395.                                          */
  396.                                         if (mOnCompletionListener != null) {
  397.                                             mOnCompletionListener.onCompletion(mMediaPlayer);
  398.                                         }
  399.                                     }
  400.                                 })
  401.                         .setCancelable(false)
  402.                         .show();
  403.             }
  404.             return true;
  405.         }
  406.     };
  407.  
  408.     private MediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener =
  409.         new MediaPlayer.OnBufferingUpdateListener() {
  410.         public void onBufferingUpdate(MediaPlayer mp, int percent) {
  411.             mCurrentBufferPercentage = percent;
  412.         }
  413.     };
  414.  
  415.     /**
  416.      * Register a callback to be invoked when the media file
  417.      * is loaded and ready to go.
  418.      *
  419.      * @param l The callback that will be run
  420.      */
  421.     public void setOnPreparedListener(MediaPlayer.OnPreparedListener l)
  422.     {
  423.         mOnPreparedListener = l;
  424.     }
  425.  
  426.     /**
  427.      * Register a callback to be invoked when the end of a media file
  428.      * has been reached during playback.
  429.      *
  430.      * @param l The callback that will be run
  431.      */
  432.     public void setOnCompletionListener(OnCompletionListener l)
  433.     {
  434.         mOnCompletionListener = l;
  435.     }
  436.  
  437.     /**
  438.      * Register a callback to be invoked when an error occurs
  439.      * during playback or setup.  If no listener is specified,
  440.      * or if the listener returned false, VideoView will inform
  441.      * the user of any errors.
  442.      *
  443.      * @param l The callback that will be run
  444.      */
  445.     public void setOnErrorListener(OnErrorListener l)
  446.     {
  447.         mOnErrorListener = l;
  448.     }
  449.  
  450.     SurfaceHolder.Callback mSHCallback = new SurfaceHolder.Callback()
  451.     {
  452.         public void surfaceChanged(SurfaceHolder holder, int format,
  453.                                     int w, int h)
  454.         {
  455.             mSurfaceWidth = w;
  456.             mSurfaceHeight = h;
  457.             boolean isValidState =  (mTargetState == STATE_PLAYING);
  458.             boolean hasValidSize = (mVideoWidth == w &amp;&amp; mVideoHeight == h);
  459.             if (mMediaPlayer != null &amp;&amp; isValidState &amp;&amp; hasValidSize) {
  460.                 if (mSeekWhenPrepared != 0) {
  461.                     seekTo(mSeekWhenPrepared);
  462.                 }
  463.                 start();
  464.                 if (mMediaController != null) {
  465.                     mMediaController.show();
  466.                 }
  467.             }
  468.         }
  469.  
  470.         public void surfaceCreated(SurfaceHolder holder)
  471.         {
  472.             mSurfaceHolder = holder;
  473.             //resume() was called before surfaceCreated()
  474.             if (mMediaPlayer != null &amp;&amp; mCurrentState == STATE_SUSPEND
  475.                    &amp;&amp; mTargetState == STATE_RESUME) {
  476.                 mMediaPlayer.setDisplay(mSurfaceHolder);
  477.                 resume();
  478.             } else {
  479.                 openVideo();
  480.             }
  481.         }
  482.  
  483.         public void surfaceDestroyed(SurfaceHolder holder)
  484.         {
  485.             // after we return from this we can&#39;t use the surface any more
  486.             mSurfaceHolder = null;
  487.             if (mMediaController != null) mMediaController.hide();
  488.             if (mCurrentState != STATE_SUSPEND) {
  489.                 release(true);
  490.             }
  491.         }
  492.     };
  493.  
  494.     /*
  495.      * release the media player in any state
  496.      */
  497.     private void release(boolean cleartargetstate) {
  498.         if (mMediaPlayer != null) {
  499.             mMediaPlayer.reset();
  500.             mMediaPlayer.release();
  501.             mMediaPlayer = null;
  502.             mCurrentState = STATE_IDLE;
  503.             if (cleartargetstate) {
  504.                 mTargetState  = STATE_IDLE;
  505.             }
  506.         }
  507.     }
  508.  
  509.     @Override
  510.     public boolean onTouchEvent(MotionEvent ev) {
  511.         if (isInPlaybackState() &amp;&amp; mMediaController != null) {
  512.             toggleMediaControlsVisiblity();
  513.         }
  514.         return false;
  515.     }
  516.  
  517.     @Override
  518.     public boolean onTrackballEvent(MotionEvent ev) {
  519.         if (isInPlaybackState() &amp;&amp; mMediaController != null) {
  520.             toggleMediaControlsVisiblity();
  521.         }
  522.         return false;
  523.     }
  524.  
  525.     @Override
  526.     public boolean onKeyDown(int keyCode, KeyEvent event)
  527.     {
  528.         boolean isKeyCodeSupported = keyCode != KeyEvent.KEYCODE_BACK &amp;&amp;
  529.                                      keyCode != KeyEvent.KEYCODE_VOLUME_UP &amp;&amp;
  530.                                      keyCode != KeyEvent.KEYCODE_VOLUME_DOWN &amp;&amp;
  531.                                      keyCode != KeyEvent.KEYCODE_MENU &amp;&amp;
  532.                                      keyCode != KeyEvent.KEYCODE_CALL &amp;&amp;
  533.                                      keyCode != KeyEvent.KEYCODE_ENDCALL;
  534.         if (isInPlaybackState() &amp;&amp; isKeyCodeSupported &amp;&amp; mMediaController != null) {
  535.             if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK ||
  536.                     keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) {
  537.                 if (mMediaPlayer.isPlaying()) {
  538.                     pause();
  539.                     mMediaController.show();
  540.                 } else {
  541.                     start();
  542.                     mMediaController.hide();
  543.                 }
  544.                 return true;
  545.             } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP
  546.                     &amp;&amp; mMediaPlayer.isPlaying()) {
  547.                 pause();
  548.                 mMediaController.show();
  549.             } else {
  550.                 toggleMediaControlsVisiblity();
  551.             }
  552.         }
  553.  
  554.         return super.onKeyDown(keyCode, event);
  555.     }
  556.  
  557.     private void toggleMediaControlsVisiblity() {
  558.         if (mMediaController.isShowing()) {
  559.             mMediaController.hide();
  560.         } else {
  561.             mMediaController.show();
  562.         }
  563.     }
  564.  
  565.     public void start() {
  566.         if (isInPlaybackState()) {
  567.             mMediaPlayer.start();
  568.             mCurrentState = STATE_PLAYING;
  569.         }
  570.         mTargetState = STATE_PLAYING;
  571.     }
  572.  
  573.     public void pause() {
  574.         if (isInPlaybackState()) {
  575.             if (mMediaPlayer.isPlaying()) {
  576.                 mMediaPlayer.pause();
  577.                 mCurrentState = STATE_PAUSED;
  578.             }
  579.         }
  580.         mTargetState = STATE_PAUSED;
  581.     }
  582.  
  583.     public void suspend() {
  584.         if (isInPlaybackState()) {
  585.             if (mMediaPlayer.suspend()) {
  586.                 mStateWhenSuspended = mCurrentState;
  587.                 mCurrentState = STATE_SUSPEND;
  588.                 mTargetState = STATE_SUSPEND;
  589.             } else {
  590.                 release(false);
  591.                 mCurrentState = STATE_SUSPEND_UNSUPPORTED;
  592.                 Log.w(TAG, &quot;Unable to suspend video. Release MediaPlayer.&quot;);
  593.             }
  594.         }
  595.     }
  596.  
  597.     public void resume() {
  598.         if (mSurfaceHolder == null &amp;&amp; mCurrentState == STATE_SUSPEND){
  599.             mTargetState = STATE_RESUME;
  600.             return;
  601.         }
  602.         if (mMediaPlayer != null &amp;&amp; mCurrentState == STATE_SUSPEND) {
  603.             if (mMediaPlayer.resume()) {
  604.                 mCurrentState = mStateWhenSuspended;
  605.                 mTargetState = mStateWhenSuspended;
  606.             } else {
  607.                 Log.w(TAG, &quot;Unable to resume video&quot;);
  608.             }
  609.             return;
  610.         }
  611.         if (mCurrentState == STATE_SUSPEND_UNSUPPORTED) {
  612.             openVideo();
  613.         }
  614.     }
  615.  
  616.    // cache duration as mDuration for faster access
  617.     public int getDuration() {
  618.         if (isInPlaybackState()) {
  619.             if (mDuration &gt; 0) {
  620.                 return mDuration;
  621.             }
  622.             mDuration = mMediaPlayer.getDuration();
  623.             return mDuration;
  624.         }
  625.         mDuration = -1;
  626.         return mDuration;
  627.     }
  628.  
  629.     public int getCurrentPosition() {
  630.         if (isInPlaybackState()) {
  631.             return mMediaPlayer.getCurrentPosition();
  632.         }
  633.         return 0;
  634.     }
  635.  
  636.     public void seekTo(int msec) {
  637.         if (isInPlaybackState()) {
  638.             mMediaPlayer.seekTo(msec);
  639.             mSeekWhenPrepared = 0;
  640.         } else {
  641.             mSeekWhenPrepared = msec;
  642.         }
  643.     }
  644.  
  645.     public boolean isPlaying() {
  646.         return isInPlaybackState() &amp;&amp; mMediaPlayer.isPlaying();
  647.     }
  648.  
  649.     public int getBufferPercentage() {
  650.         if (mMediaPlayer != null) {
  651.             return mCurrentBufferPercentage;
  652.         }
  653.         return 0;
  654.     }
  655.  
  656.     private boolean isInPlaybackState() {
  657.         return (mMediaPlayer != null &amp;&amp;
  658.                 mCurrentState != STATE_ERROR &amp;&amp;
  659.                 mCurrentState != STATE_IDLE &amp;&amp;
  660.                 mCurrentState != STATE_PREPARING);
  661.     }
  662.  
  663.     public boolean canPause() {
  664.         return mCanPause;
  665.     }
  666.  
  667.     public boolean canSeekBackward() {
  668.         return mCanSeekBack;
  669.     }
  670.  
  671.     public boolean canSeekForward() {
  672.         return mCanSeekForward;
  673.     }
  674. }
  675. </string,></string,>

继续阅读Android Dev:VideoView源代码浅析及拓展应用