Android HTML5 video fullscreen and rotation
Asked Answered
T

1

6

i read the article Android WebView: handling orientation changes

and follow the tip i build a project MainActivity

package com.example.testvideo1;

import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBar;
import android.support.v4.app.Fragment;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.webkit.WebView;
import android.os.Build;

@SuppressLint("NewApi")
public class MainActivity extends ActionBarActivity {

    private VideoEnabledWebView webView;
    private VideoEnabledWebChromeClient webChromeClient;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Set layout
        setContentView(R.layout.activity_main);

        // Save the web view
        webView = (VideoEnabledWebView) findViewById(R.id.webView);

        // Initialize the VideoEnabledWebChromeClient and set event handlers
        View nonVideoLayout = findViewById(R.id.nonVideoLayout);
        // Your own  view,

        //Your own  view,
        ViewGroup videoLayout = (ViewGroup) findViewById(R.id.videoLayout);  
        View loadingView = null; // Your own view, read class comments
        webChromeClient = new VideoEnabledWebChromeClient(nonVideoLayout,
                videoLayout, loadingView, webView) // See all available
                                                    // constructors...
        {
            // Subscribe to standard events, such as onProgressChanged()...
            @Override
            public void onProgressChanged(WebView view, int progress) {
                // Your code...
            }
        };
        webChromeClient
                .setOnToggledFullscreen(new VideoEnabledWebChromeClient.ToggledFullscreenCallback() {
                    @Override
                    public void toggledFullscreen(boolean fullscreen) {
                        // Your code to handle the full-screen change, for
                        // example showing and hiding the title bar. Example:
                        if (fullscreen) {
                            WindowManager.LayoutParams attrs = getWindow()
                                    .getAttributes();
                            attrs.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
                            attrs.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
                            getWindow().setAttributes(attrs);
                            if (android.os.Build.VERSION.SDK_INT >= 14) {
                                getWindow()
                                        .getDecorView()
                                        .setSystemUiVisibility(
                                                View.SYSTEM_UI_FLAG_LOW_PROFILE);
                            }
                        } else {
                            WindowManager.LayoutParams attrs = getWindow()
                                    .getAttributes();
                            attrs.flags &= ~WindowManager.LayoutParams.FLAG_FULLSCREEN;
                            attrs.flags &= ~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
                            getWindow().setAttributes(attrs);
                            if (android.os.Build.VERSION.SDK_INT >= 14) {
                                getWindow().getDecorView()
                                        .setSystemUiVisibility(
                                                View.SYSTEM_UI_FLAG_VISIBLE);
                            }
                        }

                    }
                });
        webView.setWebChromeClient(webChromeClient);

        // Navigate everywhere you want, this classes have only been tested on
        // YouTube's mobile site
        webView.loadUrl("http://app.vlooks.cn/webchat/html5/2300/home");
    }

    @Override
    public void onBackPressed() {
        // Notify the VideoEnabledWebChromeClient, and handle it ourselves if it
        // doesn't handle it
        if (!webChromeClient.onBackPressed()) {
            if (webView.canGoBack()) {
                webView.goBack();
            } else {
                // Close app (presumably)
                super.onBackPressed();
            }
        }
    }


}

follow is VideoEnabledWebChromeClient.java

package com.example.testvideo1;

import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.webkit.WebChromeClient;
import android.widget.FrameLayout;

/**
 * This class serves as a WebChromeClient to be set to a WebView, allowing it to
 * play video. Video will play differently depending on target API level
 * (in-line, fullscreen, or both).
 * 
 * It has been tested with the following video classes: -
 * android.widget.VideoView (typically API level <11) -
 * android.webkit.HTML5VideoFullScreen$VideoSurfaceView/VideoTextureView
 * (typically API level 11-18) -
 * com.android.org.chromium.content.browser.ContentVideoView$VideoSurfaceView
 * (typically API level 19+)
 * 
 * Important notes: - For API level 11+, android:hardwareAccelerated="true" must
 * be set in the application manifest. - The invoking activity must call
 * VideoEnabledWebChromeClient's onBackPressed() inside of its own
 * onBackPressed(). - Tested in Android API levels 8-19. Only tested on
 * http://m.youtube.com.
 * 
 * @author Cristian Perez (http://cpr.name)
 * 
 */
