HTML5VideoViewProxy.java revision 158fbdb29b8fdda57f942ec2056d908714c326be
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,
49661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                          SurfaceTexture.OnFrameAvailableListener {
506fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu    // Logging tag.
516fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu    private static final String LOGTAG = "HTML5VideoViewProxy";
526fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu
533c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu    // Message Ids for WebCore thread -> UI thread communication.
5450c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    private static final int PLAY                = 100;
5550c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    private static final int SEEK                = 101;
5650c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    private static final int PAUSE               = 102;
5750c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    private static final int ERROR               = 103;
5850c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    private static final int LOAD_DEFAULT_POSTER = 104;
596fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu
6064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    // Message Ids to be handled on the WebCore thread
61290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    private static final int PREPARED          = 200;
62290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    private static final int ENDED             = 201;
6350c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    private static final int POSTER_FETCHED    = 202;
6443aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang    private static final int PAUSED            = 203;
6564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu
66048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu    // Timer thread -> UI thread
67048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu    private static final int TIMEUPDATE = 300;
68048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu
69290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    // The C++ MediaPlayerPrivateAndroid object.
70290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    int mNativePointer;
7164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    // The handler for WebCore thread messages;
7264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    private Handler mWebCoreHandler;
733c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu    // The WebView instance that created this view.
743c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu    private WebView mWebView;
7564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    // The poster image to be shown when the video is not playing.
7650c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    // This ref prevents the bitmap from being GC'ed.
7750c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    private Bitmap mPoster;
7864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    // The poster downloader.
7964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    private PosterDownloader mPosterDownloader;
80290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    // The seek position.
81290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    private int mSeekPosition;
8264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    // A helper class to control the playback. This executes on the UI thread!
8364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    private static final class VideoPlayer {
8464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // The proxy that is currently playing (if any).
8564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private static HTML5VideoViewProxy mCurrentProxy;
8664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // The VideoView instance. This is a singleton for now, at least until
8764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // http://b/issue?id=1973663 is fixed.
88661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        private static HTML5VideoView mHTML5VideoView;
89048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu
90661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        private static boolean isVideoSelfEnded = false;
91661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // By using the baseLayer and the current video Layer ID, we can
92661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // identify the exact layer on the UI thread to use the SurfaceTexture.
93661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        private static int mBaseLayer = 0;
94661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu
95661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // Every time webView setBaseLayer, this will be called.
96661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // When we found the Video layer, then we set the Surface Texture to it.
97661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // Otherwise, we may want to delete the Surface Texture to save memory.
98661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        public static void setBaseLayer(int layer) {
9910ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu            // Don't do this for full screen mode.
10010ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu            if (mHTML5VideoView != null
10110ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                    && !mHTML5VideoView.isFullScreenMode()) {
102661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                mBaseLayer = layer;
103661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                SurfaceTexture surfTexture = mHTML5VideoView.getSurfaceTexture();
104661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                int textureName = mHTML5VideoView.getTextureName();
105661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu
106661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                int currentVideoLayerId = mHTML5VideoView.getVideoLayerId();
107661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                if (layer != 0 && surfTexture != null && currentVideoLayerId != -1) {
108265db32f31a9db60d4a93d59befa07c825cbe4f2Teng-Hui Zhu                    int playerState = mHTML5VideoView.getCurrentState();
109661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                    boolean foundInTree = nativeSendSurfaceTexture(surfTexture,
110661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                            layer, currentVideoLayerId, textureName,
111265db32f31a9db60d4a93d59befa07c825cbe4f2Teng-Hui Zhu                            playerState);
112265db32f31a9db60d4a93d59befa07c825cbe4f2Teng-Hui Zhu                    if (playerState == HTML5VideoView.STATE_PREPARED
113265db32f31a9db60d4a93d59befa07c825cbe4f2Teng-Hui Zhu                            && !foundInTree) {
114661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                        mHTML5VideoView.pauseAndDispatch(mCurrentProxy);
115661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                        mHTML5VideoView.deleteSurfaceTexture();
11631d2aa1e17f1ee580edb762a6ef634098bba02bbAndrei Popescu                    }
11764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                }
118661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            }
119661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        }
120661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu
121661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // When a WebView is paused, we also want to pause the video in it.
122661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        public static void pauseAndDispatch() {
123661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            if (mHTML5VideoView != null) {
124661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                mHTML5VideoView.pauseAndDispatch(mCurrentProxy);
125661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                // When switching out, clean the video content on the old page
126661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                // by telling the layer not readyToUseSurfTex.
127661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                setBaseLayer(mBaseLayer);
128661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            }
129661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        }
13064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu
13110ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu        public static void enterFullScreenVideo(int layerId, String url,
13210ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                HTML5VideoViewProxy proxy, WebView webView) {
13310ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                // Save the inline video info and inherit it in the full screen
13410ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                int savePosition = 0;
13510ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                boolean savedIsPlaying = false;
13610ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                if (mHTML5VideoView != null) {
13710ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                    // If we are playing the same video, then it is better to
13810ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                    // save the current position.
13910ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                    if (layerId == mHTML5VideoView.getVideoLayerId()) {
14010ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                        savePosition = mHTML5VideoView.getCurrentPosition();
14110ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                        savedIsPlaying = mHTML5VideoView.isPlaying();
14210ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                    }
14310ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                    mHTML5VideoView.pauseAndDispatch(mCurrentProxy);
14410ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                    mHTML5VideoView.release();
14510ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                }
14610ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                mHTML5VideoView = new HTML5VideoFullScreen(proxy.getContext(),
14710ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                        layerId, savePosition, savedIsPlaying);
14810ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                mCurrentProxy = proxy;
14910ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu
15010ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                mHTML5VideoView.setVideoURI(url, mCurrentProxy);
15110ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu
15210ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                mHTML5VideoView.enterFullScreenVideoState(layerId, proxy, webView);
15310ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu        }
15410ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu
155661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // This is on the UI thread.
156661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // When native tell Java to play, we need to check whether or not it is
157661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // still the same video by using videoLayerId and treat it differently.
158290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        public static void play(String url, int time, HTML5VideoViewProxy proxy,
159661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                WebChromeClient client, int videoLayerId) {
160661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            int currentVideoLayerId = -1;
16110ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu            boolean backFromFullScreenMode = false;
16210ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu
16310ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu            if (mHTML5VideoView != null) {
164661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                currentVideoLayerId = mHTML5VideoView.getVideoLayerId();
16510ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                if (mHTML5VideoView instanceof HTML5VideoFullScreen) {
16610ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                    backFromFullScreenMode = true;
16710ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                }
16810ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu            }
169661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu
17010ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu            if (backFromFullScreenMode
17110ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                ||  currentVideoLayerId != videoLayerId
172661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                || mHTML5VideoView.getSurfaceTexture() == null) {
173661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                // Here, we handle the case when switching to a new video,
174661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                // either inside a WebView or across WebViews
175661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                // For switching videos within a WebView or across the WebView,
176661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                // we need to pause the old one and re-create a new media player
177661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                // inside the HTML5VideoView.
178661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                if (mHTML5VideoView != null) {
179661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                    mHTML5VideoView.pauseAndDispatch(mCurrentProxy);
180661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                    // release the media player to avoid finalize error
181661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                    mHTML5VideoView.release();
182a41f97bd77f2583e2e3698cfbba62230a8ac4789Andrei Popescu                }
183661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                mCurrentProxy = proxy;
18410ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                mHTML5VideoView = new HTML5VideoInline(videoLayerId, time, false);
185a41f97bd77f2583e2e3698cfbba62230a8ac4789Andrei Popescu
18610ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                mHTML5VideoView.setVideoURI(url, mCurrentProxy);
18710ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                mHTML5VideoView.prepareDataAndDisplayMode(proxy);
188661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            } else if (mCurrentProxy == proxy) {
189661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                // Here, we handle the case when we keep playing with one video
190661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                if (!mHTML5VideoView.isPlaying()) {
191661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                    mHTML5VideoView.seekTo(time);
192661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                    mHTML5VideoView.start();
193661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                }
194661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            } else if (mCurrentProxy != null) {
19510ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                // Some other video is already playing. Notify the caller that
19610ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu                // its playback ended.
197661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                proxy.dispatchOnEnded();
198bf385d7c7b093564738f8cfd4386daf5e94b8a6dAndrei Popescu            }
19964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
200290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu
201048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu        public static boolean isPlaying(HTML5VideoViewProxy proxy) {
202661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            return (mCurrentProxy == proxy && mHTML5VideoView != null
203661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                    && mHTML5VideoView.isPlaying());
204048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu        }
205048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu
206048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu        public static int getCurrentPosition() {
207048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu            int currentPosMs = 0;
208661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            if (mHTML5VideoView != null) {
209661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                currentPosMs = mHTML5VideoView.getCurrentPosition();
210048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu            }
211048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu            return currentPosMs;
212048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu        }
213048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu
214290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        public static void seek(int time, HTML5VideoViewProxy proxy) {
215661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            if (mCurrentProxy == proxy && time >= 0 && mHTML5VideoView != null) {
216661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                mHTML5VideoView.seekTo(time);
217290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu            }
218290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        }
219290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu
220290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        public static void pause(HTML5VideoViewProxy proxy) {
221661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            if (mCurrentProxy == proxy && mHTML5VideoView != null) {
222661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                mHTML5VideoView.pause();
223290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu            }
224290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        }
225bf385d7c7b093564738f8cfd4386daf5e94b8a6dAndrei Popescu
226bf385d7c7b093564738f8cfd4386daf5e94b8a6dAndrei Popescu        public static void onPrepared() {
227158fbdb29b8fdda57f942ec2056d908714c326beTeng-Hui Zhu            // The VideoView will decide whether to really kick off to play.
228158fbdb29b8fdda57f942ec2056d908714c326beTeng-Hui Zhu            mHTML5VideoView.start();
229265db32f31a9db60d4a93d59befa07c825cbe4f2Teng-Hui Zhu            if (mBaseLayer != 0) {
230265db32f31a9db60d4a93d59befa07c825cbe4f2Teng-Hui Zhu                setBaseLayer(mBaseLayer);
231265db32f31a9db60d4a93d59befa07c825cbe4f2Teng-Hui Zhu            }
232661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        }
233661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu
234661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        public static void end() {
235661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            if (mCurrentProxy != null) {
236661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                if (isVideoSelfEnded)
237661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                    mCurrentProxy.dispatchOnEnded();
238661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                else
239661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                    mCurrentProxy.dispatchOnPaused();
240661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            }
241661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            isVideoSelfEnded = false;
242bf385d7c7b093564738f8cfd4386daf5e94b8a6dAndrei Popescu        }
243290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    }
244290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu
245290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    // A bunch event listeners for our VideoView
246290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    // MediaPlayer.OnPreparedListener
247290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    public void onPrepared(MediaPlayer mp) {
248bf385d7c7b093564738f8cfd4386daf5e94b8a6dAndrei Popescu        VideoPlayer.onPrepared();
249290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        Message msg = Message.obtain(mWebCoreHandler, PREPARED);
250290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        Map<String, Object> map = new HashMap<String, Object>();
251290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        map.put("dur", new Integer(mp.getDuration()));
252290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        map.put("width", new Integer(mp.getVideoWidth()));
253290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        map.put("height", new Integer(mp.getVideoHeight()));
254290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        msg.obj = map;
255290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        mWebCoreHandler.sendMessage(msg);
256290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    }
257290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu
258290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    // MediaPlayer.OnCompletionListener;
259290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    public void onCompletion(MediaPlayer mp) {
260c4fbceb57bcfbabb6e370e2dd6448184dc116015Andrei Popescu        // The video ended by itself, so we need to
261c4fbceb57bcfbabb6e370e2dd6448184dc116015Andrei Popescu        // send a message to the UI thread to dismiss
262c4fbceb57bcfbabb6e370e2dd6448184dc116015Andrei Popescu        // the video view and to return to the WebView.
26343aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang        // arg1 == 1 means the video ends by itself.
26443aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang        sendMessage(obtainMessage(ENDED, 1, 0));
265290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    }
266290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu
26750c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    // MediaPlayer.OnErrorListener
26850c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    public boolean onError(MediaPlayer mp, int what, int extra) {
26950c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu        sendMessage(obtainMessage(ERROR));
27050c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu        return false;
27150c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    }
27250c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu
273c4fbceb57bcfbabb6e370e2dd6448184dc116015Andrei Popescu    public void dispatchOnEnded() {
274290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        Message msg = Message.obtain(mWebCoreHandler, ENDED);
275290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        mWebCoreHandler.sendMessage(msg);
27664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    }
2773c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu
27843aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang    public void dispatchOnPaused() {
27943aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang      Message msg = Message.obtain(mWebCoreHandler, PAUSED);
28043aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang      mWebCoreHandler.sendMessage(msg);
28143aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang    }
28243aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang
283048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu    public void onTimeupdate() {
284048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu        sendMessage(obtainMessage(TIMEUPDATE));
285048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu    }
286048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu
287661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu    // When there is a frame ready from surface texture, we should tell WebView
288661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu    // to refresh.
289661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu    @Override
290661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu    public void onFrameAvailable(SurfaceTexture surfaceTexture) {
291661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // TODO: This should support partial invalidation too.
292661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        mWebView.invalidate();
293661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu    }
294661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu
295048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu    // Handler for the messages from WebCore or Timer thread to the UI thread.
29664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    @Override
29764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    public void handleMessage(Message msg) {
29864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // This executes on the UI thread.
29964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        switch (msg.what) {
30064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            case PLAY: {
30164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                String url = (String) msg.obj;
30264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                WebChromeClient client = mWebView.getWebChromeClient();
303661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                int videoLayerID = msg.arg1;
30464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                if (client != null) {
305661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                    VideoPlayer.play(url, mSeekPosition, this, client, videoLayerID);
30664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                }
30764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                break;
30864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            }
309290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu            case SEEK: {
310290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                Integer time = (Integer) msg.obj;
311290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                mSeekPosition = time;
312290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                VideoPlayer.seek(mSeekPosition, this);
313290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                break;
314290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu            }
315290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu            case PAUSE: {
316290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                VideoPlayer.pause(this);
317290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                break;
318290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu            }
31946a83b4ead517b9fc13b4bee4c59c3eaf4d3fdd9Andrei Popescu            case ENDED:
32043aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang                if (msg.arg1 == 1)
32143aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang                    VideoPlayer.isVideoSelfEnded = true;
322661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                VideoPlayer.end();
323661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu                break;
32450c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu            case ERROR: {
32550c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                WebChromeClient client = mWebView.getWebChromeClient();
32650c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                if (client != null) {
32750c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                    client.onHideCustomView();
32850c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                }
32950c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                break;
33050c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu            }
33150c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu            case LOAD_DEFAULT_POSTER: {
33250c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                WebChromeClient client = mWebView.getWebChromeClient();
33350c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                if (client != null) {
33450c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                    doSetPoster(client.getDefaultVideoPoster());
33550c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                }
33650c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                break;
33750c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu            }
338048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu            case TIMEUPDATE: {
339048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu                if (VideoPlayer.isPlaying(this)) {
340048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu                    sendTimeupdate();
341048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu                }
342048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu                break;
343048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu            }
34464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
34564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    }
34664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu
34764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    // Everything below this comment executes on the WebCore thread, except for
34864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    // the EventHandler methods, which are called on the network thread.
34964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu
35064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    // A helper class that knows how to download posters
35164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    private static final class PosterDownloader implements EventHandler {
35264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // The request queue. This is static as we have one queue for all posters.
35364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private static RequestQueue mRequestQueue;
35464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private static int mQueueRefCount = 0;
35564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // The poster URL
35642509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch        private URL mUrl;
35764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // The proxy we're doing this for.
35864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private final HTML5VideoViewProxy mProxy;
35964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // The poster bytes. We only touch this on the network thread.
36064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private ByteArrayOutputStream mPosterBytes;
36164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // The request handle. We only touch this on the WebCore thread.
36264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private RequestHandle mRequestHandle;
36364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // The response status code.
36464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private int mStatusCode;
36564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // The response headers.
36664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private Headers mHeaders;
36764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // The handler to handle messages on the WebCore thread.
36864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private Handler mHandler;
36964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu
37064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        public PosterDownloader(String url, HTML5VideoViewProxy proxy) {
37142509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch            try {
37242509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch                mUrl = new URL(url);
37342509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch            } catch (MalformedURLException e) {
37442509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch                mUrl = null;
37542509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch            }
37664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            mProxy = proxy;
37764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            mHandler = new Handler();
37864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
37964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // Start the download. Called on WebCore thread.
38064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        public void start() {
38164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            retainQueue();
38242509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch
38342509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch            if (mUrl == null) {
38442509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch                return;
38542509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch            }
38642509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch
38742509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch            // Only support downloading posters over http/https.
38842509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch            // FIXME: Add support for other schemes. WebKit seems able to load
38942509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch            // posters over other schemes e.g. file://, but gets the dimensions wrong.
39042509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch            String protocol = mUrl.getProtocol();
39142509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch            if ("http".equals(protocol) || "https".equals(protocol)) {
39242509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch                mRequestHandle = mRequestQueue.queueRequest(mUrl.toString(), "GET", null,
39342509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch                        this, null, 0);
39442509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch            }
39564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
39664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // Cancel the download if active and release the queue. Called on WebCore thread.
39764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        public void cancelAndReleaseQueue() {
39864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            if (mRequestHandle != null) {
39964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                mRequestHandle.cancel();
40064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                mRequestHandle = null;
40164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            }
40264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            releaseQueue();
40364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
40464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // EventHandler methods. Executed on the network thread.
40564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        public void status(int major_version,
40664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                int minor_version,
40764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                int code,
40864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                String reason_phrase) {
40964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            mStatusCode = code;
41064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
4113c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu
41264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        public void headers(Headers headers) {
41364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            mHeaders = headers;
4143c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu        }
4153c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu
41664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        public void data(byte[] data, int len) {
41764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            if (mPosterBytes == null) {
41864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                mPosterBytes = new ByteArrayOutputStream();
4193c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu            }
42064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            mPosterBytes.write(data, 0, len);
4213c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu        }
4223c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu
42364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        public void endData() {
42464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            if (mStatusCode == 200) {
42564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                if (mPosterBytes.size() > 0) {
42664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                    Bitmap poster = BitmapFactory.decodeByteArray(
42764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                            mPosterBytes.toByteArray(), 0, mPosterBytes.size());
42850c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                    mProxy.doSetPoster(poster);
42964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                }
43064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                cleanup();
43164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            } else if (mStatusCode >= 300 && mStatusCode < 400) {
43264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                // We have a redirect.
43342509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch                try {
43442509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch                    mUrl = new URL(mHeaders.getLocation());
43542509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch                } catch (MalformedURLException e) {
43642509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch                    mUrl = null;
43742509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch                }
43864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                if (mUrl != null) {
43964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                    mHandler.post(new Runnable() {
44064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                       public void run() {
44164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                           if (mRequestHandle != null) {
44242509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch                               mRequestHandle.setupRedirect(mUrl.toString(), mStatusCode,
44364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                                       new HashMap<String, String>());
44464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                           }
44564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                       }
44664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                    });
44764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                }
44864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            }
4493c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu        }
4503c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu
45164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        public void certificate(SslCertificate certificate) {
45264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            // Don't care.
4533c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu        }
4543c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu
45564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        public void error(int id, String description) {
45664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            cleanup();
45764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
45864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu
45964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        public boolean handleSslErrorRequest(SslError error) {
46064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            // Don't care. If this happens, data() will never be called so
46164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            // mPosterBytes will never be created, so no need to call cleanup.
46264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            return false;
46364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
46464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // Tears down the poster bytes stream. Called on network thread.
46564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private void cleanup() {
46664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            if (mPosterBytes != null) {
46764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                try {
46864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                    mPosterBytes.close();
46964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                } catch (IOException ignored) {
47064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                    // Ignored.
47164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                } finally {
47264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                    mPosterBytes = null;
47364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                }
4743c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu            }
47564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
47664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu
47764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // Queue management methods. Called on WebCore thread.
47864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private void retainQueue() {
47964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            if (mRequestQueue == null) {
48064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                mRequestQueue = new RequestQueue(mProxy.getContext());
4813c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu            }
48264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            mQueueRefCount++;
4833c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu        }
4843c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu
48564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        private void releaseQueue() {
48664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            if (mQueueRefCount == 0) {
48764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                return;
48864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            }
48964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            if (--mQueueRefCount == 0) {
49064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                mRequestQueue.shutdown();
49164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                mRequestQueue = null;
49264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            }
4933c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu        }
4943c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu    }
4956fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu
4966fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu    /**
4976fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu     * Private constructor.
498290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu     * @param webView is the WebView that hosts the video.
499290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu     * @param nativePtr is the C++ pointer to the MediaPlayerPrivate object.
5006fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu     */
501290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    private HTML5VideoViewProxy(WebView webView, int nativePtr) {
5026fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu        // This handler is for the main (UI) thread.
5036fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu        super(Looper.getMainLooper());
5043c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu        // Save the WebView object.
5053c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu        mWebView = webView;
506661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // Pass Proxy into webview, such that every time we have a setBaseLayer
507661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // call, we tell this Proxy to call the native to update the layer tree
508661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        // for the Video Layer's surface texture info
509661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        mWebView.setHTML5VideoViewProxy(this);
510290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        // Save the native ptr
511290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        mNativePointer = nativePtr;
51264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // create the message handler for this thread
51364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        createWebCoreHandler();
5146fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu    }
5156fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu
51664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    private void createWebCoreHandler() {
51764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        mWebCoreHandler = new Handler() {
51864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            @Override
51964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            public void handleMessage(Message msg) {
52064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu                switch (msg.what) {
521290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                    case PREPARED: {
522290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                        Map<String, Object> map = (Map<String, Object>) msg.obj;
523290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                        Integer duration = (Integer) map.get("dur");
524290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                        Integer width = (Integer) map.get("width");
525290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                        Integer height = (Integer) map.get("height");
526290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                        nativeOnPrepared(duration.intValue(), width.intValue(),
527290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                                height.intValue(), mNativePointer);
528290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                        break;
529290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                    }
530290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                    case ENDED:
531ff19d19e016f67edf0a4e8eea374d144dc5129efBen Murdoch                        mSeekPosition = 0;
532290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                        nativeOnEnded(mNativePointer);
533290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu                        break;
53443aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang                    case PAUSED:
53543aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang                        nativeOnPaused(mNativePointer);
53643aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang                        break;
53750c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                    case POSTER_FETCHED:
53850c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                        Bitmap poster = (Bitmap) msg.obj;
53950c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                        nativeOnPosterFetched(poster, mNativePointer);
54050c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu                        break;
541048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu                    case TIMEUPDATE:
542048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu                        nativeOnTimeupdate(msg.arg1, mNativePointer);
543048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu                        break;
5443c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu                }
54564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            }
54664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        };
54764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    }
54864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu
54964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    private void doSetPoster(Bitmap poster) {
55064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        if (poster == null) {
55164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            return;
5526fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu        }
55350c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu        // Save a ref to the bitmap and send it over to the WebCore thread.
55450c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu        mPoster = poster;
55550c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu        Message msg = Message.obtain(mWebCoreHandler, POSTER_FETCHED);
55650c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu        msg.obj = poster;
55750c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu        mWebCoreHandler.sendMessage(msg);
5586fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu    }
5596fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu
560048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu    private void sendTimeupdate() {
561048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu        Message msg = Message.obtain(mWebCoreHandler, TIMEUPDATE);
562048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu        msg.arg1 = VideoPlayer.getCurrentPosition();
563048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu        mWebCoreHandler.sendMessage(msg);
564048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu    }
565048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu
56664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    public Context getContext() {
56764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        return mWebView.getContext();
56864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    }
56964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu
57064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    // The public methods below are all called from WebKit only.
5716fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu    /**
5726fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu     * Play a video stream.
5736fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu     * @param url is the URL of the video stream.
5746fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu     */
575661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu    public void play(String url, int position, int videoLayerID) {
57664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        if (url == null) {
57764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            return;
57864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
579ff19d19e016f67edf0a4e8eea374d144dc5129efBen Murdoch
580ff19d19e016f67edf0a4e8eea374d144dc5129efBen Murdoch        if (position > 0) {
581ff19d19e016f67edf0a4e8eea374d144dc5129efBen Murdoch            seek(position);
582ff19d19e016f67edf0a4e8eea374d144dc5129efBen Murdoch        }
5836fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu        Message message = obtainMessage(PLAY);
584661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        message.arg1 = videoLayerID;
58564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        message.obj = url;
5866fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu        sendMessage(message);
5876fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu    }
5886fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu
58964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    /**
590290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu     * Seek into the video stream.
591290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu     * @param  time is the position in the video stream.
592290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu     */
593290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    public void seek(int time) {
594290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        Message message = obtainMessage(SEEK);
595290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        message.obj = new Integer(time);
596290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        sendMessage(message);
597290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    }
598290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu
599290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    /**
600290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu     * Pause the playback.
601290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu     */
602290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    public void pause() {
603290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        Message message = obtainMessage(PAUSE);
604290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        sendMessage(message);
605290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    }
606290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu
607290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    /**
60850c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu     * Tear down this proxy object.
60964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu     */
61050c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    public void teardown() {
61164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // This is called by the C++ MediaPlayerPrivate dtor.
61264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // Cancel any active poster download.
61364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        if (mPosterDownloader != null) {
61464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            mPosterDownloader.cancelAndReleaseQueue();
61564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
61650c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu        mNativePointer = 0;
61764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    }
61864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu
61964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    /**
62064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu     * Load the poster image.
62164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu     * @param url is the URL of the poster image.
62264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu     */
62364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu    public void loadPoster(String url) {
62464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        if (url == null) {
62550c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu            Message message = obtainMessage(LOAD_DEFAULT_POSTER);
62650c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu            sendMessage(message);
62764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            return;
62864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
62964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // Cancel any active poster download.
63064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        if (mPosterDownloader != null) {
63164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu            mPosterDownloader.cancelAndReleaseQueue();
63264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        }
63364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        // Load the poster asynchronously
63464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        mPosterDownloader = new PosterDownloader(url, this);
63564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu        mPosterDownloader.start();
6360a5ce01eda210f83619ada0603a80fd883512fe9Patrick Scott    }
6370a5ce01eda210f83619ada0603a80fd883512fe9Patrick Scott
63810ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu    // These three function are called from UI thread only by WebView.
639661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu    public void setBaseLayer(int layer) {
640661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        VideoPlayer.setBaseLayer(layer);
641661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu    }
642661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu
643661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu    public void pauseAndDispatch() {
644661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu        VideoPlayer.pauseAndDispatch();
645661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu    }
64610ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu
64710ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu    public void enterFullScreenVideo(int layerId, String url) {
64810ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu        VideoPlayer.enterFullScreenVideo(layerId, url, this, mWebView);
64910ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu    }
65010ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu
6516fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu    /**
6523c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu     * The factory for HTML5VideoViewProxy instances.
6536fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu     * @param webViewCore is the WebViewCore that is requesting the proxy.
6546fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu     *
6553c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu     * @return a new HTML5VideoViewProxy object.
6566fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu     */
657290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    public static HTML5VideoViewProxy getInstance(WebViewCore webViewCore, int nativePtr) {
658290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu        return new HTML5VideoViewProxy(webViewCore.getWebView(), nativePtr);
6596fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu    }
660290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu
6611708ad53c3669b72d20724e52301eecd35e86377Ben Murdoch    /* package */ WebView getWebView() {
6621708ad53c3669b72d20724e52301eecd35e86377Ben Murdoch        return mWebView;
6631708ad53c3669b72d20724e52301eecd35e86377Ben Murdoch    }
6641708ad53c3669b72d20724e52301eecd35e86377Ben Murdoch
665290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    private native void nativeOnPrepared(int duration, int width, int height, int nativePointer);
666290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu    private native void nativeOnEnded(int nativePointer);
66743aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang    private native void nativeOnPaused(int nativePointer);
66850c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu    private native void nativeOnPosterFetched(Bitmap poster, int nativePointer);
669048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu    private native void nativeOnTimeupdate(int position, int nativePointer);
670661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu    private native static boolean nativeSendSurfaceTexture(SurfaceTexture texture,
671661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu            int baseLayer, int videoLayerId, int textureName,
672265db32f31a9db60d4a93d59befa07c825cbe4f2Teng-Hui Zhu            int playerState);
6736fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu}
674