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; 345558eacfbfb1294912c5dde2179793ccfe2b7324Teng-Hui Zhuimport android.view.KeyEvent; 355558eacfbfb1294912c5dde2179793ccfe2b7324Teng-Hui Zhuimport android.view.View; 366fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu 3764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescuimport java.io.ByteArrayOutputStream; 3864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescuimport java.io.IOException; 3942509799f261c844bf6be66ce630c47bdee620f3Ben Murdochimport java.net.MalformedURLException; 4042509799f261c844bf6be66ce630c47bdee620f3Ben Murdochimport java.net.URL; 416fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescuimport java.util.HashMap; 42290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescuimport java.util.Map; 436fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu 446fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu/** 453c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu * <p>Proxy for HTML5 video views. 466fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu */ 47290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescuclass HTML5VideoViewProxy extends Handler 48290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu implements MediaPlayer.OnPreparedListener, 4950c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu MediaPlayer.OnCompletionListener, 50661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu MediaPlayer.OnErrorListener, 51c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu MediaPlayer.OnInfoListener, 525558eacfbfb1294912c5dde2179793ccfe2b7324Teng-Hui Zhu SurfaceTexture.OnFrameAvailableListener, 535558eacfbfb1294912c5dde2179793ccfe2b7324Teng-Hui Zhu View.OnKeyListener { 546fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu // Logging tag. 556fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu private static final String LOGTAG = "HTML5VideoViewProxy"; 566fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu 573c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu // Message Ids for WebCore thread -> UI thread communication. 5850c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu private static final int PLAY = 100; 5950c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu private static final int SEEK = 101; 6050c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu private static final int PAUSE = 102; 6150c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu private static final int ERROR = 103; 6250c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu private static final int LOAD_DEFAULT_POSTER = 104; 63c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu private static final int BUFFERING_START = 105; 64c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu private static final int BUFFERING_END = 106; 65c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu private static final int ENTER_FULLSCREEN = 107; 666fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu 6764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // Message Ids to be handled on the WebCore thread 68290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu private static final int PREPARED = 200; 69290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu private static final int ENDED = 201; 7050c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu private static final int POSTER_FETCHED = 202; 7143aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang private static final int PAUSED = 203; 72b109c8877139077fe25fa26ea2e0961b7cbb8341Teng-Hui Zhu private static final int STOPFULLSCREEN = 204; 73e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu private static final int RESTORESTATE = 205; 7464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu 75048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu // Timer thread -> UI thread 76048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu private static final int TIMEUPDATE = 300; 77048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu 78290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu // The C++ MediaPlayerPrivateAndroid object. 79290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu int mNativePointer; 8064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // The handler for WebCore thread messages; 8164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu private Handler mWebCoreHandler; 823c90952036a5ff7ddb2946c643f1a0bf1c31d53aJonathan Dixon // The WebViewClassic instance that created this view. 833c90952036a5ff7ddb2946c643f1a0bf1c31d53aJonathan Dixon private WebViewClassic mWebView; 8464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // The poster image to be shown when the video is not playing. 8550c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu // This ref prevents the bitmap from being GC'ed. 8650c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu private Bitmap mPoster; 8764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // The poster downloader. 8864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu private PosterDownloader mPosterDownloader; 89290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu // The seek position. 90290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu private int mSeekPosition; 9164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // A helper class to control the playback. This executes on the UI thread! 9264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu private static final class VideoPlayer { 9364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // The proxy that is currently playing (if any). 9464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu private static HTML5VideoViewProxy mCurrentProxy; 9564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // The VideoView instance. This is a singleton for now, at least until 9664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // http://b/issue?id=1973663 is fixed. 97661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu private static HTML5VideoView mHTML5VideoView; 98048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu 99661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu private static boolean isVideoSelfEnded = false; 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) { 10910ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu // Don't do this for full screen mode. 11010ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu if (mHTML5VideoView != null 111156f97b6c8580b790600b09b679b9dab8b271c5dTeng-Hui Zhu && !mHTML5VideoView.isFullScreenMode() 112156f97b6c8580b790600b09b679b9dab8b271c5dTeng-Hui Zhu && !mHTML5VideoView.isReleased()) { 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; 217156f97b6c8580b790600b09b679b9dab8b271c5dTeng-Hui Zhu if (backFromFullScreenMode 218156f97b6c8580b790600b09b679b9dab8b271c5dTeng-Hui Zhu && currentVideoLayerId == videoLayerId 219156f97b6c8580b790600b09b679b9dab8b271c5dTeng-Hui Zhu && !mHTML5VideoView.isReleased()) { 220c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu skipPrepare = true; 221c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu createInlineView = true; 222c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu } else if(backFromFullScreenMode 2233fafd39d0776a15c3613795183043a2c28277691Teng-Hui Zhu || currentVideoLayerId != videoLayerId 224c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu || HTML5VideoInline.surfaceTextureDeleted()) { 225661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu // Here, we handle the case when switching to a new video, 226661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu // either inside a WebView or across WebViews 227661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu // For switching videos within a WebView or across the WebView, 228661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu // we need to pause the old one and re-create a new media player 229661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu // inside the HTML5VideoView. 230661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu if (mHTML5VideoView != null) { 23122954d435d645d48885f653bd4ca6bc79e1bcd83Teng-Hui Zhu if (!backFromFullScreenMode) { 23222954d435d645d48885f653bd4ca6bc79e1bcd83Teng-Hui Zhu mHTML5VideoView.pauseAndDispatch(mCurrentProxy); 23322954d435d645d48885f653bd4ca6bc79e1bcd83Teng-Hui Zhu } 234c2b06d5a83f8f118eaf46f093126da08a28715ebTeng-Hui Zhu mHTML5VideoView.reset(); 235a41f97bd77f2583e2e3698cfbba62230a8ac4789Andrei Popescu } 236c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu createInlineView = true; 237c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu } 238c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu if (createInlineView) { 239661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu mCurrentProxy = proxy; 240c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu mHTML5VideoView = new HTML5VideoInline(videoLayerId, time, skipPrepare); 241a41f97bd77f2583e2e3698cfbba62230a8ac4789Andrei Popescu 24210ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu mHTML5VideoView.setVideoURI(url, mCurrentProxy); 24310ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu mHTML5VideoView.prepareDataAndDisplayMode(proxy); 244c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu return; 245c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu } 246c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu 247c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu if (mCurrentProxy == proxy) { 248661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu // Here, we handle the case when we keep playing with one video 249661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu if (!mHTML5VideoView.isPlaying()) { 250661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu mHTML5VideoView.seekTo(time); 251661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu mHTML5VideoView.start(); 252661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu } 253661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu } else if (mCurrentProxy != null) { 25410ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu // Some other video is already playing. Notify the caller that 25510ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu // its playback ended. 256661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu proxy.dispatchOnEnded(); 257bf385d7c7b093564738f8cfd4386daf5e94b8a6dAndrei Popescu } 25864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu } 259290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu 260048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu public static boolean isPlaying(HTML5VideoViewProxy proxy) { 261661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu return (mCurrentProxy == proxy && mHTML5VideoView != null 262661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu && mHTML5VideoView.isPlaying()); 263048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu } 264048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu 265048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu public static int getCurrentPosition() { 266048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu int currentPosMs = 0; 267661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu if (mHTML5VideoView != null) { 268661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu currentPosMs = mHTML5VideoView.getCurrentPosition(); 269048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu } 270048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu return currentPosMs; 271048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu } 272048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu 273290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu public static void seek(int time, HTML5VideoViewProxy proxy) { 274661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu if (mCurrentProxy == proxy && time >= 0 && mHTML5VideoView != null) { 275661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu mHTML5VideoView.seekTo(time); 276290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu } 277290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu } 278290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu 279290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu public static void pause(HTML5VideoViewProxy proxy) { 280661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu if (mCurrentProxy == proxy && mHTML5VideoView != null) { 281661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu mHTML5VideoView.pause(); 282290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu } 283290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu } 284bf385d7c7b093564738f8cfd4386daf5e94b8a6dAndrei Popescu 285bf385d7c7b093564738f8cfd4386daf5e94b8a6dAndrei Popescu public static void onPrepared() { 286e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu if (!mHTML5VideoView.isFullScreenMode()) { 2870504967cb05f7bbd0c17962360a5d88ace8d173fTeng-Hui Zhu mHTML5VideoView.start(); 2880504967cb05f7bbd0c17962360a5d88ace8d173fTeng-Hui Zhu } 289661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu } 290661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu 291661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu public static void end() { 2924dd9dc8204105a25e37dacbc392ea3c7212a8063Teng-Hui Zhu mHTML5VideoView.showControllerInFullScreen(); 293661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu if (mCurrentProxy != null) { 294661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu if (isVideoSelfEnded) 295661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu mCurrentProxy.dispatchOnEnded(); 296661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu else 297661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu mCurrentProxy.dispatchOnPaused(); 298661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu } 299661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu isVideoSelfEnded = false; 300bf385d7c7b093564738f8cfd4386daf5e94b8a6dAndrei Popescu } 301290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu } 302290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu 303290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu // A bunch event listeners for our VideoView 304290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu // MediaPlayer.OnPreparedListener 3055558eacfbfb1294912c5dde2179793ccfe2b7324Teng-Hui Zhu @Override 306290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu public void onPrepared(MediaPlayer mp) { 307bf385d7c7b093564738f8cfd4386daf5e94b8a6dAndrei Popescu VideoPlayer.onPrepared(); 308290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu Message msg = Message.obtain(mWebCoreHandler, PREPARED); 309290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu Map<String, Object> map = new HashMap<String, Object>(); 310290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu map.put("dur", new Integer(mp.getDuration())); 311290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu map.put("width", new Integer(mp.getVideoWidth())); 312290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu map.put("height", new Integer(mp.getVideoHeight())); 313290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu msg.obj = map; 314290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu mWebCoreHandler.sendMessage(msg); 315290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu } 316290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu 317290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu // MediaPlayer.OnCompletionListener; 3185558eacfbfb1294912c5dde2179793ccfe2b7324Teng-Hui Zhu @Override 319290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu public void onCompletion(MediaPlayer mp) { 320c4fbceb57bcfbabb6e370e2dd6448184dc116015Andrei Popescu // The video ended by itself, so we need to 321c4fbceb57bcfbabb6e370e2dd6448184dc116015Andrei Popescu // send a message to the UI thread to dismiss 322c4fbceb57bcfbabb6e370e2dd6448184dc116015Andrei Popescu // the video view and to return to the WebView. 32343aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang // arg1 == 1 means the video ends by itself. 32443aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang sendMessage(obtainMessage(ENDED, 1, 0)); 325290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu } 326290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu 32750c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu // MediaPlayer.OnErrorListener 3285558eacfbfb1294912c5dde2179793ccfe2b7324Teng-Hui Zhu @Override 32950c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu public boolean onError(MediaPlayer mp, int what, int extra) { 33050c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu sendMessage(obtainMessage(ERROR)); 33150c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu return false; 33250c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu } 33350c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu 334c4fbceb57bcfbabb6e370e2dd6448184dc116015Andrei Popescu public void dispatchOnEnded() { 335290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu Message msg = Message.obtain(mWebCoreHandler, ENDED); 336290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu mWebCoreHandler.sendMessage(msg); 33764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu } 3383c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu 33943aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang public void dispatchOnPaused() { 340b109c8877139077fe25fa26ea2e0961b7cbb8341Teng-Hui Zhu Message msg = Message.obtain(mWebCoreHandler, PAUSED); 341b109c8877139077fe25fa26ea2e0961b7cbb8341Teng-Hui Zhu mWebCoreHandler.sendMessage(msg); 342b109c8877139077fe25fa26ea2e0961b7cbb8341Teng-Hui Zhu } 343b109c8877139077fe25fa26ea2e0961b7cbb8341Teng-Hui Zhu 344c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu public void dispatchOnStopFullScreen(boolean stillPlaying) { 345b109c8877139077fe25fa26ea2e0961b7cbb8341Teng-Hui Zhu Message msg = Message.obtain(mWebCoreHandler, STOPFULLSCREEN); 346c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu msg.arg1 = stillPlaying ? 1 : 0; 347b109c8877139077fe25fa26ea2e0961b7cbb8341Teng-Hui Zhu mWebCoreHandler.sendMessage(msg); 34843aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang } 34943aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang 350e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu public void dispatchOnRestoreState() { 351e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu Message msg = Message.obtain(mWebCoreHandler, RESTORESTATE); 352e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu mWebCoreHandler.sendMessage(msg); 353e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu } 354e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu 355048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu public void onTimeupdate() { 356048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu sendMessage(obtainMessage(TIMEUPDATE)); 357048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu } 358048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu 359661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu // When there is a frame ready from surface texture, we should tell WebView 360661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu // to refresh. 361661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu @Override 362661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu public void onFrameAvailable(SurfaceTexture surfaceTexture) { 363661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu // TODO: This should support partial invalidation too. 364661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu mWebView.invalidate(); 365661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu } 366661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu 367048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu // Handler for the messages from WebCore or Timer thread to the UI thread. 36864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu @Override 36964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu public void handleMessage(Message msg) { 37064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // This executes on the UI thread. 37164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu switch (msg.what) { 37264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu case PLAY: { 37364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu String url = (String) msg.obj; 37464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu WebChromeClient client = mWebView.getWebChromeClient(); 375661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu int videoLayerID = msg.arg1; 37664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu if (client != null) { 377661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu VideoPlayer.play(url, mSeekPosition, this, client, videoLayerID); 37864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu } 37964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu break; 38064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu } 381c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu case ENTER_FULLSCREEN:{ 382c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu String url = (String) msg.obj; 383c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu WebChromeClient client = mWebView.getWebChromeClient(); 384c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu int videoLayerID = msg.arg1; 385c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu if (client != null) { 386c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu VideoPlayer.enterFullScreenVideo(videoLayerID, url, this, mWebView); 387c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu } 388c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu break; 389c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu } 390290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu case SEEK: { 391290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu Integer time = (Integer) msg.obj; 392290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu mSeekPosition = time; 393290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu VideoPlayer.seek(mSeekPosition, this); 394290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu break; 395290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu } 396290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu case PAUSE: { 397290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu VideoPlayer.pause(this); 398290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu break; 399290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu } 40046a83b4ead517b9fc13b4bee4c59c3eaf4d3fdd9Andrei Popescu case ENDED: 40143aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang if (msg.arg1 == 1) 40243aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang VideoPlayer.isVideoSelfEnded = true; 403661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu VideoPlayer.end(); 404661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu break; 40550c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu case ERROR: { 40650c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu WebChromeClient client = mWebView.getWebChromeClient(); 40750c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu if (client != null) { 40850c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu client.onHideCustomView(); 40950c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu } 41050c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu break; 41150c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu } 41250c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu case LOAD_DEFAULT_POSTER: { 41350c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu WebChromeClient client = mWebView.getWebChromeClient(); 41450c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu if (client != null) { 41550c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu doSetPoster(client.getDefaultVideoPoster()); 41650c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu } 41750c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu break; 41850c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu } 419048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu case TIMEUPDATE: { 420048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu if (VideoPlayer.isPlaying(this)) { 421048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu sendTimeupdate(); 422048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu } 423048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu break; 424048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu } 425c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu case BUFFERING_START: { 426f4d4e9e05f7605118910739c16e493e2ab869aaeTeng-Hui Zhu VideoPlayer.setPlayerBuffering(true); 427c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu break; 428c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu } 429c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu case BUFFERING_END: { 430f4d4e9e05f7605118910739c16e493e2ab869aaeTeng-Hui Zhu VideoPlayer.setPlayerBuffering(false); 431c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu break; 432c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu } 43364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu } 43464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu } 43564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu 43664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // Everything below this comment executes on the WebCore thread, except for 43764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // the EventHandler methods, which are called on the network thread. 43864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu 43964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // A helper class that knows how to download posters 44064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu private static final class PosterDownloader implements EventHandler { 44164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // The request queue. This is static as we have one queue for all posters. 44264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu private static RequestQueue mRequestQueue; 44364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu private static int mQueueRefCount = 0; 44464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // The poster URL 44542509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch private URL mUrl; 44664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // The proxy we're doing this for. 44764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu private final HTML5VideoViewProxy mProxy; 44864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // The poster bytes. We only touch this on the network thread. 44964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu private ByteArrayOutputStream mPosterBytes; 45064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // The request handle. We only touch this on the WebCore thread. 45164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu private RequestHandle mRequestHandle; 45264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // The response status code. 45364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu private int mStatusCode; 45464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // The response headers. 45564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu private Headers mHeaders; 45664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // The handler to handle messages on the WebCore thread. 45764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu private Handler mHandler; 45864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu 45964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu public PosterDownloader(String url, HTML5VideoViewProxy proxy) { 46042509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch try { 46142509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch mUrl = new URL(url); 46242509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch } catch (MalformedURLException e) { 46342509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch mUrl = null; 46442509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch } 46564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu mProxy = proxy; 46664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu mHandler = new Handler(); 46764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu } 46864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // Start the download. Called on WebCore thread. 46964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu public void start() { 47064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu retainQueue(); 47142509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch 47242509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch if (mUrl == null) { 47342509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch return; 47442509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch } 47542509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch 47642509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch // Only support downloading posters over http/https. 47742509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch // FIXME: Add support for other schemes. WebKit seems able to load 47842509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch // posters over other schemes e.g. file://, but gets the dimensions wrong. 47942509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch String protocol = mUrl.getProtocol(); 48042509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch if ("http".equals(protocol) || "https".equals(protocol)) { 48142509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch mRequestHandle = mRequestQueue.queueRequest(mUrl.toString(), "GET", null, 48242509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch this, null, 0); 48342509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch } 48464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu } 48564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // Cancel the download if active and release the queue. Called on WebCore thread. 48664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu public void cancelAndReleaseQueue() { 48764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu if (mRequestHandle != null) { 48864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu mRequestHandle.cancel(); 48964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu mRequestHandle = null; 49064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu } 49164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu releaseQueue(); 49264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu } 49364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // EventHandler methods. Executed on the network thread. 4945558eacfbfb1294912c5dde2179793ccfe2b7324Teng-Hui Zhu @Override 49564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu public void status(int major_version, 49664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu int minor_version, 49764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu int code, 49864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu String reason_phrase) { 49964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu mStatusCode = code; 50064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu } 5013c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu 5025558eacfbfb1294912c5dde2179793ccfe2b7324Teng-Hui Zhu @Override 50364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu public void headers(Headers headers) { 50464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu mHeaders = headers; 5053c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu } 5063c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu 5075558eacfbfb1294912c5dde2179793ccfe2b7324Teng-Hui Zhu @Override 50864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu public void data(byte[] data, int len) { 50964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu if (mPosterBytes == null) { 51064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu mPosterBytes = new ByteArrayOutputStream(); 5113c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu } 51264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu mPosterBytes.write(data, 0, len); 5133c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu } 5143c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu 5155558eacfbfb1294912c5dde2179793ccfe2b7324Teng-Hui Zhu @Override 51664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu public void endData() { 51764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu if (mStatusCode == 200) { 51864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu if (mPosterBytes.size() > 0) { 51964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu Bitmap poster = BitmapFactory.decodeByteArray( 52064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu mPosterBytes.toByteArray(), 0, mPosterBytes.size()); 52150c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu mProxy.doSetPoster(poster); 52264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu } 52364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu cleanup(); 52464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu } else if (mStatusCode >= 300 && mStatusCode < 400) { 52564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // We have a redirect. 52642509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch try { 52742509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch mUrl = new URL(mHeaders.getLocation()); 52842509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch } catch (MalformedURLException e) { 52942509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch mUrl = null; 53042509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch } 53164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu if (mUrl != null) { 53264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu mHandler.post(new Runnable() { 5335558eacfbfb1294912c5dde2179793ccfe2b7324Teng-Hui Zhu @Override 53464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu public void run() { 53564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu if (mRequestHandle != null) { 53642509799f261c844bf6be66ce630c47bdee620f3Ben Murdoch mRequestHandle.setupRedirect(mUrl.toString(), mStatusCode, 53764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu new HashMap<String, String>()); 53864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu } 53964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu } 54064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu }); 54164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu } 54264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu } 5433c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu } 5443c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu 5455558eacfbfb1294912c5dde2179793ccfe2b7324Teng-Hui Zhu @Override 54664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu public void certificate(SslCertificate certificate) { 54764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // Don't care. 5483c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu } 5493c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu 5505558eacfbfb1294912c5dde2179793ccfe2b7324Teng-Hui Zhu @Override 55164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu public void error(int id, String description) { 55264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu cleanup(); 55364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu } 55464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu 5555558eacfbfb1294912c5dde2179793ccfe2b7324Teng-Hui Zhu @Override 55664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu public boolean handleSslErrorRequest(SslError error) { 55764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // Don't care. If this happens, data() will never be called so 55864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // mPosterBytes will never be created, so no need to call cleanup. 55964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu return false; 56064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu } 56164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // Tears down the poster bytes stream. Called on network thread. 56264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu private void cleanup() { 56364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu if (mPosterBytes != null) { 56464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu try { 56564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu mPosterBytes.close(); 56664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu } catch (IOException ignored) { 56764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // Ignored. 56864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu } finally { 56964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu mPosterBytes = null; 57064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu } 5713c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu } 57264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu } 57364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu 57464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // Queue management methods. Called on WebCore thread. 57564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu private void retainQueue() { 57664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu if (mRequestQueue == null) { 57764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu mRequestQueue = new RequestQueue(mProxy.getContext()); 5783c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu } 57964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu mQueueRefCount++; 5803c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu } 5813c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu 58264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu private void releaseQueue() { 58364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu if (mQueueRefCount == 0) { 58464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu return; 58564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu } 58664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu if (--mQueueRefCount == 0) { 58764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu mRequestQueue.shutdown(); 58864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu mRequestQueue = null; 58964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu } 5903c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu } 5913c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu } 5926fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu 5936fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu /** 5946fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu * Private constructor. 595290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu * @param webView is the WebView that hosts the video. 596290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu * @param nativePtr is the C++ pointer to the MediaPlayerPrivate object. 5976fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu */ 5983c90952036a5ff7ddb2946c643f1a0bf1c31d53aJonathan Dixon private HTML5VideoViewProxy(WebViewClassic webView, int nativePtr) { 5996fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu // This handler is for the main (UI) thread. 6006fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu super(Looper.getMainLooper()); 6013c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu // Save the WebView object. 6023c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu mWebView = webView; 603661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu // Pass Proxy into webview, such that every time we have a setBaseLayer 604661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu // call, we tell this Proxy to call the native to update the layer tree 605661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu // for the Video Layer's surface texture info 606661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu mWebView.setHTML5VideoViewProxy(this); 607290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu // Save the native ptr 608290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu mNativePointer = nativePtr; 60964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // create the message handler for this thread 61064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu createWebCoreHandler(); 6116fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu } 6126fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu 61364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu private void createWebCoreHandler() { 61464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu mWebCoreHandler = new Handler() { 61564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu @Override 61664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu public void handleMessage(Message msg) { 61764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu switch (msg.what) { 618290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu case PREPARED: { 619290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu Map<String, Object> map = (Map<String, Object>) msg.obj; 620290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu Integer duration = (Integer) map.get("dur"); 621290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu Integer width = (Integer) map.get("width"); 622290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu Integer height = (Integer) map.get("height"); 623290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu nativeOnPrepared(duration.intValue(), width.intValue(), 624290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu height.intValue(), mNativePointer); 625290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu break; 626290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu } 627290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu case ENDED: 628ff19d19e016f67edf0a4e8eea374d144dc5129efBen Murdoch mSeekPosition = 0; 629290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu nativeOnEnded(mNativePointer); 630290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu break; 63143aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang case PAUSED: 63243aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang nativeOnPaused(mNativePointer); 63343aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang break; 63450c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu case POSTER_FETCHED: 63550c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu Bitmap poster = (Bitmap) msg.obj; 63650c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu nativeOnPosterFetched(poster, mNativePointer); 63750c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu break; 638048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu case TIMEUPDATE: 639048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu nativeOnTimeupdate(msg.arg1, mNativePointer); 640048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu break; 641b109c8877139077fe25fa26ea2e0961b7cbb8341Teng-Hui Zhu case STOPFULLSCREEN: 642c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu nativeOnStopFullscreen(msg.arg1, mNativePointer); 643b109c8877139077fe25fa26ea2e0961b7cbb8341Teng-Hui Zhu break; 644e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu case RESTORESTATE: 645e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu nativeOnRestoreState(mNativePointer); 646e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu break; 6473c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu } 64864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu } 64964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu }; 65064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu } 65164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu 65264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu private void doSetPoster(Bitmap poster) { 65364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu if (poster == null) { 65464b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu return; 6556fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu } 65650c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu // Save a ref to the bitmap and send it over to the WebCore thread. 65750c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu mPoster = poster; 65850c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu Message msg = Message.obtain(mWebCoreHandler, POSTER_FETCHED); 65950c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu msg.obj = poster; 66050c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu mWebCoreHandler.sendMessage(msg); 6616fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu } 6626fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu 663048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu private void sendTimeupdate() { 664048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu Message msg = Message.obtain(mWebCoreHandler, TIMEUPDATE); 665048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu msg.arg1 = VideoPlayer.getCurrentPosition(); 666048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu mWebCoreHandler.sendMessage(msg); 667048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu } 668048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu 66964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu public Context getContext() { 67064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu return mWebView.getContext(); 67164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu } 67264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu 67364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // The public methods below are all called from WebKit only. 6746fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu /** 6756fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu * Play a video stream. 6766fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu * @param url is the URL of the video stream. 6776fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu */ 678661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu public void play(String url, int position, int videoLayerID) { 67964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu if (url == null) { 68064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu return; 68164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu } 682ff19d19e016f67edf0a4e8eea374d144dc5129efBen Murdoch 683ff19d19e016f67edf0a4e8eea374d144dc5129efBen Murdoch if (position > 0) { 684ff19d19e016f67edf0a4e8eea374d144dc5129efBen Murdoch seek(position); 685ff19d19e016f67edf0a4e8eea374d144dc5129efBen Murdoch } 6866fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu Message message = obtainMessage(PLAY); 687661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu message.arg1 = videoLayerID; 68864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu message.obj = url; 6896fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu sendMessage(message); 6906fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu } 6916fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu 69264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu /** 693c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu * Play a video stream in full screen mode. 694c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu * @param url is the URL of the video stream. 695c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu */ 696c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu public void enterFullscreenForVideoLayer(String url, int videoLayerID) { 697c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu if (url == null) { 698c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu return; 699c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu } 700c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu 701c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu Message message = obtainMessage(ENTER_FULLSCREEN); 702c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu message.arg1 = videoLayerID; 703c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu message.obj = url; 704c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu sendMessage(message); 705c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu } 706c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu 707c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu /** 708290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu * Seek into the video stream. 709290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu * @param time is the position in the video stream. 710290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu */ 711290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu public void seek(int time) { 712290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu Message message = obtainMessage(SEEK); 713290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu message.obj = new Integer(time); 714290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu sendMessage(message); 715290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu } 716290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu 717290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu /** 718290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu * Pause the playback. 719290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu */ 720290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu public void pause() { 721290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu Message message = obtainMessage(PAUSE); 722290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu sendMessage(message); 723290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu } 724290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu 725290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu /** 72650c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu * Tear down this proxy object. 72764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu */ 72850c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu public void teardown() { 72964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // This is called by the C++ MediaPlayerPrivate dtor. 73064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // Cancel any active poster download. 73164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu if (mPosterDownloader != null) { 73264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu mPosterDownloader.cancelAndReleaseQueue(); 73364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu } 73450c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu mNativePointer = 0; 73564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu } 73664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu 73764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu /** 73864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu * Load the poster image. 73964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu * @param url is the URL of the poster image. 74064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu */ 74164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu public void loadPoster(String url) { 74264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu if (url == null) { 74350c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu Message message = obtainMessage(LOAD_DEFAULT_POSTER); 74450c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu sendMessage(message); 74564b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu return; 74664b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu } 74764b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // Cancel any active poster download. 74864b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu if (mPosterDownloader != null) { 74964b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu mPosterDownloader.cancelAndReleaseQueue(); 75064b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu } 75164b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu // Load the poster asynchronously 75264b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu mPosterDownloader = new PosterDownloader(url, this); 75364b86a1e8b6679ed10ecf344abcaebc8412b2efbAndrei Popescu mPosterDownloader.start(); 7540a5ce01eda210f83619ada0603a80fd883512fe9Patrick Scott } 7550a5ce01eda210f83619ada0603a80fd883512fe9Patrick Scott 75610ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu // These three function are called from UI thread only by WebView. 757661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu public void setBaseLayer(int layer) { 758661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu VideoPlayer.setBaseLayer(layer); 759661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu } 760661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu 761661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu public void pauseAndDispatch() { 762661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu VideoPlayer.pauseAndDispatch(); 763661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu } 76410ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu 76510ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu public void enterFullScreenVideo(int layerId, String url) { 76610ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu VideoPlayer.enterFullScreenVideo(layerId, url, this, mWebView); 76710ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu } 76810ab654943b386c0816a33dbd639c3b8d6260b01Teng-Hui Zhu 769d7678a1684966cac10717b34b161b5241b9865c5Teng-Hui Zhu public void exitFullScreenVideo() { 770d7678a1684966cac10717b34b161b5241b9865c5Teng-Hui Zhu VideoPlayer.exitFullScreenVideo(this, mWebView); 771d7678a1684966cac10717b34b161b5241b9865c5Teng-Hui Zhu } 772d7678a1684966cac10717b34b161b5241b9865c5Teng-Hui Zhu 7736fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu /** 7743c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu * The factory for HTML5VideoViewProxy instances. 7756fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu * @param webViewCore is the WebViewCore that is requesting the proxy. 7766fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu * 7773c946a1a9637e85e4256f40b68f3b9d4b9f40c27Andrei Popescu * @return a new HTML5VideoViewProxy object. 7786fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu */ 779290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu public static HTML5VideoViewProxy getInstance(WebViewCore webViewCore, int nativePtr) { 780a6c4d8e018e39ff94263ce8f2a31b768104d1bb6Jonathan Dixon return new HTML5VideoViewProxy(webViewCore.getWebViewClassic(), nativePtr); 7816fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu } 782290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu 7833c90952036a5ff7ddb2946c643f1a0bf1c31d53aJonathan Dixon /* package */ WebViewClassic getWebView() { 7841708ad53c3669b72d20724e52301eecd35e86377Ben Murdoch return mWebView; 7851708ad53c3669b72d20724e52301eecd35e86377Ben Murdoch } 7861708ad53c3669b72d20724e52301eecd35e86377Ben Murdoch 787290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu private native void nativeOnPrepared(int duration, int width, int height, int nativePointer); 788290c34ac3a36b407b74b42c37501c2d0cdac70adAndrei Popescu private native void nativeOnEnded(int nativePointer); 78943aaa2dd3f1f5169145338ba93f3c9f59fa4b1eaShimeng (Simon) Wang private native void nativeOnPaused(int nativePointer); 79050c862324b8c4b9a130beeba6378ca3398960fb7Andrei Popescu private native void nativeOnPosterFetched(Bitmap poster, int nativePointer); 791048eb3bfa124f0869f644fc82a50696f593fe592Andrei Popescu private native void nativeOnTimeupdate(int position, int nativePointer); 792c3a2858de909145a382e7932d5fb044e1388c0b3Teng-Hui Zhu private native void nativeOnStopFullscreen(int stillPlaying, int nativePointer); 793e4c89e321c7a33a7baf1a90237d21220d637e966Teng-Hui Zhu private native void nativeOnRestoreState(int nativePointer); 794661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu private native static boolean nativeSendSurfaceTexture(SurfaceTexture texture, 795661e8b1f21f03ea429ff34f8fdb58b68a5049092Teng-Hui Zhu int baseLayer, int videoLayerId, int textureName, 796265db32f31a9db60d4a93d59befa07c825cbe4f2Teng-Hui Zhu int playerState); 797c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu 798c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu @Override 799c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu public boolean onInfo(MediaPlayer mp, int what, int extra) { 800c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu if (what == MediaPlayer.MEDIA_INFO_BUFFERING_START) { 801c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu sendMessage(obtainMessage(BUFFERING_START, what, extra)); 802c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu } else if (what == MediaPlayer.MEDIA_INFO_BUFFERING_END) { 803c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu sendMessage(obtainMessage(BUFFERING_END, what, extra)); 804c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu } 805c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu return false; 806c0fccd1292de4d2743fb30fef8310bcda4ce9824Teng-Hui Zhu } 8075558eacfbfb1294912c5dde2179793ccfe2b7324Teng-Hui Zhu 8085558eacfbfb1294912c5dde2179793ccfe2b7324Teng-Hui Zhu @Override 8095558eacfbfb1294912c5dde2179793ccfe2b7324Teng-Hui Zhu public boolean onKey(View v, int keyCode, KeyEvent event) { 8105558eacfbfb1294912c5dde2179793ccfe2b7324Teng-Hui Zhu if (keyCode == KeyEvent.KEYCODE_BACK) { 8115558eacfbfb1294912c5dde2179793ccfe2b7324Teng-Hui Zhu if (event.getAction() == KeyEvent.ACTION_DOWN) { 8125558eacfbfb1294912c5dde2179793ccfe2b7324Teng-Hui Zhu return true; 8135558eacfbfb1294912c5dde2179793ccfe2b7324Teng-Hui Zhu } else if (event.getAction() == KeyEvent.ACTION_UP && !event.isCanceled()) { 8145558eacfbfb1294912c5dde2179793ccfe2b7324Teng-Hui Zhu VideoPlayer.exitFullScreenVideo(this, mWebView); 8155558eacfbfb1294912c5dde2179793ccfe2b7324Teng-Hui Zhu return true; 8165558eacfbfb1294912c5dde2179793ccfe2b7324Teng-Hui Zhu } 8175558eacfbfb1294912c5dde2179793ccfe2b7324Teng-Hui Zhu } 8185558eacfbfb1294912c5dde2179793ccfe2b7324Teng-Hui Zhu return false; 8195558eacfbfb1294912c5dde2179793ccfe2b7324Teng-Hui Zhu } 8206fa2958059a08390ed2b87b8572f8847ad9999e4Andrei Popescu} 821