HTML5VideoViewProxy.java revision c3a2858de909145a382e7932d5fb044e1388c0b3
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;
62c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu    private static final int ENTER_FULLSCREEN    = 107;
636fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu
6464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    // Message Ids to be handled on the WebCore thread
65290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    private static final int PREPARED          = 200;
66290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    private static final int ENDED             = 201;
6750c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    private static final int POSTER_FETCHED    = 202;
6843aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang    private static final int PAUSED            = 203;
69b109c8877139077fe25fa26ea2e0961b7cbb8341Teng-Hui Zhu    private static final int STOPFULLSCREEN    = 204;
70e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu    private static final int RESTORESTATE      = 205;
7164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu
72048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu    // Timer thread -> UI thread
73048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu    private static final int TIMEUPDATE = 300;
74048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu
75290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    // The C++ MediaPlayerPrivateAndroid object.
76290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    int mNativePointer;
7764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    // The handler for WebCore thread messages;
7864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    private Handler mWebCoreHandler;
793c90952036a5ff7ddb2946c643f1a0bf1c31d53aJonathan Dixon    // The WebViewClassic instance that created this view.
803c90952036a5ff7ddb2946c643f1a0bf1c31d53aJonathan Dixon    private WebViewClassic mWebView;
8164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    // The poster image to be shown when the video is not playing.
8250c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    // This ref prevents the bitmap from being GC'ed.
8350c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    private Bitmap mPoster;
8464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    // The poster downloader.
8564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    private PosterDownloader mPosterDownloader;
86290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    // The seek position.
87290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    private int mSeekPosition;
8864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    // A helper class to control the playback. This executes on the UI thread!
8964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    private static final class VideoPlayer {
9064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // The proxy that is currently playing (if any).
9164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private static HTML5VideoViewProxy mCurrentProxy;
9264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // The VideoView instance. This is a singleton for now, at least until
9364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // http://b/issue?id=1973663 is fixed.
94661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        private static HTML5VideoView mHTML5VideoView;
95048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu
96661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        private static boolean isVideoSelfEnded = false;
97661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // By using the baseLayer and the current video Layer ID, we can
98661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // identify the exact layer on the UI thread to use the SurfaceTexture.
99661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        private static int mBaseLayer = 0;
100661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu
101f4d4e9e05f7605118910739c16e493e2ab869aaeTeng-Hui Zhu        private static void setPlayerBuffering(boolean playerBuffering) {
102f4d4e9e05f7605118910739c16e493e2ab869aaeTeng-Hui Zhu            mHTML5VideoView.setPlayerBuffering(playerBuffering);
103f4d4e9e05f7605118910739c16e493e2ab869aaeTeng-Hui Zhu        }
104f4d4e9e05f7605118910739c16e493e2ab869aaeTeng-Hui Zhu
105661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // Every time webView setBaseLayer, this will be called.
106661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // When we found the Video layer, then we set the Surface Texture to it.
107661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // Otherwise, we may want to delete the Surface Texture to save memory.
108661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        public static void setBaseLayer(int layer) {
109c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu            mBaseLayer = layer;
11010ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu            // Don't do this for full screen mode.
11110ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu            if (mHTML5VideoView != null
112c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu                && !mHTML5VideoView.isFullScreenMode()) {
113661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                int currentVideoLayerId = mHTML5VideoView.getVideoLayerId();
114c2b06d5a83f8f118eaf46f093126da08a28715ebTeng-Hui Zhu                SurfaceTexture surfTexture =
115c2b06d5a83f8f118eaf46f093126da08a28715ebTeng-Hui Zhu                        HTML5VideoInline.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())
121c2b06d5a83f8f118eaf46f093126da08a28715ebTeng-Hui Zhu                        playerState = HTML5VideoView.STATE_PREPARING;
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);
12831d2aa1e17f1ee580edb762a6ef634098bba02bbAndrei Popescu                    }
12964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                }
130661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            }
131661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        }
132661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu
133661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // When a WebView is paused, we also want to pause the video in it.
134661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        public static void pauseAndDispatch() {
135661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            if (mHTML5VideoView != null) {
136661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                mHTML5VideoView.pauseAndDispatch(mCurrentProxy);
137661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            }
138661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        }
13964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu
14010ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu        public static void enterFullScreenVideo(int layerId, String url,
1413c90952036a5ff7ddb2946c643f1a0bf1c31d53aJonathan Dixon                HTML5VideoViewProxy proxy, WebViewClassic webView) {
14210ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                // Save the inline video info and inherit it in the full screen
14310ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                int savePosition = 0;
144c2b06d5a83f8f118eaf46f093126da08a28715ebTeng-Hui Zhu                boolean canSkipPrepare = false;
1456a9586bc57b162a2d68dd3e417f0fd43d8932fd0Teng-Hui Zhu                boolean forceStart = false;
14610ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                if (mHTML5VideoView != null) {
1472b64c5a6f70bfae7db95f763441b52a506d6f630Teng-Hui Zhu                    // We don't allow enter full screen mode while the previous
1482b64c5a6f70bfae7db95f763441b52a506d6f630Teng-Hui Zhu                    // full screen video hasn't finished yet.
1492b64c5a6f70bfae7db95f763441b52a506d6f630Teng-Hui Zhu                    if (!mHTML5VideoView.fullScreenExited() && mHTML5VideoView.isFullScreenMode()) {
1502b64c5a6f70bfae7db95f763441b52a506d6f630Teng-Hui Zhu                        Log.w(LOGTAG, "Try to reenter the full screen mode");
1512b64c5a6f70bfae7db95f763441b52a506d6f630Teng-Hui Zhu                        return;
1522b64c5a6f70bfae7db95f763441b52a506d6f630Teng-Hui Zhu                    }
1536a9586bc57b162a2d68dd3e417f0fd43d8932fd0Teng-Hui Zhu                    int playerState = mHTML5VideoView.getCurrentState();
15410ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                    // If we are playing the same video, then it is better to
15510ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                    // save the current position.
15610ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                    if (layerId == mHTML5VideoView.getVideoLayerId()) {
15710ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                        savePosition = mHTML5VideoView.getCurrentPosition();
158c2b06d5a83f8f118eaf46f093126da08a28715ebTeng-Hui Zhu                        canSkipPrepare = (playerState == HTML5VideoView.STATE_PREPARING
159c2b06d5a83f8f118eaf46f093126da08a28715ebTeng-Hui Zhu                                || playerState == HTML5VideoView.STATE_PREPARED
160c2b06d5a83f8f118eaf46f093126da08a28715ebTeng-Hui Zhu                                || playerState == HTML5VideoView.STATE_PLAYING)
161c2b06d5a83f8f118eaf46f093126da08a28715ebTeng-Hui Zhu                                && !mHTML5VideoView.isFullScreenMode();
162c2b06d5a83f8f118eaf46f093126da08a28715ebTeng-Hui Zhu                    }
163c2b06d5a83f8f118eaf46f093126da08a28715ebTeng-Hui Zhu                    if (!canSkipPrepare) {
164c2b06d5a83f8f118eaf46f093126da08a28715ebTeng-Hui Zhu                        mHTML5VideoView.reset();
1656a9586bc57b162a2d68dd3e417f0fd43d8932fd0Teng-Hui Zhu                    } else {
1666a9586bc57b162a2d68dd3e417f0fd43d8932fd0Teng-Hui Zhu                        forceStart = playerState == HTML5VideoView.STATE_PREPARING
1676a9586bc57b162a2d68dd3e417f0fd43d8932fd0Teng-Hui Zhu                                || playerState == HTML5VideoView.STATE_PLAYING;
16810ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                    }
16910ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                }
17010ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                mHTML5VideoView = new HTML5VideoFullScreen(proxy.getContext(),
171c2b06d5a83f8f118eaf46f093126da08a28715ebTeng-Hui Zhu                        layerId, savePosition, canSkipPrepare);
1726a9586bc57b162a2d68dd3e417f0fd43d8932fd0Teng-Hui Zhu                mHTML5VideoView.setStartWhenPrepared(forceStart);
17310ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                mCurrentProxy = proxy;
17410ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                mHTML5VideoView.setVideoURI(url, mCurrentProxy);
17510ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                mHTML5VideoView.enterFullScreenVideoState(layerId, proxy, webView);
17610ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu        }
17710ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu
178d7678a1684966cac10717b34b161b5241b9865c5Teng-Hui Zhu        public static void exitFullScreenVideo(HTML5VideoViewProxy proxy,
1793c90952036a5ff7ddb2946c643f1a0bf1c31d53aJonathan Dixon                WebViewClassic webView) {
180d7678a1684966cac10717b34b161b5241b9865c5Teng-Hui Zhu            if (!mHTML5VideoView.fullScreenExited() && mHTML5VideoView.isFullScreenMode()) {
181d7678a1684966cac10717b34b161b5241b9865c5Teng-Hui Zhu                WebChromeClient client = webView.getWebChromeClient();
182d7678a1684966cac10717b34b161b5241b9865c5Teng-Hui Zhu                if (client != null) {
183d7678a1684966cac10717b34b161b5241b9865c5Teng-Hui Zhu                    client.onHideCustomView();
184d7678a1684966cac10717b34b161b5241b9865c5Teng-Hui Zhu                }
185d7678a1684966cac10717b34b161b5241b9865c5Teng-Hui Zhu            }
186d7678a1684966cac10717b34b161b5241b9865c5Teng-Hui Zhu        }
187d7678a1684966cac10717b34b161b5241b9865c5Teng-Hui Zhu
188661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // This is on the UI thread.
189661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // When native tell Java to play, we need to check whether or not it is
190661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // still the same video by using videoLayerId and treat it differently.
191290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        public static void play(String url, int time, HTML5VideoViewProxy proxy,
192661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                WebChromeClient client, int videoLayerId) {
193661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            int currentVideoLayerId = -1;
19410ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu            boolean backFromFullScreenMode = false;
19510ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu            if (mHTML5VideoView != null) {
196661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                currentVideoLayerId = mHTML5VideoView.getVideoLayerId();
1971a88acbed9cd04d7c8ddd0c33a15926238157a07Teng-Hui Zhu                backFromFullScreenMode = mHTML5VideoView.fullScreenExited();
19896fae5e088916e1da8d4afaf40758ceec6e7187aTeng-Hui Zhu
19996fae5e088916e1da8d4afaf40758ceec6e7187aTeng-Hui Zhu                // When playing video back to back in full screen mode,
20096fae5e088916e1da8d4afaf40758ceec6e7187aTeng-Hui Zhu                // javascript will switch the src and call play.
20196fae5e088916e1da8d4afaf40758ceec6e7187aTeng-Hui Zhu                // In this case, we can just reuse the same full screen view,
20296fae5e088916e1da8d4afaf40758ceec6e7187aTeng-Hui Zhu                // and play the video after prepared.
20396fae5e088916e1da8d4afaf40758ceec6e7187aTeng-Hui Zhu                if (mHTML5VideoView.isFullScreenMode()
20496fae5e088916e1da8d4afaf40758ceec6e7187aTeng-Hui Zhu                    && !backFromFullScreenMode
20596fae5e088916e1da8d4afaf40758ceec6e7187aTeng-Hui Zhu                    && currentVideoLayerId != videoLayerId
20696fae5e088916e1da8d4afaf40758ceec6e7187aTeng-Hui Zhu                    && mCurrentProxy != proxy) {
20796fae5e088916e1da8d4afaf40758ceec6e7187aTeng-Hui Zhu                    mCurrentProxy = proxy;
20896fae5e088916e1da8d4afaf40758ceec6e7187aTeng-Hui Zhu                    mHTML5VideoView.setStartWhenPrepared(true);
20996fae5e088916e1da8d4afaf40758ceec6e7187aTeng-Hui Zhu                    mHTML5VideoView.setVideoURI(url, proxy);
21096fae5e088916e1da8d4afaf40758ceec6e7187aTeng-Hui Zhu                    mHTML5VideoView.reprepareData(proxy);
21196fae5e088916e1da8d4afaf40758ceec6e7187aTeng-Hui Zhu                    return;
21296fae5e088916e1da8d4afaf40758ceec6e7187aTeng-Hui Zhu                }
21310ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu            }
214661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu
215c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu            boolean skipPrepare = false;
216c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu            boolean createInlineView = false;
217c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu            if (backFromFullScreenMode && currentVideoLayerId == videoLayerId) {
218c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu                skipPrepare = true;
219c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu                createInlineView = true;
220c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu            } else if(backFromFullScreenMode
2213fafd39d0776a15c3613795183043a2c28277691Teng-Hui Zhu                || currentVideoLayerId != videoLayerId
222c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu                || HTML5VideoInline.surfaceTextureDeleted()) {
223661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                // Here, we handle the case when switching to a new video,
224661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                // either inside a WebView or across WebViews
225661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                // For switching videos within a WebView or across the WebView,
226661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                // we need to pause the old one and re-create a new media player
227661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                // inside the HTML5VideoView.
228661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                if (mHTML5VideoView != null) {
22922954d435d645d48885f653bd4ca6bc79e1bcd83Teng-Hui Zhu                    if (!backFromFullScreenMode) {
23022954d435d645d48885f653bd4ca6bc79e1bcd83Teng-Hui Zhu                        mHTML5VideoView.pauseAndDispatch(mCurrentProxy);
23122954d435d645d48885f653bd4ca6bc79e1bcd83Teng-Hui Zhu                    }
232c2b06d5a83f8f118eaf46f093126da08a28715ebTeng-Hui Zhu                    mHTML5VideoView.reset();
233a41f97bd77f2583e2e3698cfbba62230a8ac4789Andrei Popescu                }
234c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu                createInlineView = true;
235c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu            }
236c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu            if (createInlineView) {
237661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                mCurrentProxy = proxy;
238c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu                mHTML5VideoView = new HTML5VideoInline(videoLayerId, time, skipPrepare);
239a41f97bd77f2583e2e3698cfbba62230a8ac4789Andrei Popescu
24010ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                mHTML5VideoView.setVideoURI(url, mCurrentProxy);
24110ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                mHTML5VideoView.prepareDataAndDisplayMode(proxy);
242c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu                return;
243c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu            }
244c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu
245c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu            if (mCurrentProxy == proxy) {
246661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                // Here, we handle the case when we keep playing with one video
247661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                if (!mHTML5VideoView.isPlaying()) {
248661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                    mHTML5VideoView.seekTo(time);
249661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                    mHTML5VideoView.start();
250661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                }
251661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            } else if (mCurrentProxy != null) {
25210ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                // Some other video is already playing. Notify the caller that
25310ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                // its playback ended.
254661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                proxy.dispatchOnEnded();
255bf385d7c7b093564738f8cfd4386daf5e94b8a6dAndrei Popescu            }
25664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
257290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu
258048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu        public static boolean isPlaying(HTML5VideoViewProxy proxy) {
259661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            return (mCurrentProxy == proxy && mHTML5VideoView != null
260661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                    && mHTML5VideoView.isPlaying());
261048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu        }
262048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu
263048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu        public static int getCurrentPosition() {
264048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu            int currentPosMs = 0;
265661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            if (mHTML5VideoView != null) {
266661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                currentPosMs = mHTML5VideoView.getCurrentPosition();
267048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu            }
268048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu            return currentPosMs;
269048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu        }
270048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu
271290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        public static void seek(int time, HTML5VideoViewProxy proxy) {
272661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            if (mCurrentProxy == proxy && time >= 0 && mHTML5VideoView != null) {
273661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                mHTML5VideoView.seekTo(time);
274290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu            }
275290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        }
276290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu
277290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        public static void pause(HTML5VideoViewProxy proxy) {
278661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            if (mCurrentProxy == proxy && mHTML5VideoView != null) {
279661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                mHTML5VideoView.pause();
280290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu            }
281290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        }
282bf385d7c7b093564738f8cfd4386daf5e94b8a6dAndrei Popescu
283bf385d7c7b093564738f8cfd4386daf5e94b8a6dAndrei Popescu        public static void onPrepared() {
284e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu            if (!mHTML5VideoView.isFullScreenMode()) {
2850504967cb05f7bbd0c17962360a5d88ace8d173fTeng-Hui Zhu                mHTML5VideoView.start();
2860504967cb05f7bbd0c17962360a5d88ace8d173fTeng-Hui Zhu            }
287661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        }
288661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu
289661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        public static void end() {
2904dd9dc8204105a25e37dacbc392ea3c7212a8063Teng-Hui Zhu            mHTML5VideoView.showControllerInFullScreen();
291661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            if (mCurrentProxy != null) {
292661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                if (isVideoSelfEnded)
293661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                    mCurrentProxy.dispatchOnEnded();
294661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                else
295661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                    mCurrentProxy.dispatchOnPaused();
296661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            }
297661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            isVideoSelfEnded = false;
298bf385d7c7b093564738f8cfd4386daf5e94b8a6dAndrei Popescu        }
299290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    }
300290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu
301290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    // A bunch event listeners for our VideoView
302290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    // MediaPlayer.OnPreparedListener
303290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    public void onPrepared(MediaPlayer mp) {
304bf385d7c7b093564738f8cfd4386daf5e94b8a6dAndrei Popescu        VideoPlayer.onPrepared();
305290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        Message msg = Message.obtain(mWebCoreHandler, PREPARED);
306290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        Map<String, Object> map = new HashMap<String, Object>();
307290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        map.put("dur", new Integer(mp.getDuration()));
308290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        map.put("width", new Integer(mp.getVideoWidth()));
309290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        map.put("height", new Integer(mp.getVideoHeight()));
310290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        msg.obj = map;
311290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        mWebCoreHandler.sendMessage(msg);
312290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    }
313290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu
314290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    // MediaPlayer.OnCompletionListener;
315290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    public void onCompletion(MediaPlayer mp) {
316c4fbceb57bcfbabb6e370e2dd6448184dc116015Andrei Popescu        // The video ended by itself, so we need to
317c4fbceb57bcfbabb6e370e2dd6448184dc116015Andrei Popescu        // send a message to the UI thread to dismiss
318c4fbceb57bcfbabb6e370e2dd6448184dc116015Andrei Popescu        // the video view and to return to the WebView.
31943aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang        // arg1 == 1 means the video ends by itself.
32043aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang        sendMessage(obtainMessage(ENDED, 1, 0));
321290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    }
322290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu
32350c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    // MediaPlayer.OnErrorListener
32450c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    public boolean onError(MediaPlayer mp, int what, int extra) {
32550c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu        sendMessage(obtainMessage(ERROR));
32650c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu        return false;
32750c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    }
32850c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu
329c4fbceb57bcfbabb6e370e2dd6448184dc116015Andrei Popescu    public void dispatchOnEnded() {
330290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        Message msg = Message.obtain(mWebCoreHandler, ENDED);
331290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        mWebCoreHandler.sendMessage(msg);
33264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    }
3333c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu
33443aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang    public void dispatchOnPaused() {
335b109c8877139077fe25fa26ea2e0961b7cbb8341Teng-Hui Zhu        Message msg = Message.obtain(mWebCoreHandler, PAUSED);
336b109c8877139077fe25fa26ea2e0961b7cbb8341Teng-Hui Zhu        mWebCoreHandler.sendMessage(msg);
337b109c8877139077fe25fa26ea2e0961b7cbb8341Teng-Hui Zhu    }
338b109c8877139077fe25fa26ea2e0961b7cbb8341Teng-Hui Zhu
339c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu    public void dispatchOnStopFullScreen(boolean stillPlaying) {
340b109c8877139077fe25fa26ea2e0961b7cbb8341Teng-Hui Zhu        Message msg = Message.obtain(mWebCoreHandler, STOPFULLSCREEN);
341c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu        msg.arg1 = stillPlaying ? 1 : 0;
342b109c8877139077fe25fa26ea2e0961b7cbb8341Teng-Hui Zhu        mWebCoreHandler.sendMessage(msg);
34343aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang    }
34443aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang
345e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu    public void dispatchOnRestoreState() {
346e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu        Message msg = Message.obtain(mWebCoreHandler, RESTORESTATE);
347e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu        mWebCoreHandler.sendMessage(msg);
348e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu    }
349e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu
350048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu    public void onTimeupdate() {
351048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu        sendMessage(obtainMessage(TIMEUPDATE));
352048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu    }
353048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu
354661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu    // When there is a frame ready from surface texture, we should tell WebView
355661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu    // to refresh.
356661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu    @Override
357661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu    public void onFrameAvailable(SurfaceTexture surfaceTexture) {
358661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // TODO: This should support partial invalidation too.
359661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        mWebView.invalidate();
360661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu    }
361661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu
362048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu    // Handler for the messages from WebCore or Timer thread to the UI thread.
36364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    @Override
36464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    public void handleMessage(Message msg) {
36564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // This executes on the UI thread.
36664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        switch (msg.what) {
36764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            case PLAY: {
36864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                String url = (String) msg.obj;
36964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                WebChromeClient client = mWebView.getWebChromeClient();
370661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                int videoLayerID = msg.arg1;
37164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                if (client != null) {
372661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                    VideoPlayer.play(url, mSeekPosition, this, client, videoLayerID);
37364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                }
37464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                break;
37564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            }
376c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu            case ENTER_FULLSCREEN:{
377c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu                String url = (String) msg.obj;
378c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu                WebChromeClient client = mWebView.getWebChromeClient();
379c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu                int videoLayerID = msg.arg1;
380c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu                if (client != null) {
381c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu                    VideoPlayer.enterFullScreenVideo(videoLayerID, url, this, mWebView);
382c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu                }
383c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu                break;
384c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu            }
385290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu            case SEEK: {
386290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                Integer time = (Integer) msg.obj;
387290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                mSeekPosition = time;
388290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                VideoPlayer.seek(mSeekPosition, this);
389290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                break;
390290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu            }
391290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu            case PAUSE: {
392290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                VideoPlayer.pause(this);
393290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                break;
394290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu            }
39546a83b4ead517b9fc13b4bee4c59c3eaf4d3fdd9Andrei Popescu            case ENDED:
39643aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang                if (msg.arg1 == 1)
39743aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang                    VideoPlayer.isVideoSelfEnded = true;
398661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                VideoPlayer.end();
399661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                break;
40050c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu            case ERROR: {
40150c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                WebChromeClient client = mWebView.getWebChromeClient();
40250c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                if (client != null) {
40350c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                    client.onHideCustomView();
40450c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                }
40550c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                break;
40650c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu            }
40750c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu            case LOAD_DEFAULT_POSTER: {
40850c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                WebChromeClient client = mWebView.getWebChromeClient();
40950c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                if (client != null) {
41050c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                    doSetPoster(client.getDefaultVideoPoster());
41150c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                }
41250c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                break;
41350c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu            }
414048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu            case TIMEUPDATE: {
415048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu                if (VideoPlayer.isPlaying(this)) {
416048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu                    sendTimeupdate();
417048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu                }
418048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu                break;
419048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu            }
420c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu            case BUFFERING_START: {
421f4d4e9e05f7605118910739c16e493e2ab869aaeTeng-Hui Zhu                VideoPlayer.setPlayerBuffering(true);
422c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu                break;
423c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu            }
424c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu            case BUFFERING_END: {
425f4d4e9e05f7605118910739c16e493e2ab869aaeTeng-Hui Zhu                VideoPlayer.setPlayerBuffering(false);
426c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu                break;
427c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu            }
42864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
42964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    }
43064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu
43164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    // Everything below this comment executes on the WebCore thread, except for
43264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    // the EventHandler methods, which are called on the network thread.
43364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu
43464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    // A helper class that knows how to download posters
43564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    private static final class PosterDownloader implements EventHandler {
43664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // The request queue. This is static as we have one queue for all posters.
43764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private static RequestQueue mRequestQueue;
43864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private static int mQueueRefCount = 0;
43964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // The poster URL
44042509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch        private URL mUrl;
44164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // The proxy we're doing this for.
44264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private final HTML5VideoViewProxy mProxy;
44364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // The poster bytes. We only touch this on the network thread.
44464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private ByteArrayOutputStream mPosterBytes;
44564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // The request handle. We only touch this on the WebCore thread.
44664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private RequestHandle mRequestHandle;
44764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // The response status code.
44864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private int mStatusCode;
44964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // The response headers.
45064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private Headers mHeaders;
45164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // The handler to handle messages on the WebCore thread.
45264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private Handler mHandler;
45364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu
45464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        public PosterDownloader(String url, HTML5VideoViewProxy proxy) {
45542509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch            try {
45642509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch                mUrl = new URL(url);
45742509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch            } catch (MalformedURLException e) {
45842509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch                mUrl = null;
45942509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch            }
46064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            mProxy = proxy;
46164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            mHandler = new Handler();
46264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
46364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // Start the download. Called on WebCore thread.
46464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        public void start() {
46564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            retainQueue();
46642509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch
46742509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch            if (mUrl == null) {
46842509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch                return;
46942509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch            }
47042509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch
47142509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch            // Only support downloading posters over http/https.
47242509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch            // FIXME: Add support for other schemes. WebKit seems able to load
47342509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch            // posters over other schemes e.g. file://, but gets the dimensions wrong.
47442509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch            String protocol = mUrl.getProtocol();
47542509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch            if ("http".equals(protocol) || "https".equals(protocol)) {
47642509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch                mRequestHandle = mRequestQueue.queueRequest(mUrl.toString(), "GET", null,
47742509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch                        this, null, 0);
47842509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch            }
47964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
48064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // Cancel the download if active and release the queue. Called on WebCore thread.
48164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        public void cancelAndReleaseQueue() {
48264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            if (mRequestHandle != null) {
48364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                mRequestHandle.cancel();
48464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                mRequestHandle = null;
48564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            }
48664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            releaseQueue();
48764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
48864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // EventHandler methods. Executed on the network thread.
48964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        public void status(int major_version,
49064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                int minor_version,
49164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                int code,
49264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                String reason_phrase) {
49364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            mStatusCode = code;
49464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
4953c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu
49664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        public void headers(Headers headers) {
49764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            mHeaders = headers;
4983c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu        }
4993c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu
50064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        public void data(byte[] data, int len) {
50164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            if (mPosterBytes == null) {
50264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                mPosterBytes = new ByteArrayOutputStream();
5033c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu            }
50464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            mPosterBytes.write(data, 0, len);
5053c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu        }
5063c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu
50764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        public void endData() {
50864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            if (mStatusCode == 200) {
50964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                if (mPosterBytes.size() > 0) {
51064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                    Bitmap poster = BitmapFactory.decodeByteArray(
51164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                            mPosterBytes.toByteArray(), 0, mPosterBytes.size());
51250c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                    mProxy.doSetPoster(poster);
51364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                }
51464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                cleanup();
51564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            } else if (mStatusCode >= 300 && mStatusCode < 400) {
51664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                // We have a redirect.
51742509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch                try {
51842509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch                    mUrl = new URL(mHeaders.getLocation());
51942509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch                } catch (MalformedURLException e) {
52042509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch                    mUrl = null;
52142509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch                }
52264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                if (mUrl != null) {
52364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                    mHandler.post(new Runnable() {
52464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                       public void run() {
52564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                           if (mRequestHandle != null) {
52642509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch                               mRequestHandle.setupRedirect(mUrl.toString(), mStatusCode,
52764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                                       new HashMap<String, String>());
52864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                           }
52964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                       }
53064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                    });
53164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                }
53264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            }
5333c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu        }
5343c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu
53564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        public void certificate(SslCertificate certificate) {
53664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            // Don't care.
5373c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu        }
5383c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu
53964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        public void error(int id, String description) {
54064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            cleanup();
54164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
54264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu
54364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        public boolean handleSslErrorRequest(SslError error) {
54464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            // Don't care. If this happens, data() will never be called so
54564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            // mPosterBytes will never be created, so no need to call cleanup.
54664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            return false;
54764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
54864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // Tears down the poster bytes stream. Called on network thread.
54964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private void cleanup() {
55064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            if (mPosterBytes != null) {
55164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                try {
55264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                    mPosterBytes.close();
55364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                } catch (IOException ignored) {
55464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                    // Ignored.
55564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                } finally {
55664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                    mPosterBytes = null;
55764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                }
5583c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu            }
55964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
56064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu
56164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // Queue management methods. Called on WebCore thread.
56264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private void retainQueue() {
56364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            if (mRequestQueue == null) {
56464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                mRequestQueue = new RequestQueue(mProxy.getContext());
5653c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu            }
56664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            mQueueRefCount++;
5673c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu        }
5683c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu
56964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private void releaseQueue() {
57064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            if (mQueueRefCount == 0) {
57164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                return;
57264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            }
57364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            if (--mQueueRefCount == 0) {
57464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                mRequestQueue.shutdown();
57564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                mRequestQueue = null;
57664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            }
5773c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu        }
5783c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu    }
5796fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu
5806fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu    /**
5816fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu     * Private constructor.
582290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu     * @param webView is the WebView that hosts the video.
583290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu     * @param nativePtr is the C++ pointer to the MediaPlayerPrivate object.
5846fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu     */
5853c90952036a5ff7ddb2946c643f1a0bf1c31d53aJonathan Dixon    private HTML5VideoViewProxy(WebViewClassic webView, int nativePtr) {
5866fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu        // This handler is for the main (UI) thread.
5876fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu        super(Looper.getMainLooper());
5883c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu        // Save the WebView object.
5893c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu        mWebView = webView;
590661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // Pass Proxy into webview, such that every time we have a setBaseLayer
591661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // call, we tell this Proxy to call the native to update the layer tree
592661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // for the Video Layer's surface texture info
593661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        mWebView.setHTML5VideoViewProxy(this);
594290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        // Save the native ptr
595290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        mNativePointer = nativePtr;
59664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // create the message handler for this thread
59764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        createWebCoreHandler();
5986fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu    }
5996fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu
60064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    private void createWebCoreHandler() {
60164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        mWebCoreHandler = new Handler() {
60264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            @Override
60364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            public void handleMessage(Message msg) {
60464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                switch (msg.what) {
605290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                    case PREPARED: {
606290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                        Map<String, Object> map = (Map<String, Object>) msg.obj;
607290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                        Integer duration = (Integer) map.get("dur");
608290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                        Integer width = (Integer) map.get("width");
609290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                        Integer height = (Integer) map.get("height");
610290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                        nativeOnPrepared(duration.intValue(), width.intValue(),
611290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                                height.intValue(), mNativePointer);
612290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                        break;
613290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                    }
614290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                    case ENDED:
615ff19d19e016f67edf0a4e8eea374d144dc5129efBen Murdoch                        mSeekPosition = 0;
616290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                        nativeOnEnded(mNativePointer);
617290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                        break;
61843aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang                    case PAUSED:
61943aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang                        nativeOnPaused(mNativePointer);
62043aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang                        break;
62150c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                    case POSTER_FETCHED:
62250c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                        Bitmap poster = (Bitmap) msg.obj;
62350c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                        nativeOnPosterFetched(poster, mNativePointer);
62450c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                        break;
625048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu                    case TIMEUPDATE:
626048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu                        nativeOnTimeupdate(msg.arg1, mNativePointer);
627048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu                        break;
628b109c8877139077fe25fa26ea2e0961b7cbb8341Teng-Hui Zhu                    case STOPFULLSCREEN:
629c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu                        nativeOnStopFullscreen(msg.arg1, mNativePointer);
630b109c8877139077fe25fa26ea2e0961b7cbb8341Teng-Hui Zhu                        break;
631e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu                    case RESTORESTATE:
632e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu                        nativeOnRestoreState(mNativePointer);
633e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu                        break;
6343c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu                }
63564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            }
63664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        };
63764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    }
63864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu
63964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    private void doSetPoster(Bitmap poster) {
64064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        if (poster == null) {
64164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            return;
6426fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu        }
64350c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu        // Save a ref to the bitmap and send it over to the WebCore thread.
64450c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu        mPoster = poster;
64550c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu        Message msg = Message.obtain(mWebCoreHandler, POSTER_FETCHED);
64650c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu        msg.obj = poster;
64750c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu        mWebCoreHandler.sendMessage(msg);
6486fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu    }
6496fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu
650048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu    private void sendTimeupdate() {
651048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu        Message msg = Message.obtain(mWebCoreHandler, TIMEUPDATE);
652048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu        msg.arg1 = VideoPlayer.getCurrentPosition();
653048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu        mWebCoreHandler.sendMessage(msg);
654048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu    }
655048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu
65664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    public Context getContext() {
65764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        return mWebView.getContext();
65864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    }
65964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu
66064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    // The public methods below are all called from WebKit only.
6616fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu    /**
6626fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu     * Play a video stream.
6636fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu     * @param url is the URL of the video stream.
6646fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu     */
665661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu    public void play(String url, int position, int videoLayerID) {
66664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        if (url == null) {
66764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            return;
66864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
669ff19d19e016f67edf0a4e8eea374d144dc5129efBen Murdoch
670ff19d19e016f67edf0a4e8eea374d144dc5129efBen Murdoch        if (position > 0) {
671ff19d19e016f67edf0a4e8eea374d144dc5129efBen Murdoch            seek(position);
672ff19d19e016f67edf0a4e8eea374d144dc5129efBen Murdoch        }
6736fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu        Message message = obtainMessage(PLAY);
674661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        message.arg1 = videoLayerID;
67564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        message.obj = url;
6766fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu        sendMessage(message);
6776fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu    }
6786fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu
67964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    /**
680c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu     * Play a video stream in full screen mode.
681c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu     * @param url is the URL of the video stream.
682c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu     */
683c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu    public void enterFullscreenForVideoLayer(String url, int videoLayerID) {
684c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu        if (url == null) {
685c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu            return;
686c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu        }
687c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu
688c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu        Message message = obtainMessage(ENTER_FULLSCREEN);
689c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu        message.arg1 = videoLayerID;
690c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu        message.obj = url;
691c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu        sendMessage(message);
692c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu    }
693c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu
694c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu    /**
695290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu     * Seek into the video stream.
696290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu     * @param  time is the position in the video stream.
697290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu     */
698290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    public void seek(int time) {
699290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        Message message = obtainMessage(SEEK);
700290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        message.obj = new Integer(time);
701290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        sendMessage(message);
702290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    }
703290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu
704290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    /**
705290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu     * Pause the playback.
706290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu     */
707290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    public void pause() {
708290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        Message message = obtainMessage(PAUSE);
709290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        sendMessage(message);
710290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    }
711290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu
712290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    /**
71350c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu     * Tear down this proxy object.
71464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu     */
71550c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    public void teardown() {
71664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // This is called by the C++ MediaPlayerPrivate dtor.
71764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // Cancel any active poster download.
71864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        if (mPosterDownloader != null) {
71964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            mPosterDownloader.cancelAndReleaseQueue();
72064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
72150c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu        mNativePointer = 0;
72264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    }
72364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu
72464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    /**
72564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu     * Load the poster image.
72664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu     * @param url is the URL of the poster image.
72764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu     */
72864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    public void loadPoster(String url) {
72964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        if (url == null) {
73050c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu            Message message = obtainMessage(LOAD_DEFAULT_POSTER);
73150c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu            sendMessage(message);
73264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            return;
73364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
73464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // Cancel any active poster download.
73564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        if (mPosterDownloader != null) {
73664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            mPosterDownloader.cancelAndReleaseQueue();
73764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
73864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // Load the poster asynchronously
73964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        mPosterDownloader = new PosterDownloader(url, this);
74064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        mPosterDownloader.start();
7410a5ce01eda210f83619ada0603a80fd883512fe9Patrick Scott    }
7420a5ce01eda210f83619ada0603a80fd883512fe9Patrick Scott
74310ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu    // These three function are called from UI thread only by WebView.
744661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu    public void setBaseLayer(int layer) {
745661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        VideoPlayer.setBaseLayer(layer);
746661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu    }
747661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu
748661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu    public void pauseAndDispatch() {
749661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        VideoPlayer.pauseAndDispatch();
750661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu    }
75110ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu
75210ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu    public void enterFullScreenVideo(int layerId, String url) {
75310ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu        VideoPlayer.enterFullScreenVideo(layerId, url, this, mWebView);
75410ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu    }
75510ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu
756d7678a1684966cac10717b34b161b5241b9865c5Teng-Hui Zhu    public void exitFullScreenVideo() {
757d7678a1684966cac10717b34b161b5241b9865c5Teng-Hui Zhu        VideoPlayer.exitFullScreenVideo(this, mWebView);
758d7678a1684966cac10717b34b161b5241b9865c5Teng-Hui Zhu    }
759d7678a1684966cac10717b34b161b5241b9865c5Teng-Hui Zhu
7606fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu    /**
7613c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu     * The factory for HTML5VideoViewProxy instances.
7626fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu     * @param webViewCore is the WebViewCore that is requesting the proxy.
7636fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu     *
7643c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu     * @return a new HTML5VideoViewProxy object.
7656fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu     */
766290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    public static HTML5VideoViewProxy getInstance(WebViewCore webViewCore, int nativePtr) {
767a6c4d8e018e39ff94263ce8f2a31b768104d1bb6Jonathan Dixon        return new HTML5VideoViewProxy(webViewCore.getWebViewClassic(), nativePtr);
7686fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu    }
769290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu
7703c90952036a5ff7ddb2946c643f1a0bf1c31d53aJonathan Dixon    /* package */ WebViewClassic getWebView() {
7711708ad53c3669b72d20724e52301eecd35e86377Ben Murdoch        return mWebView;
7721708ad53c3669b72d20724e52301eecd35e86377Ben Murdoch    }
7731708ad53c3669b72d20724e52301eecd35e86377Ben Murdoch
774290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    private native void nativeOnPrepared(int duration, int width, int height, int nativePointer);
775290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    private native void nativeOnEnded(int nativePointer);
77643aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang    private native void nativeOnPaused(int nativePointer);
77750c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    private native void nativeOnPosterFetched(Bitmap poster, int nativePointer);
778048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu    private native void nativeOnTimeupdate(int position, int nativePointer);
779c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu    private native void nativeOnStopFullscreen(int stillPlaying, int nativePointer);
780e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu    private native void nativeOnRestoreState(int nativePointer);
781661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu    private native static boolean nativeSendSurfaceTexture(SurfaceTexture texture,
782661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            int baseLayer, int videoLayerId, int textureName,
783265db32f31a9db60d4a93d59befa07c825cbe4f2Teng-Hui Zhu            int playerState);
784c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu
785c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu    @Override
786c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu    public boolean onInfo(MediaPlayer mp, int what, int extra) {
787c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu        if (what == MediaPlayer.MEDIA_INFO_BUFFERING_START) {
788c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu            sendMessage(obtainMessage(BUFFERING_START, what, extra));
789c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu        } else if (what == MediaPlayer.MEDIA_INFO_BUFFERING_END) {
790c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu            sendMessage(obtainMessage(BUFFERING_END, what, extra));
791c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu        }
792c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu        return false;
793c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu    }
7946fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu}
795