• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 package android.webkit;
3 
4 import android.content.Context;
5 import android.media.MediaPlayer;
6 import android.media.Metadata;
7 import android.util.Log;
8 import android.view.Gravity;
9 import android.view.MotionEvent;
10 import android.view.SurfaceHolder;
11 import android.view.SurfaceView;
12 import android.view.View;
13 import android.view.ViewGroup;
14 import android.webkit.HTML5VideoView;
15 import android.webkit.HTML5VideoViewProxy;
16 import android.widget.FrameLayout;
17 import android.widget.MediaController;
18 import android.widget.MediaController.MediaPlayerControl;
19 
20 
21 /**
22  * @hide This is only used by the browser
23  */
24 public class HTML5VideoFullScreen extends HTML5VideoView
25     implements MediaPlayerControl, MediaPlayer.OnPreparedListener,
26     View.OnTouchListener {
27 
28     // Add this sub-class to handle the resizing when rotating screen.
29     private class VideoSurfaceView extends SurfaceView {
30 
VideoSurfaceView(Context context)31         public VideoSurfaceView(Context context) {
32             super(context);
33         }
34 
35         @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)36         protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
37             int width = getDefaultSize(mVideoWidth, widthMeasureSpec);
38             int height = getDefaultSize(mVideoHeight, heightMeasureSpec);
39             if (mVideoWidth > 0 && mVideoHeight > 0) {
40                 if ( mVideoWidth * height  > width * mVideoHeight ) {
41                     height = width * mVideoHeight / mVideoWidth;
42                 } else if ( mVideoWidth * height  < width * mVideoHeight ) {
43                     width = height * mVideoWidth / mVideoHeight;
44                 }
45             }
46             setMeasuredDimension(width, height);
47         }
48     }
49 
50     // This view will contain the video.
51     private VideoSurfaceView mVideoSurfaceView;
52 
53     // We need the full screen state to decide which surface to render to and
54     // when to create the MediaPlayer accordingly.
55     static final int FULLSCREEN_OFF               = 0;
56     static final int FULLSCREEN_SURFACECREATING   = 1;
57     static final int FULLSCREEN_SURFACECREATED    = 2;
58 
59     private int mFullScreenMode;
60     // The Media Controller only used for full screen mode
61     private MediaController mMediaController;
62 
63     // SurfaceHolder for full screen
64     private SurfaceHolder mSurfaceHolder = null;
65 
66     // Data only for MediaController
67     private boolean mCanSeekBack;
68     private boolean mCanSeekForward;
69     private boolean mCanPause;
70     private int mCurrentBufferPercentage;
71 
72     // The progress view.
73     private static View mProgressView;
74     // The container for the progress view and video view
75     private static FrameLayout mLayout;
76 
77     // The video size will be ready when prepared. Used to make sure the aspect
78     // ratio is correct.
79     private int mVideoWidth;
80     private int mVideoHeight;
81 
82     SurfaceHolder.Callback mSHCallback = new SurfaceHolder.Callback()
83     {
84         public void surfaceChanged(SurfaceHolder holder, int format,
85                                     int w, int h)
86         {
87             if (mPlayer != null && mMediaController != null
88                     && mCurrentState == STATE_PREPARED) {
89                 if (mMediaController.isShowing()) {
90                     // ensure the controller will get repositioned later
91                     mMediaController.hide();
92                 }
93                 mMediaController.show();
94             }
95         }
96 
97         public void surfaceCreated(SurfaceHolder holder)
98         {
99             mSurfaceHolder = holder;
100             mFullScreenMode = FULLSCREEN_SURFACECREATED;
101 
102             prepareForFullScreen();
103         }
104 
105         public void surfaceDestroyed(SurfaceHolder holder)
106         {
107             // After we return from this we can't use the surface any more.
108             // The current Video View will be destroy when we play a new video.
109             pauseAndDispatch(mProxy);
110             mPlayer.release();
111             mSurfaceHolder = null;
112             if (mMediaController != null) {
113                 mMediaController.hide();
114             }
115         }
116     };
117 
getSurfaceView()118     private SurfaceView getSurfaceView() {
119         return mVideoSurfaceView;
120     }
121 
HTML5VideoFullScreen(Context context, int videoLayerId, int position, boolean autoStart)122     HTML5VideoFullScreen(Context context, int videoLayerId, int position,
123             boolean autoStart) {
124         mVideoSurfaceView = new VideoSurfaceView(context);
125         mFullScreenMode = FULLSCREEN_OFF;
126         mVideoWidth = 0;
127         mVideoHeight = 0;
128         init(videoLayerId, position, autoStart);
129     }
130 
setMediaController(MediaController m)131     private void setMediaController(MediaController m) {
132         mMediaController  = m;
133         attachMediaController();
134     }
135 
attachMediaController()136     private void attachMediaController() {
137         if (mPlayer != null && mMediaController != null) {
138             mMediaController.setMediaPlayer(this);
139             mMediaController.setAnchorView(mVideoSurfaceView);
140             //Will be enabled when prepared
141             mMediaController.setEnabled(false);
142         }
143     }
144 
145     @Override
decideDisplayMode()146     public void decideDisplayMode() {
147         mPlayer.setDisplay(mSurfaceHolder);
148     }
149 
prepareForFullScreen()150     private void prepareForFullScreen() {
151         // So in full screen, we reset the MediaPlayer
152         mPlayer.reset();
153         setMediaController(new MediaController(mProxy.getContext()));
154         mPlayer.setScreenOnWhilePlaying(true);
155         prepareDataAndDisplayMode(mProxy);
156     }
157 
158 
toggleMediaControlsVisiblity()159     private void toggleMediaControlsVisiblity() {
160         if (mMediaController.isShowing()) {
161             mMediaController.hide();
162         } else {
163             mMediaController.show();
164         }
165     }
166 
167     @Override
onPrepared(MediaPlayer mp)168     public void onPrepared(MediaPlayer mp) {
169         super.onPrepared(mp);
170 
171         mVideoSurfaceView.setOnTouchListener(this);
172         // Get the capabilities of the player for this stream
173         Metadata data = mp.getMetadata(MediaPlayer.METADATA_ALL,
174                 MediaPlayer.BYPASS_METADATA_FILTER);
175         if (data != null) {
176             mCanPause = !data.has(Metadata.PAUSE_AVAILABLE)
177                     || data.getBoolean(Metadata.PAUSE_AVAILABLE);
178             mCanSeekBack = !data.has(Metadata.SEEK_BACKWARD_AVAILABLE)
179                     || data.getBoolean(Metadata.SEEK_BACKWARD_AVAILABLE);
180             mCanSeekForward = !data.has(Metadata.SEEK_FORWARD_AVAILABLE)
181                     || data.getBoolean(Metadata.SEEK_FORWARD_AVAILABLE);
182         } else {
183             mCanPause = mCanSeekBack = mCanSeekForward = true;
184         }
185 
186         // mMediaController status depends on the Metadata result, so put it
187         // after reading the MetaData
188         if (mMediaController != null) {
189             mMediaController.setEnabled(true);
190             // If paused , should show the controller for ever!
191             if (getAutostart())
192                 mMediaController.show();
193             else
194                 mMediaController.show(0);
195         }
196 
197         if (mProgressView != null) {
198             mProgressView.setVisibility(View.GONE);
199         }
200 
201         mVideoWidth = mp.getVideoWidth();
202         mVideoHeight = mp.getVideoHeight();
203         // This will trigger the onMeasure to get the display size right.
204         mVideoSurfaceView.getHolder().setFixedSize(mVideoWidth, mVideoHeight);
205     }
206 
fullScreenExited()207     public boolean fullScreenExited() {
208         return (mLayout == null);
209     }
210 
211     private final WebChromeClient.CustomViewCallback mCallback =
212         new WebChromeClient.CustomViewCallback() {
213             public void onCustomViewHidden() {
214                 // It listens to SurfaceHolder.Callback.SurfaceDestroyed event
215                 // which happens when the video view is detached from its parent
216                 // view. This happens in the WebChromeClient before this method
217                 // is invoked.
218                 mProxy.dispatchOnStopFullScreen();
219                 mLayout.removeView(getSurfaceView());
220 
221                 if (mProgressView != null) {
222                     mLayout.removeView(mProgressView);
223                     mProgressView = null;
224                 }
225                 mLayout = null;
226                 // Re enable plugin views.
227                 mProxy.getWebView().getViewManager().showAll();
228 
229                 mProxy = null;
230 
231                 // Don't show the controller after exiting the full screen.
232                 mMediaController = null;
233                 mCurrentState = STATE_RELEASED;
234             }
235         };
236 
237     @Override
enterFullScreenVideoState(int layerId, HTML5VideoViewProxy proxy, WebView webView)238     public void enterFullScreenVideoState(int layerId,
239             HTML5VideoViewProxy proxy, WebView webView) {
240         mFullScreenMode = FULLSCREEN_SURFACECREATING;
241         mCurrentBufferPercentage = 0;
242         mPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
243         mProxy = proxy;
244 
245         mVideoSurfaceView.getHolder().addCallback(mSHCallback);
246         mVideoSurfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
247         mVideoSurfaceView.setFocusable(true);
248         mVideoSurfaceView.setFocusableInTouchMode(true);
249         mVideoSurfaceView.requestFocus();
250 
251         // Create a FrameLayout that will contain the VideoView and the
252         // progress view (if any).
253         mLayout = new FrameLayout(mProxy.getContext());
254         FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
255                             ViewGroup.LayoutParams.WRAP_CONTENT,
256                             ViewGroup.LayoutParams.WRAP_CONTENT,
257                             Gravity.CENTER);
258 
259         mLayout.addView(getSurfaceView(), layoutParams);
260 
261         mLayout.setVisibility(View.VISIBLE);
262 
263         WebChromeClient client = webView.getWebChromeClient();
264         if (client != null) {
265             client.onShowCustomView(mLayout, mCallback);
266             // Plugins like Flash will draw over the video so hide
267             // them while we're playing.
268             if (webView.getViewManager() != null)
269                 webView.getViewManager().hideAll();
270 
271             mProgressView = client.getVideoLoadingProgressView();
272             if (mProgressView != null) {
273                 mLayout.addView(mProgressView, layoutParams);
274                 mProgressView.setVisibility(View.VISIBLE);
275             }
276         }
277     }
278 
279     /**
280      * @return true when we are in full screen mode, even the surface not fully
281      * created.
282      */
isFullScreenMode()283     public boolean isFullScreenMode() {
284         return true;
285     }
286 
287     // MediaController FUNCTIONS:
288     @Override
canPause()289     public boolean canPause() {
290         return mCanPause;
291     }
292 
293     @Override
canSeekBackward()294     public boolean canSeekBackward() {
295         return mCanSeekBack;
296     }
297 
298     @Override
canSeekForward()299     public boolean canSeekForward() {
300         return mCanSeekForward;
301     }
302 
303     @Override
getBufferPercentage()304     public int getBufferPercentage() {
305         if (mPlayer != null) {
306             return mCurrentBufferPercentage;
307         }
308     return 0;
309     }
310 
311     // Other listeners functions:
312     private MediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener =
313         new MediaPlayer.OnBufferingUpdateListener() {
314         public void onBufferingUpdate(MediaPlayer mp, int percent) {
315             mCurrentBufferPercentage = percent;
316         }
317     };
318 
319     @Override
onTouch(View v, MotionEvent event)320     public boolean onTouch(View v, MotionEvent event) {
321         if (mFullScreenMode >= FULLSCREEN_SURFACECREATED
322                 && mMediaController != null) {
323             toggleMediaControlsVisiblity();
324         }
325         return false;
326     }
327 
328     @Override
switchProgressView(boolean playerBuffering)329     protected void switchProgressView(boolean playerBuffering) {
330         if (mProgressView != null) {
331             if (playerBuffering) {
332                 mProgressView.setVisibility(View.VISIBLE);
333             } else {
334                 mProgressView.setVisibility(View.GONE);
335             }
336         }
337         return;
338     }
339 }
340