HTML5VideoViewProxy.java revision 96fae5e088916e1da8d4afaf40758ceec6e7187a
16fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu/*
26fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu * Copyright (C) 2009 The Android Open Source Project
36fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu *
46fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu * Licensed under the Apache License, Version 2.0 (the "License");
56fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu * you may not use this file except in compliance with the License.
66fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu * You may obtain a copy of the License at
76fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu *
86fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu *      http://www.apache.org/licenses/LICENSE-2.0
96fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu *
106fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu * Unless required by applicable law or agreed to in writing, software
116fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu * distributed under the License is distributed on an "AS IS" BASIS,
126fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu * See the License for the specific language governing permissions and
146fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu * limitations under the License.
156fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu */
166fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu
176fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescupackage android.webkit;
186fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu
196fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescuimport android.content.Context;
2064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescuimport android.graphics.Bitmap;
2164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescuimport android.graphics.BitmapFactory;
22661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhuimport android.graphics.SurfaceTexture;
233c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescuimport android.media.MediaPlayer;
2464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescuimport android.net.http.EventHandler;
2564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescuimport android.net.http.Headers;
2664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescuimport android.net.http.RequestHandle;
2764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescuimport android.net.http.RequestQueue;
2864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescuimport android.net.http.SslCertificate;
2964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescuimport android.net.http.SslError;
306fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescuimport android.os.Handler;
316fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescuimport android.os.Looper;
326fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescuimport android.os.Message;
336fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescuimport android.util.Log;
346fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu
3564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescuimport java.io.ByteArrayOutputStream;
3664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescuimport java.io.IOException;
3742509799f261c844bf6be66ce630c47bdee620f3Ben Murdochimport java.net.MalformedURLException;
3842509799f261c844bf6be66ce630c47bdee620f3Ben Murdochimport java.net.URL;
396fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescuimport java.util.HashMap;
40290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescuimport java.util.Map;
416fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu
426fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu/**
433c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu * <p>Proxy for HTML5 video views.
446fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu */
45290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescuclass HTML5VideoViewProxy extends Handler
46290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                          implements MediaPlayer.OnPreparedListener,
4750c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                          MediaPlayer.OnCompletionListener,
48661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                          MediaPlayer.OnErrorListener,
49c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu                          MediaPlayer.OnInfoListener,
50661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                          SurfaceTexture.OnFrameAvailableListener {
516fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu    // Logging tag.
526fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu    private static final String LOGTAG = "HTML5VideoViewProxy";
536fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu
543c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu    // Message Ids for WebCore thread -> UI thread communication.
5550c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    private static final int PLAY                = 100;
5650c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    private static final int SEEK                = 101;
5750c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    private static final int PAUSE               = 102;
5850c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    private static final int ERROR               = 103;
5950c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    private static final int LOAD_DEFAULT_POSTER = 104;
60c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu    private static final int BUFFERING_START     = 105;
61c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu    private static final int BUFFERING_END       = 106;
626fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu
6364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    // Message Ids to be handled on the WebCore thread
64290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    private static final int PREPARED          = 200;
65290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    private static final int ENDED             = 201;
6650c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    private static final int POSTER_FETCHED    = 202;
6743aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang    private static final int PAUSED            = 203;
68b109c8877139077fe25fa26ea2e0961b7cbb8341Teng-Hui Zhu    private static final int STOPFULLSCREEN    = 204;
69e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu    private static final int RESTORESTATE      = 205;
7064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu
71048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu    // Timer thread -> UI thread
72048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu    private static final int TIMEUPDATE = 300;
73048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu
74290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    // The C++ MediaPlayerPrivateAndroid object.
75290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    int mNativePointer;
7664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    // The handler for WebCore thread messages;
7764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    private Handler mWebCoreHandler;
783c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu    // The WebView instance that created this view.
793c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu    private WebView mWebView;
8064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    // The poster image to be shown when the video is not playing.
8150c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    // This ref prevents the bitmap from being GC'ed.
8250c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    private Bitmap mPoster;
8364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    // The poster downloader.
8464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    private PosterDownloader mPosterDownloader;
85290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    // The seek position.
86290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    private int mSeekPosition;
8764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    // A helper class to control the playback. This executes on the UI thread!
8864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    private static final class VideoPlayer {
8964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // The proxy that is currently playing (if any).
9064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private static HTML5VideoViewProxy mCurrentProxy;
9164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // The VideoView instance. This is a singleton for now, at least until
9264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // http://b/issue?id=1973663 is fixed.
93661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        private static HTML5VideoView mHTML5VideoView;
94048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu
95661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        private static boolean isVideoSelfEnded = false;
96661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // By using the baseLayer and the current video Layer ID, we can
97661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // identify the exact layer on the UI thread to use the SurfaceTexture.
98661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        private static int mBaseLayer = 0;
99661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu
100f4d4e9e05f7605118910739c16e493e2ab869aaeTeng-Hui Zhu        private static void setPlayerBuffering(boolean playerBuffering) {
101f4d4e9e05f7605118910739c16e493e2ab869aaeTeng-Hui Zhu            mHTML5VideoView.setPlayerBuffering(playerBuffering);
102f4d4e9e05f7605118910739c16e493e2ab869aaeTeng-Hui Zhu        }
103f4d4e9e05f7605118910739c16e493e2ab869aaeTeng-Hui Zhu
104661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // Every time webView setBaseLayer, this will be called.
105661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // When we found the Video layer, then we set the Surface Texture to it.
106661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // Otherwise, we may want to delete the Surface Texture to save memory.
107661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        public static void setBaseLayer(int layer) {
10810ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu            // Don't do this for full screen mode.
10910ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu            if (mHTML5VideoView != null
1103fafd39d0776a15c3613795183043a2c28277691Teng-Hui Zhu                && !mHTML5VideoView.isFullScreenMode()
1113fafd39d0776a15c3613795183043a2c28277691Teng-Hui Zhu                && !mHTML5VideoView.surfaceTextureDeleted()) {
112661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                mBaseLayer = layer;
113661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu
114661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                int currentVideoLayerId = mHTML5VideoView.getVideoLayerId();
1153fafd39d0776a15c3613795183043a2c28277691Teng-Hui Zhu                SurfaceTexture surfTexture = mHTML5VideoView.getSurfaceTexture(currentVideoLayerId);
1163fafd39d0776a15c3613795183043a2c28277691Teng-Hui Zhu                int textureName = mHTML5VideoView.getTextureName();
1173fafd39d0776a15c3613795183043a2c28277691Teng-Hui Zhu
118661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                if (layer != 0 && surfTexture != null && currentVideoLayerId != -1) {
119265db32f31a9db60d4a93d59befa07c825cbe4f2Teng-Hui Zhu                    int playerState = mHTML5VideoView.getCurrentState();
120f4d4e9e05f7605118910739c16e493e2ab869aaeTeng-Hui Zhu                    if (mHTML5VideoView.getPlayerBuffering())
121c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu                        playerState = HTML5VideoView.STATE_NOTPREPARED;
122661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                    boolean foundInTree = nativeSendSurfaceTexture(surfTexture,
123661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                            layer, currentVideoLayerId, textureName,
124265db32f31a9db60d4a93d59befa07c825cbe4f2Teng-Hui Zhu                            playerState);
1251e26d82ffaf983dc288152cfe8c0a821de33f2a4Teng-Hui Zhu                    if (playerState >= HTML5VideoView.STATE_PREPARED
126265db32f31a9db60d4a93d59befa07c825cbe4f2Teng-Hui Zhu                            && !foundInTree) {
127661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                        mHTML5VideoView.pauseAndDispatch(mCurrentProxy);
128661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                        mHTML5VideoView.deleteSurfaceTexture();
12931d2aa1e17f1ee580edb762a6ef634098bba02bbAndrei Popescu                    }
13064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                }
131661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            }
132661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        }
133661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu
134661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // When a WebView is paused, we also want to pause the video in it.
135661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        public static void pauseAndDispatch() {
136661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            if (mHTML5VideoView != null) {
137661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                mHTML5VideoView.pauseAndDispatch(mCurrentProxy);
138661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                // When switching out, clean the video content on the old page
139661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                // by telling the layer not readyToUseSurfTex.
140661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                setBaseLayer(mBaseLayer);
141661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            }
142661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        }
14364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu
14410ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu        public static void enterFullScreenVideo(int layerId, String url,
14510ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                HTML5VideoViewProxy proxy, WebView webView) {
14610ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                // Save the inline video info and inherit it in the full screen
14710ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                int savePosition = 0;
14810ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                if (mHTML5VideoView != null) {
14910ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                    // If we are playing the same video, then it is better to
15010ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                    // save the current position.
15110ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                    if (layerId == mHTML5VideoView.getVideoLayerId()) {
15210ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                        savePosition = mHTML5VideoView.getCurrentPosition();
15310ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                    }
15410ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                    mHTML5VideoView.release();
15510ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                }
15610ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                mHTML5VideoView = new HTML5VideoFullScreen(proxy.getContext(),
157e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu                        layerId, savePosition);
15810ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                mCurrentProxy = proxy;
15910ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu
16010ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                mHTML5VideoView.setVideoURI(url, mCurrentProxy);
16110ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu
16210ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                mHTML5VideoView.enterFullScreenVideoState(layerId, proxy, webView);
16310ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu        }
16410ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu
165d7678a1684966cac10717b34b161b5241b9865c5Teng-Hui Zhu        public static void exitFullScreenVideo(HTML5VideoViewProxy proxy,
166d7678a1684966cac10717b34b161b5241b9865c5Teng-Hui Zhu                WebView webView) {
167d7678a1684966cac10717b34b161b5241b9865c5Teng-Hui Zhu            if (!mHTML5VideoView.fullScreenExited() && mHTML5VideoView.isFullScreenMode()) {
168d7678a1684966cac10717b34b161b5241b9865c5Teng-Hui Zhu                WebChromeClient client = webView.getWebChromeClient();
169d7678a1684966cac10717b34b161b5241b9865c5Teng-Hui Zhu                if (client != null) {
170d7678a1684966cac10717b34b161b5241b9865c5Teng-Hui Zhu                    client.onHideCustomView();
171d7678a1684966cac10717b34b161b5241b9865c5Teng-Hui Zhu                }
172d7678a1684966cac10717b34b161b5241b9865c5Teng-Hui Zhu            }
173d7678a1684966cac10717b34b161b5241b9865c5Teng-Hui Zhu        }
174d7678a1684966cac10717b34b161b5241b9865c5Teng-Hui Zhu
175661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // This is on the UI thread.
176661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // When native tell Java to play, we need to check whether or not it is
177661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // still the same video by using videoLayerId and treat it differently.
178290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        public static void play(String url, int time, HTML5VideoViewProxy proxy,
179661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                WebChromeClient client, int videoLayerId) {
180661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            int currentVideoLayerId = -1;
18110ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu            boolean backFromFullScreenMode = false;
18210ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu            if (mHTML5VideoView != null) {
183661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                currentVideoLayerId = mHTML5VideoView.getVideoLayerId();
1841a88acbed9cd04d7c8ddd0c33a15926238157a07Teng-Hui Zhu                backFromFullScreenMode = mHTML5VideoView.fullScreenExited();
18596fae5e088916e1da8d4afaf40758ceec6e7187aTeng-Hui Zhu
18696fae5e088916e1da8d4afaf40758ceec6e7187aTeng-Hui Zhu                // When playing video back to back in full screen mode,
18796fae5e088916e1da8d4afaf40758ceec6e7187aTeng-Hui Zhu                // javascript will switch the src and call play.
18896fae5e088916e1da8d4afaf40758ceec6e7187aTeng-Hui Zhu                // In this case, we can just reuse the same full screen view,
18996fae5e088916e1da8d4afaf40758ceec6e7187aTeng-Hui Zhu                // and play the video after prepared.
19096fae5e088916e1da8d4afaf40758ceec6e7187aTeng-Hui Zhu                if (mHTML5VideoView.isFullScreenMode()
19196fae5e088916e1da8d4afaf40758ceec6e7187aTeng-Hui Zhu                    && !backFromFullScreenMode
19296fae5e088916e1da8d4afaf40758ceec6e7187aTeng-Hui Zhu                    && currentVideoLayerId != videoLayerId
19396fae5e088916e1da8d4afaf40758ceec6e7187aTeng-Hui Zhu                    && mCurrentProxy != proxy) {
19496fae5e088916e1da8d4afaf40758ceec6e7187aTeng-Hui Zhu                    mCurrentProxy = proxy;
19596fae5e088916e1da8d4afaf40758ceec6e7187aTeng-Hui Zhu                    mHTML5VideoView.setStartWhenPrepared(true);
19696fae5e088916e1da8d4afaf40758ceec6e7187aTeng-Hui Zhu                    mHTML5VideoView.setVideoURI(url, proxy);
19796fae5e088916e1da8d4afaf40758ceec6e7187aTeng-Hui Zhu                    mHTML5VideoView.reprepareData(proxy);
19896fae5e088916e1da8d4afaf40758ceec6e7187aTeng-Hui Zhu                    return;
19996fae5e088916e1da8d4afaf40758ceec6e7187aTeng-Hui Zhu                }
20010ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu            }
201661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu
20210ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu            if (backFromFullScreenMode
2033fafd39d0776a15c3613795183043a2c28277691Teng-Hui Zhu                || currentVideoLayerId != videoLayerId
2043fafd39d0776a15c3613795183043a2c28277691Teng-Hui Zhu                || mHTML5VideoView.surfaceTextureDeleted()) {
205661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                // Here, we handle the case when switching to a new video,
206661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                // either inside a WebView or across WebViews
207661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                // For switching videos within a WebView or across the WebView,
208661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                // we need to pause the old one and re-create a new media player
209661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                // inside the HTML5VideoView.
210661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                if (mHTML5VideoView != null) {
21122954d435d645d48885f653bd4ca6bc79e1bcd83Teng-Hui Zhu                    if (!backFromFullScreenMode) {
21222954d435d645d48885f653bd4ca6bc79e1bcd83Teng-Hui Zhu                        mHTML5VideoView.pauseAndDispatch(mCurrentProxy);
21322954d435d645d48885f653bd4ca6bc79e1bcd83Teng-Hui Zhu                    }
214661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                    // release the media player to avoid finalize error
215661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                    mHTML5VideoView.release();
216a41f97bd77f2583e2e3698cfbba62230a8ac4789Andrei Popescu                }
217661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                mCurrentProxy = proxy;
218e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu                mHTML5VideoView = new HTML5VideoInline(videoLayerId, time);
219a41f97bd77f2583e2e3698cfbba62230a8ac4789Andrei Popescu
22010ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                mHTML5VideoView.setVideoURI(url, mCurrentProxy);
22110ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                mHTML5VideoView.prepareDataAndDisplayMode(proxy);
222661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            } else if (mCurrentProxy == proxy) {
223661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                // Here, we handle the case when we keep playing with one video
224661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                if (!mHTML5VideoView.isPlaying()) {
225661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                    mHTML5VideoView.seekTo(time);
226661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                    mHTML5VideoView.start();
227661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                }
228661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            } else if (mCurrentProxy != null) {
22910ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                // Some other video is already playing. Notify the caller that
23010ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                // its playback ended.
231661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                proxy.dispatchOnEnded();
232bf385d7c7b093564738f8cfd4386daf5e94b8a6dAndrei Popescu            }
23364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
234290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu
235048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu        public static boolean isPlaying(HTML5VideoViewProxy proxy) {
236661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            return (mCurrentProxy == proxy && mHTML5VideoView != null
237661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                    && mHTML5VideoView.isPlaying());
238048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu        }
239048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu
240048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu        public static int getCurrentPosition() {
241048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu            int currentPosMs = 0;
242661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            if (mHTML5VideoView != null) {
243661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                currentPosMs = mHTML5VideoView.getCurrentPosition();
244048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu            }
245048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu            return currentPosMs;
246048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu        }
247048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu
248290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        public static void seek(int time, HTML5VideoViewProxy proxy) {
249661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            if (mCurrentProxy == proxy && time >= 0 && mHTML5VideoView != null) {
250661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                mHTML5VideoView.seekTo(time);
251290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu            }
252290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        }
253290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu
254290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        public static void pause(HTML5VideoViewProxy proxy) {
255661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            if (mCurrentProxy == proxy && mHTML5VideoView != null) {
256661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                mHTML5VideoView.pause();
257290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu            }
258290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        }
259bf385d7c7b093564738f8cfd4386daf5e94b8a6dAndrei Popescu
260bf385d7c7b093564738f8cfd4386daf5e94b8a6dAndrei Popescu        public static void onPrepared() {
261e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu            if (!mHTML5VideoView.isFullScreenMode()) {
2620504967cb05f7bbd0c17962360a5d88ace8d173fTeng-Hui Zhu                mHTML5VideoView.start();
2630504967cb05f7bbd0c17962360a5d88ace8d173fTeng-Hui Zhu            }
264265db32f31a9db60d4a93d59befa07c825cbe4f2Teng-Hui Zhu            if (mBaseLayer != 0) {
265265db32f31a9db60d4a93d59befa07c825cbe4f2Teng-Hui Zhu                setBaseLayer(mBaseLayer);
266265db32f31a9db60d4a93d59befa07c825cbe4f2Teng-Hui Zhu            }
267661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        }
268661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu
269661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        public static void end() {
270661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            if (mCurrentProxy != null) {
271661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                if (isVideoSelfEnded)
272661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                    mCurrentProxy.dispatchOnEnded();
273661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                else
274661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                    mCurrentProxy.dispatchOnPaused();
275661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            }
276661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            isVideoSelfEnded = false;
277bf385d7c7b093564738f8cfd4386daf5e94b8a6dAndrei Popescu        }
278290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    }
279290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu
280290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    // A bunch event listeners for our VideoView
281290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    // MediaPlayer.OnPreparedListener
282290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    public void onPrepared(MediaPlayer mp) {
283bf385d7c7b093564738f8cfd4386daf5e94b8a6dAndrei Popescu        VideoPlayer.onPrepared();
284290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        Message msg = Message.obtain(mWebCoreHandler, PREPARED);
285290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        Map<String, Object> map = new HashMap<String, Object>();
286290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        map.put("dur", new Integer(mp.getDuration()));
287290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        map.put("width", new Integer(mp.getVideoWidth()));
288290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        map.put("height", new Integer(mp.getVideoHeight()));
289290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        msg.obj = map;
290290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        mWebCoreHandler.sendMessage(msg);
291290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    }
292290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu
293290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    // MediaPlayer.OnCompletionListener;
294290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    public void onCompletion(MediaPlayer mp) {
295c4fbceb57bcfbabb6e370e2dd6448184dc116015Andrei Popescu        // The video ended by itself, so we need to
296c4fbceb57bcfbabb6e370e2dd6448184dc116015Andrei Popescu        // send a message to the UI thread to dismiss
297c4fbceb57bcfbabb6e370e2dd6448184dc116015Andrei Popescu        // the video view and to return to the WebView.
29843aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang        // arg1 == 1 means the video ends by itself.
29943aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang        sendMessage(obtainMessage(ENDED, 1, 0));
300290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    }
301290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu
30250c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    // MediaPlayer.OnErrorListener
30350c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    public boolean onError(MediaPlayer mp, int what, int extra) {
30450c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu        sendMessage(obtainMessage(ERROR));
30550c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu        return false;
30650c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    }
30750c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu
308c4fbceb57bcfbabb6e370e2dd6448184dc116015Andrei Popescu    public void dispatchOnEnded() {
309290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        Message msg = Message.obtain(mWebCoreHandler, ENDED);
310290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        mWebCoreHandler.sendMessage(msg);
31164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    }
3123c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu
31343aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang    public void dispatchOnPaused() {
314b109c8877139077fe25fa26ea2e0961b7cbb8341Teng-Hui Zhu        Message msg = Message.obtain(mWebCoreHandler, PAUSED);
315b109c8877139077fe25fa26ea2e0961b7cbb8341Teng-Hui Zhu        mWebCoreHandler.sendMessage(msg);
316b109c8877139077fe25fa26ea2e0961b7cbb8341Teng-Hui Zhu    }
317b109c8877139077fe25fa26ea2e0961b7cbb8341Teng-Hui Zhu
318b109c8877139077fe25fa26ea2e0961b7cbb8341Teng-Hui Zhu    public void dispatchOnStopFullScreen() {
319b109c8877139077fe25fa26ea2e0961b7cbb8341Teng-Hui Zhu        Message msg = Message.obtain(mWebCoreHandler, STOPFULLSCREEN);
320b109c8877139077fe25fa26ea2e0961b7cbb8341Teng-Hui Zhu        mWebCoreHandler.sendMessage(msg);
32143aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang    }
32243aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang
323e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu    public void dispatchOnRestoreState() {
324e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu        Message msg = Message.obtain(mWebCoreHandler, RESTORESTATE);
325e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu        mWebCoreHandler.sendMessage(msg);
326e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu    }
327e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu
328048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu    public void onTimeupdate() {
329048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu        sendMessage(obtainMessage(TIMEUPDATE));
330048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu    }
331048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu
332661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu    // When there is a frame ready from surface texture, we should tell WebView
333661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu    // to refresh.
334661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu    @Override
335661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu    public void onFrameAvailable(SurfaceTexture surfaceTexture) {
336661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // TODO: This should support partial invalidation too.
337661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        mWebView.invalidate();
338661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu    }
339661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu
340048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu    // Handler for the messages from WebCore or Timer thread to the UI thread.
34164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    @Override
34264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    public void handleMessage(Message msg) {
34364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // This executes on the UI thread.
34464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        switch (msg.what) {
34564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            case PLAY: {
34664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                String url = (String) msg.obj;
34764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                WebChromeClient client = mWebView.getWebChromeClient();
348661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                int videoLayerID = msg.arg1;
34964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                if (client != null) {
350661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                    VideoPlayer.play(url, mSeekPosition, this, client, videoLayerID);
35164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                }
35264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                break;
35364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            }
354290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu            case SEEK: {
355290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                Integer time = (Integer) msg.obj;
356290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                mSeekPosition = time;
357290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                VideoPlayer.seek(mSeekPosition, this);
358290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                break;
359290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu            }
360290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu            case PAUSE: {
361290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                VideoPlayer.pause(this);
362290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                break;
363290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu            }
36446a83b4ead517b9fc13b4bee4c59c3eaf4d3fdd9Andrei Popescu            case ENDED:
36543aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang                if (msg.arg1 == 1)
36643aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang                    VideoPlayer.isVideoSelfEnded = true;
367661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                VideoPlayer.end();
368661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                break;
36950c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu            case ERROR: {
37050c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                WebChromeClient client = mWebView.getWebChromeClient();
37150c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                if (client != null) {
37250c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                    client.onHideCustomView();
37350c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                }
37450c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                break;
37550c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu            }
37650c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu            case LOAD_DEFAULT_POSTER: {
37750c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                WebChromeClient client = mWebView.getWebChromeClient();
37850c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                if (client != null) {
37950c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                    doSetPoster(client.getDefaultVideoPoster());
38050c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                }
38150c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                break;
38250c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu            }
383048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu            case TIMEUPDATE: {
384048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu                if (VideoPlayer.isPlaying(this)) {
385048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu                    sendTimeupdate();
386048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu                }
387048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu                break;
388048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu            }
389c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu            case BUFFERING_START: {
390f4d4e9e05f7605118910739c16e493e2ab869aaeTeng-Hui Zhu                VideoPlayer.setPlayerBuffering(true);
391c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu                break;
392c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu            }
393c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu            case BUFFERING_END: {
394f4d4e9e05f7605118910739c16e493e2ab869aaeTeng-Hui Zhu                VideoPlayer.setPlayerBuffering(false);
395c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu                break;
396c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu            }
39764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
39864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    }
39964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu
40064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    // Everything below this comment executes on the WebCore thread, except for
40164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    // the EventHandler methods, which are called on the network thread.
40264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu
40364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    // A helper class that knows how to download posters
40464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    private static final class PosterDownloader implements EventHandler {
40564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // The request queue. This is static as we have one queue for all posters.
40664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private static RequestQueue mRequestQueue;
40764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private static int mQueueRefCount = 0;
40864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // The poster URL
40942509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch        private URL mUrl;
41064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // The proxy we're doing this for.
41164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private final HTML5VideoViewProxy mProxy;
41264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // The poster bytes. We only touch this on the network thread.
41364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private ByteArrayOutputStream mPosterBytes;
41464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // The request handle. We only touch this on the WebCore thread.
41564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private RequestHandle mRequestHandle;
41664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // The response status code.
41764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private int mStatusCode;
41864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // The response headers.
41964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private Headers mHeaders;
42064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // The handler to handle messages on the WebCore thread.
42164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private Handler mHandler;
42264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu
42364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        public PosterDownloader(String url, HTML5VideoViewProxy proxy) {
42442509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch            try {
42542509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch                mUrl = new URL(url);
42642509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch            } catch (MalformedURLException e) {
42742509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch                mUrl = null;
42842509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch            }
42964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            mProxy = proxy;
43064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            mHandler = new Handler();
43164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
43264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // Start the download. Called on WebCore thread.
43364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        public void start() {
43464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            retainQueue();
43542509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch
43642509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch            if (mUrl == null) {
43742509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch                return;
43842509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch            }
43942509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch
44042509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch            // Only support downloading posters over http/https.
44142509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch            // FIXME: Add support for other schemes. WebKit seems able to load
44242509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch            // posters over other schemes e.g. file://, but gets the dimensions wrong.
44342509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch            String protocol = mUrl.getProtocol();
44442509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch            if ("http".equals(protocol) || "https".equals(protocol)) {
44542509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch                mRequestHandle = mRequestQueue.queueRequest(mUrl.toString(), "GET", null,
44642509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch                        this, null, 0);
44742509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch            }
44864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
44964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // Cancel the download if active and release the queue. Called on WebCore thread.
45064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        public void cancelAndReleaseQueue() {
45164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            if (mRequestHandle != null) {
45264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                mRequestHandle.cancel();
45364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                mRequestHandle = null;
45464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            }
45564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            releaseQueue();
45664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
45764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // EventHandler methods. Executed on the network thread.
45864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        public void status(int major_version,
45964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                int minor_version,
46064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                int code,
46164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                String reason_phrase) {
46264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            mStatusCode = code;
46364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
4643c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu
46564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        public void headers(Headers headers) {
46664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            mHeaders = headers;
4673c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu        }
4683c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu
46964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        public void data(byte[] data, int len) {
47064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            if (mPosterBytes == null) {
47164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                mPosterBytes = new ByteArrayOutputStream();
4723c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu            }
47364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            mPosterBytes.write(data, 0, len);
4743c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu        }
4753c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu
47664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        public void endData() {
47764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            if (mStatusCode == 200) {
47864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                if (mPosterBytes.size() > 0) {
47964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                    Bitmap poster = BitmapFactory.decodeByteArray(
48064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                            mPosterBytes.toByteArray(), 0, mPosterBytes.size());
48150c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                    mProxy.doSetPoster(poster);
48264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                }
48364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                cleanup();
48464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            } else if (mStatusCode >= 300 && mStatusCode < 400) {
48564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                // We have a redirect.
48642509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch                try {
48742509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch                    mUrl = new URL(mHeaders.getLocation());
48842509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch                } catch (MalformedURLException e) {
48942509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch                    mUrl = null;
49042509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch                }
49164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                if (mUrl != null) {
49264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                    mHandler.post(new Runnable() {
49364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                       public void run() {
49464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                           if (mRequestHandle != null) {
49542509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch                               mRequestHandle.setupRedirect(mUrl.toString(), mStatusCode,
49664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                                       new HashMap<String, String>());
49764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                           }
49864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                       }
49964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                    });
50064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                }
50164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            }
5023c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu        }
5033c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu
50464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        public void certificate(SslCertificate certificate) {
50564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            // Don't care.
5063c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu        }
5073c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu
50864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        public void error(int id, String description) {
50964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            cleanup();
51064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
51164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu
51264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        public boolean handleSslErrorRequest(SslError error) {
51364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            // Don't care. If this happens, data() will never be called so
51464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            // mPosterBytes will never be created, so no need to call cleanup.
51564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            return false;
51664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
51764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // Tears down the poster bytes stream. Called on network thread.
51864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private void cleanup() {
51964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            if (mPosterBytes != null) {
52064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                try {
52164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                    mPosterBytes.close();
52264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                } catch (IOException ignored) {
52364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                    // Ignored.
52464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                } finally {
52564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                    mPosterBytes = null;
52664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                }
5273c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu            }
52864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
52964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu
53064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // Queue management methods. Called on WebCore thread.
53164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private void retainQueue() {
53264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            if (mRequestQueue == null) {
53364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                mRequestQueue = new RequestQueue(mProxy.getContext());
5343c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu            }
53564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            mQueueRefCount++;
5363c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu        }
5373c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu
53864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private void releaseQueue() {
53964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            if (mQueueRefCount == 0) {
54064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                return;
54164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            }
54264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            if (--mQueueRefCount == 0) {
54364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                mRequestQueue.shutdown();
54464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                mRequestQueue = null;
54564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            }
5463c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu        }
5473c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu    }
5486fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu
5496fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu    /**
5506fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu     * Private constructor.
551290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu     * @param webView is the WebView that hosts the video.
552290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu     * @param nativePtr is the C++ pointer to the MediaPlayerPrivate object.
5536fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu     */
554290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    private HTML5VideoViewProxy(WebView webView, int nativePtr) {
5556fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu        // This handler is for the main (UI) thread.
5566fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu        super(Looper.getMainLooper());
5573c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu        // Save the WebView object.
5583c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu        mWebView = webView;
559661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // Pass Proxy into webview, such that every time we have a setBaseLayer
560661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // call, we tell this Proxy to call the native to update the layer tree
561661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // for the Video Layer's surface texture info
562661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        mWebView.setHTML5VideoViewProxy(this);
563290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        // Save the native ptr
564290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        mNativePointer = nativePtr;
56564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // create the message handler for this thread
56664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        createWebCoreHandler();
5676fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu    }
5686fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu
56964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    private void createWebCoreHandler() {
57064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        mWebCoreHandler = new Handler() {
57164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            @Override
57264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            public void handleMessage(Message msg) {
57364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                switch (msg.what) {
574290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                    case PREPARED: {
575290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                        Map<String, Object> map = (Map<String, Object>) msg.obj;
576290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                        Integer duration = (Integer) map.get("dur");
577290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                        Integer width = (Integer) map.get("width");
578290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                        Integer height = (Integer) map.get("height");
579290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                        nativeOnPrepared(duration.intValue(), width.intValue(),
580290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                                height.intValue(), mNativePointer);
581290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                        break;
582290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                    }
583290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                    case ENDED:
584ff19d19e016f67edf0a4e8eea374d144dc5129efBen Murdoch                        mSeekPosition = 0;
585290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                        nativeOnEnded(mNativePointer);
586290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                        break;
58743aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang                    case PAUSED:
58843aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang                        nativeOnPaused(mNativePointer);
58943aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang                        break;
59050c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                    case POSTER_FETCHED:
59150c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                        Bitmap poster = (Bitmap) msg.obj;
59250c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                        nativeOnPosterFetched(poster, mNativePointer);
59350c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                        break;
594048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu                    case TIMEUPDATE:
595048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu                        nativeOnTimeupdate(msg.arg1, mNativePointer);
596048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu                        break;
597b109c8877139077fe25fa26ea2e0961b7cbb8341Teng-Hui Zhu                    case STOPFULLSCREEN:
598b109c8877139077fe25fa26ea2e0961b7cbb8341Teng-Hui Zhu                        nativeOnStopFullscreen(mNativePointer);
599b109c8877139077fe25fa26ea2e0961b7cbb8341Teng-Hui Zhu                        break;
600e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu                    case RESTORESTATE:
601e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu                        nativeOnRestoreState(mNativePointer);
602e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu                        break;
6033c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu                }
60464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            }
60564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        };
60664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    }
60764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu
60864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    private void doSetPoster(Bitmap poster) {
60964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        if (poster == null) {
61064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            return;
6116fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu        }
61250c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu        // Save a ref to the bitmap and send it over to the WebCore thread.
61350c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu        mPoster = poster;
61450c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu        Message msg = Message.obtain(mWebCoreHandler, POSTER_FETCHED);
61550c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu        msg.obj = poster;
61650c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu        mWebCoreHandler.sendMessage(msg);
6176fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu    }
6186fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu
619048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu    private void sendTimeupdate() {
620048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu        Message msg = Message.obtain(mWebCoreHandler, TIMEUPDATE);
621048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu        msg.arg1 = VideoPlayer.getCurrentPosition();
622048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu        mWebCoreHandler.sendMessage(msg);
623048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu    }
624048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu
62564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    public Context getContext() {
62664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        return mWebView.getContext();
62764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    }
62864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu
62964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    // The public methods below are all called from WebKit only.
6306fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu    /**
6316fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu     * Play a video stream.
6326fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu     * @param url is the URL of the video stream.
6336fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu     */
634661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu    public void play(String url, int position, int videoLayerID) {
63564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        if (url == null) {
63664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            return;
63764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
638ff19d19e016f67edf0a4e8eea374d144dc5129efBen Murdoch
639ff19d19e016f67edf0a4e8eea374d144dc5129efBen Murdoch        if (position > 0) {
640ff19d19e016f67edf0a4e8eea374d144dc5129efBen Murdoch            seek(position);
641ff19d19e016f67edf0a4e8eea374d144dc5129efBen Murdoch        }
6426fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu        Message message = obtainMessage(PLAY);
643661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        message.arg1 = videoLayerID;
64464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        message.obj = url;
6456fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu        sendMessage(message);
6466fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu    }
6476fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu
64864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    /**
649290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu     * Seek into the video stream.
650290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu     * @param  time is the position in the video stream.
651290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu     */
652290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    public void seek(int time) {
653290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        Message message = obtainMessage(SEEK);
654290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        message.obj = new Integer(time);
655290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        sendMessage(message);
656290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    }
657290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu
658290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    /**
659290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu     * Pause the playback.
660290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu     */
661290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    public void pause() {
662290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        Message message = obtainMessage(PAUSE);
663290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        sendMessage(message);
664290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    }
665290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu
666290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    /**
66750c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu     * Tear down this proxy object.
66864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu     */
66950c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    public void teardown() {
67064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // This is called by the C++ MediaPlayerPrivate dtor.
67164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // Cancel any active poster download.
67264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        if (mPosterDownloader != null) {
67364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            mPosterDownloader.cancelAndReleaseQueue();
67464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
67550c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu        mNativePointer = 0;
67664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    }
67764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu
67864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    /**
67964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu     * Load the poster image.
68064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu     * @param url is the URL of the poster image.
68164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu     */
68264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    public void loadPoster(String url) {
68364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        if (url == null) {
68450c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu            Message message = obtainMessage(LOAD_DEFAULT_POSTER);
68550c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu            sendMessage(message);
68664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            return;
68764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
68864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // Cancel any active poster download.
68964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        if (mPosterDownloader != null) {
69064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            mPosterDownloader.cancelAndReleaseQueue();
69164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
69264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // Load the poster asynchronously
69364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        mPosterDownloader = new PosterDownloader(url, this);
69464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        mPosterDownloader.start();
6950a5ce01eda210f83619ada0603a80fd883512fe9Patrick Scott    }
6960a5ce01eda210f83619ada0603a80fd883512fe9Patrick Scott
69710ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu    // These three function are called from UI thread only by WebView.
698661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu    public void setBaseLayer(int layer) {
699661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        VideoPlayer.setBaseLayer(layer);
700661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu    }
701661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu
702661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu    public void pauseAndDispatch() {
703661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        VideoPlayer.pauseAndDispatch();
704661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu    }
70510ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu
70610ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu    public void enterFullScreenVideo(int layerId, String url) {
70710ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu        VideoPlayer.enterFullScreenVideo(layerId, url, this, mWebView);
70810ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu    }
70910ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu
710d7678a1684966cac10717b34b161b5241b9865c5Teng-Hui Zhu    public void exitFullScreenVideo() {
711d7678a1684966cac10717b34b161b5241b9865c5Teng-Hui Zhu        VideoPlayer.exitFullScreenVideo(this, mWebView);
712d7678a1684966cac10717b34b161b5241b9865c5Teng-Hui Zhu    }
713d7678a1684966cac10717b34b161b5241b9865c5Teng-Hui Zhu
7146fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu    /**
7153c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu     * The factory for HTML5VideoViewProxy instances.
7166fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu     * @param webViewCore is the WebViewCore that is requesting the proxy.
7176fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu     *
7183c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu     * @return a new HTML5VideoViewProxy object.
7196fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu     */
720290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    public static HTML5VideoViewProxy getInstance(WebViewCore webViewCore, int nativePtr) {
721290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        return new HTML5VideoViewProxy(webViewCore.getWebView(), nativePtr);
7226fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu    }
723290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu
7241708ad53c3669b72d20724e52301eecd35e86377Ben Murdoch    /* package */ WebView getWebView() {
7251708ad53c3669b72d20724e52301eecd35e86377Ben Murdoch        return mWebView;
7261708ad53c3669b72d20724e52301eecd35e86377Ben Murdoch    }
7271708ad53c3669b72d20724e52301eecd35e86377Ben Murdoch
728290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    private native void nativeOnPrepared(int duration, int width, int height, int nativePointer);
729290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    private native void nativeOnEnded(int nativePointer);
73043aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang    private native void nativeOnPaused(int nativePointer);
73150c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    private native void nativeOnPosterFetched(Bitmap poster, int nativePointer);
732048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu    private native void nativeOnTimeupdate(int position, int nativePointer);
733b109c8877139077fe25fa26ea2e0961b7cbb8341Teng-Hui Zhu    private native void nativeOnStopFullscreen(int nativePointer);
734e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu    private native void nativeOnRestoreState(int nativePointer);
735661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu    private native static boolean nativeSendSurfaceTexture(SurfaceTexture texture,
736661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            int baseLayer, int videoLayerId, int textureName,
737265db32f31a9db60d4a93d59befa07c825cbe4f2Teng-Hui Zhu            int playerState);
738c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu
739c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu    @Override
740c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu    public boolean onInfo(MediaPlayer mp, int what, int extra) {
741c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu        if (what == MediaPlayer.MEDIA_INFO_BUFFERING_START) {
742c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu            sendMessage(obtainMessage(BUFFERING_START, what, extra));
743c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu        } else if (what == MediaPlayer.MEDIA_INFO_BUFFERING_END) {
744c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu            sendMessage(obtainMessage(BUFFERING_END, what, extra));
745c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu        }
746c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu        return false;
747c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu    }
7486fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu}
749