Merge "Support html5 video switching b/t full screen and inline mode" into honeycomb-mr1
This commit is contained in:
286
core/java/android/webkit/HTML5VideoFullScreen.java
Normal file
286
core/java/android/webkit/HTML5VideoFullScreen.java
Normal file
@@ -0,0 +1,286 @@
|
|||||||
|
|
||||||
|
package android.webkit;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.media.MediaPlayer;
|
||||||
|
import android.media.Metadata;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.Gravity;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.SurfaceHolder;
|
||||||
|
import android.view.SurfaceView;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.webkit.HTML5VideoView;
|
||||||
|
import android.webkit.HTML5VideoViewProxy;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
import android.widget.MediaController;
|
||||||
|
import android.widget.MediaController.MediaPlayerControl;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide This is only used by the browser
|
||||||
|
*/
|
||||||
|
public class HTML5VideoFullScreen extends HTML5VideoView
|
||||||
|
implements MediaPlayerControl, MediaPlayer.OnPreparedListener,
|
||||||
|
View.OnTouchListener {
|
||||||
|
|
||||||
|
private SurfaceView mSurfaceView;
|
||||||
|
|
||||||
|
// We need the full screen state to decide which surface to render to and
|
||||||
|
// when to create the MediaPlayer accordingly.
|
||||||
|
static final int FULLSCREEN_OFF = 0;
|
||||||
|
static final int FULLSCREEN_SURFACECREATING = 1;
|
||||||
|
static final int FULLSCREEN_SURFACECREATED = 2;
|
||||||
|
|
||||||
|
private int mFullScreenMode;
|
||||||
|
// The Media Controller only used for full screen mode
|
||||||
|
private MediaController mMediaController;
|
||||||
|
|
||||||
|
// SurfaceHolder for full screen
|
||||||
|
private SurfaceHolder mSurfaceHolder = null;
|
||||||
|
|
||||||
|
// Data only for MediaController
|
||||||
|
private boolean mCanSeekBack;
|
||||||
|
private boolean mCanSeekForward;
|
||||||
|
private boolean mCanPause;
|
||||||
|
private int mCurrentBufferPercentage;
|
||||||
|
|
||||||
|
// The progress view.
|
||||||
|
private static View mProgressView;
|
||||||
|
// The container for the progress view and video view
|
||||||
|
private static FrameLayout mLayout;
|
||||||
|
|
||||||
|
SurfaceHolder.Callback mSHCallback = new SurfaceHolder.Callback()
|
||||||
|
{
|
||||||
|
public void surfaceChanged(SurfaceHolder holder, int format,
|
||||||
|
int w, int h)
|
||||||
|
{
|
||||||
|
if (mPlayer != null && mMediaController != null
|
||||||
|
&& mCurrentState == STATE_PREPARED) {
|
||||||
|
if (mMediaController.isShowing()) {
|
||||||
|
// ensure the controller will get repositioned later
|
||||||
|
mMediaController.hide();
|
||||||
|
}
|
||||||
|
mMediaController.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void surfaceCreated(SurfaceHolder holder)
|
||||||
|
{
|
||||||
|
mSurfaceHolder = holder;
|
||||||
|
mFullScreenMode = FULLSCREEN_SURFACECREATED;
|
||||||
|
|
||||||
|
prepareForFullScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void surfaceDestroyed(SurfaceHolder holder)
|
||||||
|
{
|
||||||
|
// after we return from this we can't use the surface any more
|
||||||
|
mSurfaceHolder = null;
|
||||||
|
// The current Video View will be destroy when we play a new video.
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public SurfaceView getSurfaceView() {
|
||||||
|
return mSurfaceView;
|
||||||
|
}
|
||||||
|
|
||||||
|
HTML5VideoFullScreen(Context context, int videoLayerId, int position,
|
||||||
|
boolean autoStart) {
|
||||||
|
mSurfaceView = new SurfaceView(context);
|
||||||
|
mFullScreenMode = FULLSCREEN_OFF;
|
||||||
|
init(videoLayerId, position, autoStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setMediaController(MediaController m) {
|
||||||
|
mMediaController = m;
|
||||||
|
attachMediaController();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void attachMediaController() {
|
||||||
|
if (mPlayer != null && mMediaController != null) {
|
||||||
|
mMediaController.setMediaPlayer(this);
|
||||||
|
mMediaController.setAnchorView(mSurfaceView);
|
||||||
|
//Will be enabled when prepared
|
||||||
|
mMediaController.setEnabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void decideDisplayMode() {
|
||||||
|
mPlayer.setDisplay(mSurfaceHolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void prepareForFullScreen() {
|
||||||
|
// So in full screen, we reset the MediaPlayer
|
||||||
|
mPlayer.reset();
|
||||||
|
setMediaController(new MediaController(mProxy.getContext()));
|
||||||
|
|
||||||
|
prepareDataAndDisplayMode(mProxy);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void toggleMediaControlsVisiblity() {
|
||||||
|
if (mMediaController.isShowing()) {
|
||||||
|
mMediaController.hide();
|
||||||
|
} else {
|
||||||
|
mMediaController.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPrepared(MediaPlayer mp) {
|
||||||
|
super.onPrepared(mp);
|
||||||
|
|
||||||
|
mSurfaceView.setOnTouchListener(this);
|
||||||
|
// Get the capabilities of the player for this stream
|
||||||
|
Metadata data = mp.getMetadata(MediaPlayer.METADATA_ALL,
|
||||||
|
MediaPlayer.BYPASS_METADATA_FILTER);
|
||||||
|
if (data != null) {
|
||||||
|
mCanPause = !data.has(Metadata.PAUSE_AVAILABLE)
|
||||||
|
|| data.getBoolean(Metadata.PAUSE_AVAILABLE);
|
||||||
|
mCanSeekBack = !data.has(Metadata.SEEK_BACKWARD_AVAILABLE)
|
||||||
|
|| data.getBoolean(Metadata.SEEK_BACKWARD_AVAILABLE);
|
||||||
|
mCanSeekForward = !data.has(Metadata.SEEK_FORWARD_AVAILABLE)
|
||||||
|
|| data.getBoolean(Metadata.SEEK_FORWARD_AVAILABLE);
|
||||||
|
} else {
|
||||||
|
mCanPause = mCanSeekBack = mCanSeekForward = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mMediaController status depends on the Metadata result, so put it
|
||||||
|
// after reading the MetaData
|
||||||
|
if (mMediaController != null) {
|
||||||
|
mMediaController.setEnabled(true);
|
||||||
|
// If paused , should show the controller for ever!
|
||||||
|
if (getAutostart())
|
||||||
|
mMediaController.show();
|
||||||
|
else
|
||||||
|
mMediaController.show(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mProgressView != null) {
|
||||||
|
mProgressView.setVisibility(View.GONE);
|
||||||
|
mLayout.removeView(mProgressView);
|
||||||
|
mProgressView = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private final WebChromeClient.CustomViewCallback mCallback =
|
||||||
|
new WebChromeClient.CustomViewCallback() {
|
||||||
|
public void onCustomViewHidden() {
|
||||||
|
// It listens to SurfaceHolder.Callback.SurfaceDestroyed event
|
||||||
|
// which happens when the video view is detached from its parent
|
||||||
|
// view. This happens in the WebChromeClient before this method
|
||||||
|
// is invoked.
|
||||||
|
mTimer.cancel();
|
||||||
|
mTimer = null;
|
||||||
|
|
||||||
|
pauseAndDispatch(mProxy);
|
||||||
|
|
||||||
|
mLayout.removeView(getSurfaceView());
|
||||||
|
|
||||||
|
if (mProgressView != null) {
|
||||||
|
mLayout.removeView(mProgressView);
|
||||||
|
mProgressView = null;
|
||||||
|
}
|
||||||
|
mLayout = null;
|
||||||
|
// Re enable plugin views.
|
||||||
|
mProxy.getWebView().getViewManager().showAll();
|
||||||
|
|
||||||
|
mProxy = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void enterFullScreenVideoState(int layerId,
|
||||||
|
HTML5VideoViewProxy proxy, WebView webView) {
|
||||||
|
mFullScreenMode = FULLSCREEN_SURFACECREATING;
|
||||||
|
mCurrentBufferPercentage = 0;
|
||||||
|
mPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
|
||||||
|
mProxy = proxy;
|
||||||
|
|
||||||
|
mSurfaceView.getHolder().addCallback(mSHCallback);
|
||||||
|
mSurfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
|
||||||
|
mSurfaceView.setFocusable(true);
|
||||||
|
mSurfaceView.setFocusableInTouchMode(true);
|
||||||
|
mSurfaceView.requestFocus();
|
||||||
|
|
||||||
|
// Create a FrameLayout that will contain the VideoView and the
|
||||||
|
// progress view (if any).
|
||||||
|
mLayout = new FrameLayout(mProxy.getContext());
|
||||||
|
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||||
|
Gravity.CENTER);
|
||||||
|
|
||||||
|
mLayout.addView(getSurfaceView(), layoutParams);
|
||||||
|
|
||||||
|
mLayout.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
|
WebChromeClient client = webView.getWebChromeClient();
|
||||||
|
client.onShowCustomView(mLayout, mCallback);
|
||||||
|
// Plugins like Flash will draw over the video so hide
|
||||||
|
// them while we're playing.
|
||||||
|
mProxy.getWebView().getViewManager().hideAll();
|
||||||
|
|
||||||
|
mProgressView = client.getVideoLoadingProgressView();
|
||||||
|
if (mProgressView != null) {
|
||||||
|
mLayout.addView(mProgressView, layoutParams);
|
||||||
|
mProgressView.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true when we are in full screen mode, even the surface not fully
|
||||||
|
* created.
|
||||||
|
*/
|
||||||
|
public boolean isFullScreenMode() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// MediaController FUNCTIONS:
|
||||||
|
@Override
|
||||||
|
public boolean canPause() {
|
||||||
|
return mCanPause;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canSeekBackward() {
|
||||||
|
return mCanSeekBack;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canSeekForward() {
|
||||||
|
return mCanSeekForward;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBufferPercentage() {
|
||||||
|
if (mPlayer != null) {
|
||||||
|
return mCurrentBufferPercentage;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Other listeners functions:
|
||||||
|
private MediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener =
|
||||||
|
new MediaPlayer.OnBufferingUpdateListener() {
|
||||||
|
public void onBufferingUpdate(MediaPlayer mp, int percent) {
|
||||||
|
mCurrentBufferPercentage = percent;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onTouch(View v, MotionEvent event) {
|
||||||
|
if (mFullScreenMode >= FULLSCREEN_SURFACECREATED
|
||||||
|
&& mMediaController != null) {
|
||||||
|
toggleMediaControlsVisiblity();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
99
core/java/android/webkit/HTML5VideoInline.java
Normal file
99
core/java/android/webkit/HTML5VideoInline.java
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
|
||||||
|
package android.webkit;
|
||||||
|
|
||||||
|
import android.graphics.SurfaceTexture;
|
||||||
|
import android.media.MediaPlayer;
|
||||||
|
import android.webkit.HTML5VideoView;
|
||||||
|
import android.webkit.HTML5VideoViewProxy;
|
||||||
|
import android.opengl.GLES20;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide This is only used by the browser
|
||||||
|
*/
|
||||||
|
public class HTML5VideoInline extends HTML5VideoView{
|
||||||
|
|
||||||
|
// Due to the fact that SurfaceTexture consume a lot of memory, we make it
|
||||||
|
// as static. m_textureNames is the texture bound with this SurfaceTexture.
|
||||||
|
private static SurfaceTexture mSurfaceTexture = null;
|
||||||
|
private static int[] mTextureNames;
|
||||||
|
|
||||||
|
// Only when the video is prepared, we render using SurfaceTexture.
|
||||||
|
// This in fact is used to avoid showing the obsolete content when
|
||||||
|
// switching videos.
|
||||||
|
private static boolean mReadyToUseSurfTex = false;
|
||||||
|
|
||||||
|
// Video control FUNCTIONS:
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
super.start();
|
||||||
|
if (mCurrentState == STATE_PREPARED) {
|
||||||
|
mReadyToUseSurfTex = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HTML5VideoInline(int videoLayerId, int position,
|
||||||
|
boolean autoStart) {
|
||||||
|
init(videoLayerId, position, autoStart);
|
||||||
|
mReadyToUseSurfTex = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void decideDisplayMode() {
|
||||||
|
mPlayer.setTexture(getSurfaceTextureInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normally called immediately after setVideoURI. But for full screen,
|
||||||
|
// this should be after surface holder created
|
||||||
|
@Override
|
||||||
|
public void prepareDataAndDisplayMode(HTML5VideoViewProxy proxy) {
|
||||||
|
super.prepareDataAndDisplayMode(proxy);
|
||||||
|
setFrameAvailableListener(proxy);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pause the play and update the play/pause button
|
||||||
|
@Override
|
||||||
|
public void pauseAndDispatch(HTML5VideoViewProxy proxy) {
|
||||||
|
super.pauseAndDispatch(proxy);
|
||||||
|
mReadyToUseSurfTex = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inline Video specific FUNCTIONS:
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SurfaceTexture getSurfaceTexture() {
|
||||||
|
return mSurfaceTexture;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteSurfaceTexture() {
|
||||||
|
mSurfaceTexture = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SurfaceTexture is a singleton here , too
|
||||||
|
private SurfaceTexture getSurfaceTextureInstance() {
|
||||||
|
// Create the surface texture.
|
||||||
|
if (mSurfaceTexture == null)
|
||||||
|
{
|
||||||
|
mTextureNames = new int[1];
|
||||||
|
GLES20.glGenTextures(1, mTextureNames, 0);
|
||||||
|
mSurfaceTexture = new SurfaceTexture(mTextureNames[0]);
|
||||||
|
}
|
||||||
|
return mSurfaceTexture;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTextureName() {
|
||||||
|
return mTextureNames[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getReadyToUseSurfTex() {
|
||||||
|
return mReadyToUseSurfTex;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setFrameAvailableListener(SurfaceTexture.OnFrameAvailableListener l) {
|
||||||
|
mSurfaceTexture.setOnFrameAvailableListener(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -4,73 +4,94 @@ package android.webkit;
|
|||||||
import android.graphics.SurfaceTexture;
|
import android.graphics.SurfaceTexture;
|
||||||
import android.media.MediaPlayer;
|
import android.media.MediaPlayer;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.view.SurfaceView;
|
||||||
import android.webkit.HTML5VideoViewProxy;
|
import android.webkit.HTML5VideoViewProxy;
|
||||||
import android.widget.MediaController;
|
|
||||||
import android.opengl.GLES20;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @hide This is only used by the browser
|
* @hide This is only used by the browser
|
||||||
*/
|
*/
|
||||||
public class HTML5VideoView implements MediaPlayer.OnPreparedListener{
|
public class HTML5VideoView implements MediaPlayer.OnPreparedListener{
|
||||||
// Due to the fact that SurfaceTexture consume a lot of memory, we make it
|
|
||||||
// as static. m_textureNames is the texture bound with this SurfaceTexture.
|
|
||||||
private static SurfaceTexture mSurfaceTexture = null;
|
|
||||||
private static int[] mTextureNames;
|
|
||||||
|
|
||||||
// Only when the video is prepared, we render using SurfaceTexture.
|
protected static final String LOGTAG = "HTML5VideoView";
|
||||||
// This in fact is used to avoid showing the obsolete content when
|
|
||||||
// switching videos.
|
protected static final String COOKIE = "Cookie";
|
||||||
private static boolean mReadyToUseSurfTex = false;
|
protected static final String HIDE_URL_LOGS = "x-hide-urls-from-log";
|
||||||
|
|
||||||
// For handling the seekTo before prepared, we need to know whether or not
|
// For handling the seekTo before prepared, we need to know whether or not
|
||||||
// the video is prepared. Therefore, we differentiate the state between
|
// the video is prepared. Therefore, we differentiate the state between
|
||||||
// prepared and not prepared.
|
// prepared and not prepared.
|
||||||
// When the video is not prepared, we will have to save the seekTo time,
|
// When the video is not prepared, we will have to save the seekTo time,
|
||||||
// and use it when prepared to play.
|
// and use it when prepared to play.
|
||||||
private static final int STATE_NOTPREPARED = 0;
|
protected static final int STATE_NOTPREPARED = 0;
|
||||||
private static final int STATE_PREPARED = 1;
|
protected static final int STATE_PREPARED = 1;
|
||||||
|
|
||||||
// We only need state for handling seekTo
|
protected int mCurrentState;
|
||||||
private int mCurrentState;
|
|
||||||
|
|
||||||
// Basically for calling back the OnPrepared in the proxy
|
protected HTML5VideoViewProxy mProxy;
|
||||||
private HTML5VideoViewProxy mProxy;
|
|
||||||
|
|
||||||
// Save the seek time when not prepared. This can happen when switching
|
// Save the seek time when not prepared. This can happen when switching
|
||||||
// video besides initial load.
|
// video besides initial load.
|
||||||
private int mSaveSeekTime;
|
protected int mSaveSeekTime;
|
||||||
|
|
||||||
// This is used to find the VideoLayer on the native side.
|
// This is used to find the VideoLayer on the native side.
|
||||||
private int mVideoLayerId;
|
protected int mVideoLayerId;
|
||||||
|
|
||||||
// Every video will have one MediaPlayer. Given the fact we only have one
|
// Every video will have one MediaPlayer. Given the fact we only have one
|
||||||
// SurfaceTexture, there is only one MediaPlayer in action. Every time we
|
// SurfaceTexture, there is only one MediaPlayer in action. Every time we
|
||||||
// switch videos, a new instance of MediaPlayer will be created in reset().
|
// switch videos, a new instance of MediaPlayer will be created in reset().
|
||||||
private MediaPlayer mPlayer;
|
// Switching between inline and full screen will also create a new instance.
|
||||||
|
protected MediaPlayer mPlayer;
|
||||||
|
|
||||||
private static HTML5VideoView mInstance = new HTML5VideoView();
|
// This will be set up every time we create the Video View object.
|
||||||
|
// Set to true only when switching into full screen while playing
|
||||||
|
protected boolean mAutostart;
|
||||||
|
|
||||||
// Video control FUNCTIONS:
|
// We need to save such info.
|
||||||
|
protected String mUri;
|
||||||
|
protected Map<String, String> mHeaders;
|
||||||
|
|
||||||
|
// The timer for timeupate events.
|
||||||
|
// See http://www.whatwg.org/specs/web-apps/current-work/#event-media-timeupdate
|
||||||
|
protected static Timer mTimer;
|
||||||
|
|
||||||
|
// The spec says the timer should fire every 250 ms or less.
|
||||||
|
private static final int TIMEUPDATE_PERIOD = 250; // ms
|
||||||
|
|
||||||
|
// common Video control FUNCTIONS:
|
||||||
public void start() {
|
public void start() {
|
||||||
if (mCurrentState == STATE_PREPARED) {
|
if (mCurrentState == STATE_PREPARED) {
|
||||||
mPlayer.start();
|
mPlayer.start();
|
||||||
mReadyToUseSurfTex = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void pause() {
|
public void pause() {
|
||||||
|
if (mCurrentState == STATE_PREPARED && mPlayer.isPlaying()) {
|
||||||
mPlayer.pause();
|
mPlayer.pause();
|
||||||
}
|
}
|
||||||
|
if (mTimer != null) {
|
||||||
|
mTimer.purge();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public int getDuration() {
|
public int getDuration() {
|
||||||
|
if (mCurrentState == STATE_PREPARED) {
|
||||||
return mPlayer.getDuration();
|
return mPlayer.getDuration();
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCurrentPosition() {
|
public int getCurrentPosition() {
|
||||||
|
if (mCurrentState == STATE_PREPARED) {
|
||||||
return mPlayer.getCurrentPosition();
|
return mPlayer.getCurrentPosition();
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
public void seekTo(int pos) {
|
public void seekTo(int pos) {
|
||||||
if (mCurrentState == STATE_PREPARED)
|
if (mCurrentState == STATE_PREPARED)
|
||||||
@@ -88,53 +109,50 @@ public class HTML5VideoView implements MediaPlayer.OnPreparedListener{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void stopPlayback() {
|
public void stopPlayback() {
|
||||||
|
if (mCurrentState == STATE_PREPARED) {
|
||||||
mPlayer.stop();
|
mPlayer.stop();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void reset(int videoLayerId) {
|
public boolean getAutostart() {
|
||||||
|
return mAutostart;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Every time we start a new Video, we create a VideoView and a MediaPlayer
|
||||||
|
public void init(int videoLayerId, int position, boolean autoStart) {
|
||||||
mPlayer = new MediaPlayer();
|
mPlayer = new MediaPlayer();
|
||||||
mCurrentState = STATE_NOTPREPARED;
|
mCurrentState = STATE_NOTPREPARED;
|
||||||
mProxy = null;
|
mProxy = null;
|
||||||
mVideoLayerId = videoLayerId;
|
mVideoLayerId = videoLayerId;
|
||||||
mReadyToUseSurfTex = false;
|
mSaveSeekTime = position;
|
||||||
|
mAutostart = autoStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static HTML5VideoView getInstance(int videoLayerId) {
|
protected HTML5VideoView() {
|
||||||
// Every time we switch between the videos, a new MediaPlayer will be
|
|
||||||
// created. Make sure we call the m_player.release() when it is done.
|
|
||||||
mInstance.reset(videoLayerId);
|
|
||||||
return mInstance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private HTML5VideoView() {
|
protected static Map<String, String> generateHeaders(String url,
|
||||||
// This is a singleton across WebViews (i.e. Tabs).
|
HTML5VideoViewProxy proxy) {
|
||||||
// HTML5VideoViewProxy will reset the internal state every time a new
|
boolean isPrivate = proxy.getWebView().isPrivateBrowsingEnabled();
|
||||||
// video start.
|
String cookieValue = CookieManager.getInstance().getCookie(url, isPrivate);
|
||||||
|
Map<String, String> headers = new HashMap<String, String>();
|
||||||
|
if (cookieValue != null) {
|
||||||
|
headers.put(COOKIE, cookieValue);
|
||||||
|
}
|
||||||
|
if (isPrivate) {
|
||||||
|
headers.put(HIDE_URL_LOGS, "true");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMediaController(MediaController m) {
|
return headers;
|
||||||
this.setMediaController(m);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setVideoURI(String uri, Map<String, String> headers) {
|
public void setVideoURI(String uri, HTML5VideoViewProxy proxy) {
|
||||||
// When switching players, surface texture will be reused.
|
// When switching players, surface texture will be reused.
|
||||||
mPlayer.setTexture(getSurfaceTextureInstance());
|
mUri = uri;
|
||||||
|
mHeaders = generateHeaders(uri, proxy);
|
||||||
|
|
||||||
// When there is exception, we could just bail out silently.
|
mTimer = new Timer();
|
||||||
// No Video will be played though. Write the stack for debug
|
|
||||||
try {
|
|
||||||
mPlayer.setDataSource(uri, headers);
|
|
||||||
mPlayer.prepareAsync();
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (IllegalStateException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// TODO [FULL SCREEN SUPPORT]
|
|
||||||
|
|
||||||
// Listeners setup FUNCTIONS:
|
// Listeners setup FUNCTIONS:
|
||||||
public void setOnCompletionListener(HTML5VideoViewProxy proxy) {
|
public void setOnCompletionListener(HTML5VideoViewProxy proxy) {
|
||||||
@@ -150,43 +168,47 @@ public class HTML5VideoView implements MediaPlayer.OnPreparedListener{
|
|||||||
mPlayer.setOnPreparedListener(this);
|
mPlayer.setOnPreparedListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inline Video specific FUNCTIONS:
|
// Normally called immediately after setVideoURI. But for full screen,
|
||||||
|
// this should be after surface holder created
|
||||||
|
public void prepareDataAndDisplayMode(HTML5VideoViewProxy proxy) {
|
||||||
|
// SurfaceTexture will be created lazily here for inline mode
|
||||||
|
decideDisplayMode();
|
||||||
|
|
||||||
public SurfaceTexture getSurfaceTexture() {
|
setOnCompletionListener(proxy);
|
||||||
return mSurfaceTexture;
|
setOnPreparedListener(proxy);
|
||||||
|
setOnErrorListener(proxy);
|
||||||
|
|
||||||
|
// When there is exception, we could just bail out silently.
|
||||||
|
// No Video will be played though. Write the stack for debug
|
||||||
|
try {
|
||||||
|
mPlayer.setDataSource(mUri, mHeaders);
|
||||||
|
mPlayer.prepareAsync();
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteSurfaceTexture() {
|
|
||||||
mSurfaceTexture = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// SurfaceTexture is a singleton here , too
|
|
||||||
private SurfaceTexture getSurfaceTextureInstance() {
|
|
||||||
// Create the surface texture.
|
|
||||||
if (mSurfaceTexture == null)
|
|
||||||
{
|
|
||||||
mTextureNames = new int[1];
|
|
||||||
GLES20.glGenTextures(1, mTextureNames, 0);
|
|
||||||
mSurfaceTexture = new SurfaceTexture(mTextureNames[0]);
|
|
||||||
}
|
|
||||||
return mSurfaceTexture;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getTextureName() {
|
|
||||||
return mTextureNames[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Common code
|
||||||
public int getVideoLayerId() {
|
public int getVideoLayerId() {
|
||||||
return mVideoLayerId;
|
return mVideoLayerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getReadyToUseSurfTex() {
|
private static final class TimeupdateTask extends TimerTask {
|
||||||
return mReadyToUseSurfTex;
|
private HTML5VideoViewProxy mProxy;
|
||||||
|
|
||||||
|
public TimeupdateTask(HTML5VideoViewProxy proxy) {
|
||||||
|
mProxy = proxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFrameAvailableListener(SurfaceTexture.OnFrameAvailableListener l) {
|
@Override
|
||||||
mSurfaceTexture.setOnFrameAvailableListener(l);
|
public void run() {
|
||||||
|
mProxy.onTimeupdate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -195,6 +217,9 @@ public class HTML5VideoView implements MediaPlayer.OnPreparedListener{
|
|||||||
seekTo(mSaveSeekTime);
|
seekTo(mSaveSeekTime);
|
||||||
if (mProxy != null)
|
if (mProxy != null)
|
||||||
mProxy.onPrepared(mp);
|
mProxy.onPrepared(mp);
|
||||||
|
|
||||||
|
mTimer.schedule(new TimeupdateTask(mProxy), TIMEUPDATE_PERIOD, TIMEUPDATE_PERIOD);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pause the play and update the play/pause button
|
// Pause the play and update the play/pause button
|
||||||
@@ -205,7 +230,42 @@ public class HTML5VideoView implements MediaPlayer.OnPreparedListener{
|
|||||||
proxy.dispatchOnPaused();
|
proxy.dispatchOnPaused();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mReadyToUseSurfTex = false;
|
}
|
||||||
|
|
||||||
|
// Below are functions that are different implementation on inline and full-
|
||||||
|
// screen mode. Some are specific to one type, but currently are called
|
||||||
|
// directly from the proxy.
|
||||||
|
public void enterFullScreenVideoState(int layerId,
|
||||||
|
HTML5VideoViewProxy proxy, WebView webView) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFullScreenMode() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SurfaceView getSurfaceView() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decideDisplayMode() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void prepareForFullScreen() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getReadyToUseSurfTex() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SurfaceTexture getSurfaceTexture() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteSurfaceTexture() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTextureName() {
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,29 +21,16 @@ import android.graphics.Bitmap;
|
|||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
import android.graphics.SurfaceTexture;
|
import android.graphics.SurfaceTexture;
|
||||||
import android.media.MediaPlayer;
|
import android.media.MediaPlayer;
|
||||||
import android.media.MediaPlayer.OnPreparedListener;
|
|
||||||
import android.media.MediaPlayer.OnCompletionListener;
|
|
||||||
import android.media.MediaPlayer.OnErrorListener;
|
|
||||||
import android.net.http.EventHandler;
|
import android.net.http.EventHandler;
|
||||||
import android.net.http.Headers;
|
import android.net.http.Headers;
|
||||||
import android.net.http.RequestHandle;
|
import android.net.http.RequestHandle;
|
||||||
import android.net.http.RequestQueue;
|
import android.net.http.RequestQueue;
|
||||||
import android.net.http.SslCertificate;
|
import android.net.http.SslCertificate;
|
||||||
import android.net.http.SslError;
|
import android.net.http.SslError;
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.MotionEvent;
|
|
||||||
import android.view.Gravity;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.AbsoluteLayout;
|
|
||||||
import android.widget.FrameLayout;
|
|
||||||
import android.widget.MediaController;
|
|
||||||
import android.widget.VideoView;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -51,8 +38,6 @@ import java.net.MalformedURLException;
|
|||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Timer;
|
|
||||||
import java.util.TimerTask;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Proxy for HTML5 video views.
|
* <p>Proxy for HTML5 video views.
|
||||||
@@ -78,9 +63,6 @@ class HTML5VideoViewProxy extends Handler
|
|||||||
private static final int POSTER_FETCHED = 202;
|
private static final int POSTER_FETCHED = 202;
|
||||||
private static final int PAUSED = 203;
|
private static final int PAUSED = 203;
|
||||||
|
|
||||||
private static final String COOKIE = "Cookie";
|
|
||||||
private static final String HIDE_URL_LOGS = "x-hide-urls-from-log";
|
|
||||||
|
|
||||||
// Timer thread -> UI thread
|
// Timer thread -> UI thread
|
||||||
private static final int TIMEUPDATE = 300;
|
private static final int TIMEUPDATE = 300;
|
||||||
|
|
||||||
@@ -104,38 +86,19 @@ class HTML5VideoViewProxy extends Handler
|
|||||||
// The VideoView instance. This is a singleton for now, at least until
|
// The VideoView instance. This is a singleton for now, at least until
|
||||||
// http://b/issue?id=1973663 is fixed.
|
// http://b/issue?id=1973663 is fixed.
|
||||||
private static HTML5VideoView mHTML5VideoView;
|
private static HTML5VideoView mHTML5VideoView;
|
||||||
// The progress view.
|
|
||||||
private static View mProgressView;
|
|
||||||
// The container for the progress view and video view
|
|
||||||
private static FrameLayout mLayout;
|
|
||||||
// The timer for timeupate events.
|
|
||||||
// See http://www.whatwg.org/specs/web-apps/current-work/#event-media-timeupdate
|
|
||||||
private static Timer mTimer;
|
|
||||||
private static final class TimeupdateTask extends TimerTask {
|
|
||||||
private HTML5VideoViewProxy mProxy;
|
|
||||||
|
|
||||||
public TimeupdateTask(HTML5VideoViewProxy proxy) {
|
|
||||||
mProxy = proxy;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void run() {
|
|
||||||
mProxy.onTimeupdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// The spec says the timer should fire every 250 ms or less.
|
|
||||||
private static final int TIMEUPDATE_PERIOD = 250; // ms
|
|
||||||
private static boolean isVideoSelfEnded = false;
|
private static boolean isVideoSelfEnded = false;
|
||||||
// By using the baseLayer and the current video Layer ID, we can
|
// By using the baseLayer and the current video Layer ID, we can
|
||||||
// identify the exact layer on the UI thread to use the SurfaceTexture.
|
// identify the exact layer on the UI thread to use the SurfaceTexture.
|
||||||
private static int mBaseLayer = 0;
|
private static int mBaseLayer = 0;
|
||||||
|
|
||||||
// TODO: [FULL SCREEN SUPPORT]
|
|
||||||
|
|
||||||
// Every time webView setBaseLayer, this will be called.
|
// Every time webView setBaseLayer, this will be called.
|
||||||
// When we found the Video layer, then we set the Surface Texture to it.
|
// When we found the Video layer, then we set the Surface Texture to it.
|
||||||
// Otherwise, we may want to delete the Surface Texture to save memory.
|
// Otherwise, we may want to delete the Surface Texture to save memory.
|
||||||
public static void setBaseLayer(int layer) {
|
public static void setBaseLayer(int layer) {
|
||||||
if (mHTML5VideoView != null) {
|
// Don't do this for full screen mode.
|
||||||
|
if (mHTML5VideoView != null
|
||||||
|
&& !mHTML5VideoView.isFullScreenMode()) {
|
||||||
mBaseLayer = layer;
|
mBaseLayer = layer;
|
||||||
SurfaceTexture surfTexture = mHTML5VideoView.getSurfaceTexture();
|
SurfaceTexture surfTexture = mHTML5VideoView.getSurfaceTexture();
|
||||||
int textureName = mHTML5VideoView.getTextureName();
|
int textureName = mHTML5VideoView.getTextureName();
|
||||||
@@ -165,16 +128,47 @@ class HTML5VideoViewProxy extends Handler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void enterFullScreenVideo(int layerId, String url,
|
||||||
|
HTML5VideoViewProxy proxy, WebView webView) {
|
||||||
|
// Save the inline video info and inherit it in the full screen
|
||||||
|
int savePosition = 0;
|
||||||
|
boolean savedIsPlaying = false;
|
||||||
|
if (mHTML5VideoView != null) {
|
||||||
|
// If we are playing the same video, then it is better to
|
||||||
|
// save the current position.
|
||||||
|
if (layerId == mHTML5VideoView.getVideoLayerId()) {
|
||||||
|
savePosition = mHTML5VideoView.getCurrentPosition();
|
||||||
|
savedIsPlaying = mHTML5VideoView.isPlaying();
|
||||||
|
}
|
||||||
|
mHTML5VideoView.pauseAndDispatch(mCurrentProxy);
|
||||||
|
mHTML5VideoView.release();
|
||||||
|
}
|
||||||
|
mHTML5VideoView = new HTML5VideoFullScreen(proxy.getContext(),
|
||||||
|
layerId, savePosition, savedIsPlaying);
|
||||||
|
mCurrentProxy = proxy;
|
||||||
|
|
||||||
|
mHTML5VideoView.setVideoURI(url, mCurrentProxy);
|
||||||
|
|
||||||
|
mHTML5VideoView.enterFullScreenVideoState(layerId, proxy, webView);
|
||||||
|
}
|
||||||
|
|
||||||
// This is on the UI thread.
|
// This is on the UI thread.
|
||||||
// When native tell Java to play, we need to check whether or not it is
|
// When native tell Java to play, we need to check whether or not it is
|
||||||
// still the same video by using videoLayerId and treat it differently.
|
// still the same video by using videoLayerId and treat it differently.
|
||||||
public static void play(String url, int time, HTML5VideoViewProxy proxy,
|
public static void play(String url, int time, HTML5VideoViewProxy proxy,
|
||||||
WebChromeClient client, int videoLayerId) {
|
WebChromeClient client, int videoLayerId) {
|
||||||
int currentVideoLayerId = -1;
|
int currentVideoLayerId = -1;
|
||||||
if (mHTML5VideoView != null)
|
boolean backFromFullScreenMode = false;
|
||||||
currentVideoLayerId = mHTML5VideoView.getVideoLayerId();
|
|
||||||
|
|
||||||
if (currentVideoLayerId != videoLayerId
|
if (mHTML5VideoView != null) {
|
||||||
|
currentVideoLayerId = mHTML5VideoView.getVideoLayerId();
|
||||||
|
if (mHTML5VideoView instanceof HTML5VideoFullScreen) {
|
||||||
|
backFromFullScreenMode = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (backFromFullScreenMode
|
||||||
|
|| currentVideoLayerId != videoLayerId
|
||||||
|| mHTML5VideoView.getSurfaceTexture() == null) {
|
|| mHTML5VideoView.getSurfaceTexture() == null) {
|
||||||
// Here, we handle the case when switching to a new video,
|
// Here, we handle the case when switching to a new video,
|
||||||
// either inside a WebView or across WebViews
|
// either inside a WebView or across WebViews
|
||||||
@@ -186,35 +180,11 @@ class HTML5VideoViewProxy extends Handler
|
|||||||
// release the media player to avoid finalize error
|
// release the media player to avoid finalize error
|
||||||
mHTML5VideoView.release();
|
mHTML5VideoView.release();
|
||||||
}
|
}
|
||||||
// HTML5VideoView is singleton, however, the internal state will
|
|
||||||
// be reset since we are switching from one video to another.
|
|
||||||
// Then we need to set up all the source/listener etc...
|
|
||||||
mHTML5VideoView = HTML5VideoView.getInstance(videoLayerId);
|
|
||||||
|
|
||||||
mCurrentProxy = proxy;
|
mCurrentProxy = proxy;
|
||||||
|
mHTML5VideoView = new HTML5VideoInline(videoLayerId, time, false);
|
||||||
|
|
||||||
// TODO: [FULL SCREEN SUPPORT]
|
mHTML5VideoView.setVideoURI(url, mCurrentProxy);
|
||||||
|
mHTML5VideoView.prepareDataAndDisplayMode(proxy);
|
||||||
boolean isPrivate = mCurrentProxy.getWebView().isPrivateBrowsingEnabled();
|
|
||||||
String cookieValue = CookieManager.getInstance().getCookie(url, isPrivate);
|
|
||||||
Map<String, String> headers = new HashMap<String, String>();
|
|
||||||
if (cookieValue != null) {
|
|
||||||
headers.put(COOKIE, cookieValue);
|
|
||||||
}
|
|
||||||
if (isPrivate) {
|
|
||||||
headers.put(HIDE_URL_LOGS, "true");
|
|
||||||
}
|
|
||||||
|
|
||||||
mHTML5VideoView.setVideoURI(url, headers);
|
|
||||||
mHTML5VideoView.setOnCompletionListener(proxy);
|
|
||||||
mHTML5VideoView.setOnPreparedListener(proxy);
|
|
||||||
mHTML5VideoView.setOnErrorListener(proxy);
|
|
||||||
mHTML5VideoView.setFrameAvailableListener(proxy);
|
|
||||||
|
|
||||||
mHTML5VideoView.seekTo(time);
|
|
||||||
|
|
||||||
mTimer = new Timer();
|
|
||||||
|
|
||||||
} else if (mCurrentProxy == proxy) {
|
} else if (mCurrentProxy == proxy) {
|
||||||
// Here, we handle the case when we keep playing with one video
|
// Here, we handle the case when we keep playing with one video
|
||||||
if (!mHTML5VideoView.isPlaying()) {
|
if (!mHTML5VideoView.isPlaying()) {
|
||||||
@@ -222,7 +192,8 @@ class HTML5VideoViewProxy extends Handler
|
|||||||
mHTML5VideoView.start();
|
mHTML5VideoView.start();
|
||||||
}
|
}
|
||||||
} else if (mCurrentProxy != null) {
|
} else if (mCurrentProxy != null) {
|
||||||
// Some other video is already playing. Notify the caller that its playback ended.
|
// Some other video is already playing. Notify the caller that
|
||||||
|
// its playback ended.
|
||||||
proxy.dispatchOnEnded();
|
proxy.dispatchOnEnded();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -249,14 +220,14 @@ class HTML5VideoViewProxy extends Handler
|
|||||||
public static void pause(HTML5VideoViewProxy proxy) {
|
public static void pause(HTML5VideoViewProxy proxy) {
|
||||||
if (mCurrentProxy == proxy && mHTML5VideoView != null) {
|
if (mCurrentProxy == proxy && mHTML5VideoView != null) {
|
||||||
mHTML5VideoView.pause();
|
mHTML5VideoView.pause();
|
||||||
mTimer.purge();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void onPrepared() {
|
public static void onPrepared() {
|
||||||
|
if (!mHTML5VideoView.isFullScreenMode() ||
|
||||||
|
mHTML5VideoView.isFullScreenMode() &&
|
||||||
|
mHTML5VideoView.getAutostart() )
|
||||||
mHTML5VideoView.start();
|
mHTML5VideoView.start();
|
||||||
mTimer.schedule(new TimeupdateTask(mCurrentProxy), TIMEUPDATE_PERIOD, TIMEUPDATE_PERIOD);
|
|
||||||
// TODO: [FULL SCREEN SUPPORT]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void end() {
|
public static void end() {
|
||||||
@@ -349,8 +320,6 @@ class HTML5VideoViewProxy extends Handler
|
|||||||
VideoPlayer.isVideoSelfEnded = true;
|
VideoPlayer.isVideoSelfEnded = true;
|
||||||
VideoPlayer.end();
|
VideoPlayer.end();
|
||||||
break;
|
break;
|
||||||
// TODO: [FULL SCREEN SUPPORT]
|
|
||||||
// For full screen case, end may need hide the view.
|
|
||||||
case ERROR: {
|
case ERROR: {
|
||||||
WebChromeClient client = mWebView.getWebChromeClient();
|
WebChromeClient client = mWebView.getWebChromeClient();
|
||||||
if (client != null) {
|
if (client != null) {
|
||||||
@@ -665,7 +634,7 @@ class HTML5VideoViewProxy extends Handler
|
|||||||
mPosterDownloader.start();
|
mPosterDownloader.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
// These two function are called from UI thread only by WebView.
|
// These three function are called from UI thread only by WebView.
|
||||||
public void setBaseLayer(int layer) {
|
public void setBaseLayer(int layer) {
|
||||||
VideoPlayer.setBaseLayer(layer);
|
VideoPlayer.setBaseLayer(layer);
|
||||||
}
|
}
|
||||||
@@ -673,6 +642,11 @@ class HTML5VideoViewProxy extends Handler
|
|||||||
public void pauseAndDispatch() {
|
public void pauseAndDispatch() {
|
||||||
VideoPlayer.pauseAndDispatch();
|
VideoPlayer.pauseAndDispatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void enterFullScreenVideo(int layerId, String url) {
|
||||||
|
VideoPlayer.enterFullScreenVideo(layerId, url, this, mWebView);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The factory for HTML5VideoViewProxy instances.
|
* The factory for HTML5VideoViewProxy instances.
|
||||||
* @param webViewCore is the WebViewCore that is requesting the proxy.
|
* @param webViewCore is the WebViewCore that is requesting the proxy.
|
||||||
|
|||||||
@@ -7860,7 +7860,11 @@ public class WebView extends AbsoluteLayout
|
|||||||
|
|
||||||
case ENTER_FULLSCREEN_VIDEO:
|
case ENTER_FULLSCREEN_VIDEO:
|
||||||
int layerId = msg.arg1;
|
int layerId = msg.arg1;
|
||||||
Log.v(LOGTAG, "Display the video layer " + layerId + " fullscreen");
|
|
||||||
|
String url = (String) msg.obj;
|
||||||
|
if (mHTML5VideoViewProxy != null) {
|
||||||
|
mHTML5VideoViewProxy.enterFullScreenVideo(layerId, url);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SHOW_FULLSCREEN: {
|
case SHOW_FULLSCREEN: {
|
||||||
|
|||||||
@@ -483,10 +483,12 @@ final class WebViewCore {
|
|||||||
/**
|
/**
|
||||||
* Notify the webview that we want to display the video layer fullscreen.
|
* Notify the webview that we want to display the video layer fullscreen.
|
||||||
*/
|
*/
|
||||||
protected void enterFullscreenForVideoLayer(int layerId) {
|
protected void enterFullscreenForVideoLayer(int layerId, String url) {
|
||||||
if (mWebView == null) return;
|
if (mWebView == null) return;
|
||||||
Message.obtain(mWebView.mPrivateHandler,
|
Message message = Message.obtain(mWebView.mPrivateHandler,
|
||||||
WebView.ENTER_FULLSCREEN_VIDEO, layerId, 0).sendToTarget();
|
WebView.ENTER_FULLSCREEN_VIDEO, layerId, 0);
|
||||||
|
message.obj = url;
|
||||||
|
message.sendToTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user