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