public class VideoEnabledWebChromeClient extends WebChromeClient implements
        OnPreparedListener, OnCompletionListener, OnErrorListener {
    public interface ToggledFullscreenCallback {
        public void toggledFullscreen(boolean fullscreen);
    }

    private View activityNonVideoView;
    private ViewGroup activityVideoView;
    private View loadingView;
    private VideoEnabledWebView webView;

    private boolean isVideoFullscreen; // Indicates if the video is being
                                        // displayed using a custom view
                                        // (typically full-screen)
    private FrameLayout videoViewContainer;
    private CustomViewCallback videoViewCallback;

    private ToggledFullscreenCallback toggledFullscreenCallback;

    /**
     * Never use this constructor alone. This constructor allows this class to
     * be defined as an inline inner class in which the user can override
     * methods
     */
    @SuppressWarnings("unused")
    public VideoEnabledWebChromeClient() {
    }

    /**
     * Builds a video enabled WebChromeClient.
     * 
     * @param activityNonVideoView
     *            A View in the activity's layout that contains every other view
     *            that should be hidden when the video goes full-screen.
     * @param activityVideoView
     *            A ViewGroup in the activity's layout that will display the
     *            video. Typically you would like this to fill the whole layout.
     */
    @SuppressWarnings("unused")
    public VideoEnabledWebChromeClient(View activityNonVideoView,
            ViewGroup activityVideoView) {
        this.activityNonVideoView = activityNonVideoView;
        this.activityVideoView = activityVideoView;
        this.loadingView = null;
        this.webView = null;
        this.isVideoFullscreen = false;
    }

    /**
     * Builds a video enabled WebChromeClient.
     * 
     * @param activityNonVideoView
     *            A View in the activity's layout that contains every other view
     *            that should be hidden when the video goes full-screen.
     * @param activityVideoView
     *            A ViewGroup in the activity's layout that will display the
     *            video. Typically you would like this to fill the whole layout.
     * @param loadingView
     *            A View to be shown while the video is loading (typically only
     *            used in API level <11). Must be already inflated and without a
     *            parent view.
     */
    @SuppressWarnings("unused")
    public VideoEnabledWebChromeClient(View activityNonVideoView,
            ViewGroup activityVideoView, View loadingView) {
        this.activityNonVideoView = activityNonVideoView;
        this.activityVideoView = activityVideoView;
        this.loadingView = loadingView;
        this.webView = null;
        this.isVideoFullscreen = false;
    }

    /**
     * Builds a video enabled WebChromeClient.
     * 
     * @param activityNonVideoView
     *            A View in the activity's layout that contains every other view
     *            that should be hidden when the video goes full-screen.
     * @param activityVideoView
     *            A ViewGroup in the activity's layout that will display the
     *            video. Typically you would like this to fill the whole layout.
     * @param loadingView
     *            A View to be shown while the video is loading (typically only
     *            used in API level <11). Must be already inflated and without a
     *            parent view.
     * @param webView
     *            The owner VideoEnabledWebView. Passing it will enable the
     *            VideoEnabledWebChromeClient to detect the HTML5 video ended
     *            event and exit full-screen. Note: The web page must only
     *            contain one video tag in order for the HTML5 video ended event
     *            to work. This could be improved if needed (see Javascript
     *            code).
     */
    public VideoEnabledWebChromeClient(View activityNonVideoView,
            ViewGroup activityVideoView, View loadingView,
            VideoEnabledWebView webView) {
        this.activityNonVideoView = activityNonVideoView;
        this.activityVideoView = activityVideoView;
        this.loadingView = loadingView;
        this.webView = webView;
        this.isVideoFullscreen = false;
    }

    /**
     * Indicates if the video is being displayed using a custom view (typically
     * full-screen)
     * 
     * @return true it the video is being displayed using a custom view
     *         (typically full-screen)
     */
    public boolean isVideoFullscreen() {
        return isVideoFullscreen;
    }

    /**
     * Set a callback that will be fired when the video starts or finishes
     * displaying using a custom view (typically full-screen)
     * 
     * @param callback
     *            A VideoEnabledWebChromeClient.ToggledFullscreenCallback
     *            callback
     */
    public void setOnToggledFullscreen(ToggledFullscreenCallback callback) {
        this.toggledFullscreenCallback = callback;
    }

    @Override
    public void onShowCustomView(View view, CustomViewCallback callback) {
        if (view instanceof FrameLayout) {
            // A video wants to be shown
            FrameLayout frameLayout = (FrameLayout) view;
            View focusedChild = frameLayout.getFocusedChild();

            // Save video related variables
            this.isVideoFullscreen = true;
            this.videoViewContainer = frameLayout;
            this.videoViewCallback = callback;

            // Hide the non-video view, add the video view, and show it
            activityNonVideoView.setVisibility(View.INVISIBLE);
            activityVideoView.addView(videoViewContainer, new LayoutParams(
                    LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
            activityVideoView.setVisibility(View.VISIBLE);

            if (focusedChild instanceof android.widget.VideoView) {
                // android.widget.VideoView (typically API level <11)
                android.widget.VideoView videoView = (android.widget.VideoView) focusedChild;

                // Handle all the required events
                videoView.setOnPreparedListener(this);
                videoView.setOnCompletionListener(this);
                videoView.setOnErrorListener(this);
            } else {
                // Other classes, including:
                // - android.webkit.HTML5VideoFullScreen$VideoSurfaceView, which
                // inherits from android.view.SurfaceView (typically API level
                // 11-18)
                // - android.webkit.HTML5VideoFullScreen$VideoTextureView, which
                // inherits from android.view.TextureView (typically API level
                // 11-18)
                // -
                // com.android.org.chromium.content.browser.ContentVideoView$VideoSurfaceView,
                // which inherits from android.view.SurfaceView (typically API
                // level 19+)

                // Handle HTML5 video ended event only if the class is a
                // SurfaceView
                // Test case: TextureView of Sony Xperia T API level 16 doesn't
                // work fullscreen when loading the javascript below
                if (webView != null
                        && webView.getSettings().getJavaScriptEnabled()
                        && focusedChild instanceof SurfaceView) {
                    // Run javascript code that detects the video end and
                    // notifies the Javascript interface
                    String js = "javascript:";
                    js += "var _ytrp_html5_video_last;";
                    js += "var _ytrp_html5_video = document.getElementsByTagName('video')[0];";
                    js += "if (_ytrp_html5_video != undefined && _ytrp_html5_video != _ytrp_html5_video_last) {";
                    {
                        js += "_ytrp_html5_video_last = _ytrp_html5_video;";
                        js += "function _ytrp_html5_video_ended() {";
                        {
                            js += "_VideoEnabledWebView.notifyVideoEnd();"; // Must
                                                                            // match
                                                                            // Javascript
                                                                            // interface
                                                                            // name
                                                                            // and
                                                                            // method
                                                                            // of
                                                                            // VideoEnableWebView
                        }
                        js += "}";
                        js += "_ytrp_html5_video.addEventListener('ended', _ytrp_html5_video_ended);";
                    }
                    js += "}";
                    webView.loadUrl(js);
                }
            }

            // Notify full-screen change
            if (toggledFullscreenCallback != null) {
                toggledFullscreenCallback.toggledFullscreen(true);
            }
        }
    }

    @Override
    @SuppressWarnings("deprecation")
    public void onShowCustomView(View view, int requestedOrientation,
            CustomViewCallback callback) // Available in API level 14+,
                                            // deprecated in API level 18+
    {
        onShowCustomView(view, callback);
    }

    @Override
    public void onHideCustomView() {
        // This method should be manually called on video end in all cases
        // because it's not always called automatically.
        // This method must be manually called on back key press (from this
        // class' onBackPressed() method).

        if (isVideoFullscreen) {
            // Hide the video view, remove it, and show the non-video view
            activityVideoView.setVisibility(View.INVISIBLE);
            activityVideoView.removeView(videoViewContainer);
            activityNonVideoView.setVisibility(View.VISIBLE);

            // Call back (only in API level <19, because in API level 19+ with
            // chromium webview it crashes)
            if (videoViewCallback != null
                    && !videoViewCallback.getClass().getName()
                            .contains(".chromium.")) {
                videoViewCallback.onCustomViewHidden();
            }

            // Reset video related variables
            isVideoFullscreen = false;
            videoViewContainer = null;
            videoViewCallback = null;

            // Notify full-screen change
            if (toggledFullscreenCallback != null) {
                toggledFullscreenCallback.toggledFullscreen(false);
            }
        }
    }

    @Override
    public View getVideoLoadingProgressView() // Video will start loading, only
                                                // called in the case of
                                                // VideoView (typically API
                                                // level 10-)
    {
        if (loadingView == null) {
            return super.getVideoLoadingProgressView();
        } else {
            loadingView.setVisibility(View.VISIBLE);
            return loadingView;
        }
    }

    @Override
    public void onPrepared(MediaPlayer mp) // Video will start playing, only
                                            // called in the case of
                                            // android.widget.VideoView
                                            // (typically API level <11)
    {
        if (loadingView != null) {
            loadingView.setVisibility(View.GONE);
        }
    }

    @Override
    public void onCompletion(MediaPlayer mp) // Video finished playing, only
                                                // called in the case of
                                                // android.widget.VideoView
                                                // (typically API level <11)
    {
        onHideCustomView();
    }

    @Override
    public boolean onError(MediaPlayer mp, int what, int extra) // Error while
                                                                // playing
                                                                // video, only
                                                                // called in the
                                                                // case of
                                                                // android.widget.VideoView
                                                                // (typically
                                                                // API level
                                                                // <11)
    {
        return false; // By returning false, onCompletion() will be called
    }

    /**
     * Notifies the class that the back key has been pressed by the user. This
     * must be called from the Activity's onBackPressed(), and if it returns
     * false, the activity itself should handle it. Otherwise don't do anything.
     * 
     * @return Returns true if the event was handled, and false if was not
     *         (video view is not visible)
     */
    public boolean onBackPressed() {
        if (isVideoFullscreen) {
            onHideCustomView();
            return true;
        } else {
            return false;
        }
    }

}

and VideoEnabledWebView.java

package com.example.testvideo1;

import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
import android.webkit.WebChromeClient;
import android.webkit.WebView;

import java.util.Map;

/**
 * This class serves as a WebView to be used in conjunction with a
 * VideoEnabledWebChromeClient. It makes possible: - To detect the HTML5 video
 * ended event so that the VideoEnabledWebChromeClient can exit full-screen.
 * 
 * Important notes: - Javascript is enabled by default and must not be disabled
 * with getSettings().setJavaScriptEnabled(false). - setWebChromeClient() must
 * be called before any loadData(), loadDataWithBaseURL() or loadUrl() method.
 * 
 * @author Cristian Perez (http://cpr.name)
 * 
 */
public class VideoEnabledWebView extends WebView {
    public class JavascriptInterface {
        @android.webkit.JavascriptInterface
        public void notifyVideoEnd() // Must match Javascript interface method
                                        // of VideoEnabledWebChromeClient
        {
            // This code is not executed in the UI thread, so we must force that
            // to happen
            new Handler(Looper.getMainLooper()).post(new Runnable() {
                @Override
                public void run() {
                    if (videoEnabledWebChromeClient != null) {
                        videoEnabledWebChromeClient.onHideCustomView();
                    }
                }
            });
        }
    }

    private VideoEnabledWebChromeClient videoEnabledWebChromeClient;
    private boolean addedJavascriptInterface;

    public VideoEnabledWebView(Context context) {
        super(context);
        addedJavascriptInterface = false;
    }

    @SuppressWarnings("unused")
    public VideoEnabledWebView(Context context, AttributeSet attrs) {
        super(context, attrs);
        addedJavascriptInterface = false;
    }

    @SuppressWarnings("unused")
    public VideoEnabledWebView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        addedJavascriptInterface = false;
    }

    /**
     * Indicates if the video is being displayed using a custom view (typically
     * full-screen)
     * 
     * @return true it the video is being displayed using a custom view
     *         (typically full-screen)
     */
    public boolean isVideoFullscreen() {
        return videoEnabledWebChromeClient != null
                && videoEnabledWebChromeClient.isVideoFullscreen();
    }

    /**
     * Pass only a VideoEnabledWebChromeClient instance.
     */
    @Override
    @SuppressLint("SetJavaScriptEnabled")
    public void setWebChromeClient(WebChromeClient client) {
        getSettings().setJavaScriptEnabled(true);

        if (client instanceof VideoEnabledWebChromeClient) {
            this.videoEnabledWebChromeClient = (VideoEnabledWebChromeClient) client;
        }

        super.setWebChromeClient(client);
    }

    @Override
    public void loadData(String data, String mimeType, String encoding) {
        addJavascriptInterface();
        super.loadData(data, mimeType, encoding);
    }

    @Override
    public void loadDataWithBaseURL(String baseUrl, String data,
            String mimeType, String encoding, String historyUrl) {
        addJavascriptInterface();
        super.loadDataWithBaseURL(baseUrl, data, mimeType, encoding, historyUrl);
    }

    @Override
    public void loadUrl(String url) {
        addJavascriptInterface();
        super.loadUrl(url);
    }

    @Override
    public void loadUrl(String url, Map<String, String> additionalHttpHeaders) {
        addJavascriptInterface();
        super.loadUrl(url, additionalHttpHeaders);
    }

    private void addJavascriptInterface() {
        if (!addedJavascriptInterface) {
            // Add javascript interface to be called when the video ends (must
            // be done before page load)
            addJavascriptInterface(new JavascriptInterface(),
                    "_VideoEnabledWebView"); // Must match Javascript interface
                                                // name of
                                                // VideoEnabledWebChromeClient

            addedJavascriptInterface = true;
        }
    }

}

and the layout file

<!-- View that will be hidden when video goes fullscreen -->
<RelativeLayout
    android:id="@+id/nonVideoLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <com.example.VideoEnabledWebView
        android:id="@+id/webView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>   

<!-- View where the video will be shown when video goes fullscreen -->
<RelativeLayout
    android:id="@+id/videoLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <!-- View that will be shown while the fullscreen video loads (maybe include a spinner and a "Loading..." message) -->
    <View
        android:id="@+id/videoLoading"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:visibility="invisible" />

</RelativeLayout>

the project can't work, and i want when fullscreen , let the program go LandScape mode. but i failed.

thanks.......

Tudela answered 22/5, 2014 at 9:34 Comment(1)
hey, did you ever solve this problem? thanksUngley
B
3

I've been facing the same issue. Although this question is quite old, I have come to a simple solution which I could not find on stack overflow.

Just enforce Landscape when going full screen: activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

And revert this, when going back.

In context:

public class BaseWebChromeClient extends WebChromeClient 
{
    @Override
    public void onShowCustomView(View view, WebChromeClient.CustomViewCallback callback) 
    {
        [...]

        act.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

        [...]

    @Override
    public void onHideCustomView(View view, WebChromeClient.CustomViewCallback callback) 
    {
        [...]

        act.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 
        // use SCREEN_ORIENTATION_SENSOR, if you don't to enforce portrait mode.

        [...]
    }
}
Backhanded answered 9/9, 2019 at 10:53 Comment(3)
This gives me an error: cannot resolve method setRequestedOrientation I'm using it as mCustomViewContainer.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);Mismate
It worked when I removed mCustomViewContainer.. Thank you so much! Also, You need to set android:configChanges="keyboard|keyboardHidden|orientation|screenSize" on AndroidManifest.xml as well to make it work properly.Mismate
However, the video itself may be portrait.Sievers

© 2022 - 2024 — McMap. All rights reserved.