blob: b7a9065e627577ab1669c1372ac1f4b77086734c [file] [log] [blame]
Andrei Popescu6fa29582009-06-19 14:54:09 +01001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.webkit;
18
19import android.content.Context;
Andrei Popescu64b86a12009-09-15 20:34:18 +010020import android.graphics.Bitmap;
21import android.graphics.BitmapFactory;
Andrei Popescu3c946a1a2009-07-03 08:20:53 +010022import android.media.MediaPlayer;
23import android.media.MediaPlayer.OnPreparedListener;
Andrei Popescu64b86a12009-09-15 20:34:18 +010024import android.media.MediaPlayer.OnCompletionListener;
25import android.media.MediaPlayer.OnErrorListener;
26import android.net.http.EventHandler;
27import android.net.http.Headers;
28import android.net.http.RequestHandle;
29import android.net.http.RequestQueue;
30import android.net.http.SslCertificate;
31import android.net.http.SslError;
Andrei Popescu6fa29582009-06-19 14:54:09 +010032import android.net.Uri;
33import android.os.Bundle;
34import android.os.Handler;
35import android.os.Looper;
36import android.os.Message;
37import android.util.Log;
Andrei Popescu3c946a1a2009-07-03 08:20:53 +010038import android.view.MotionEvent;
Andrei Popescubf385d72009-09-18 18:59:52 +010039import android.view.Gravity;
Andrei Popescu6fa29582009-06-19 14:54:09 +010040import android.view.View;
Andrei Popescu3c946a1a2009-07-03 08:20:53 +010041import android.view.ViewGroup;
Andrei Popescu3c946a1a2009-07-03 08:20:53 +010042import android.widget.AbsoluteLayout;
Andrei Popescubf385d72009-09-18 18:59:52 +010043import android.widget.FrameLayout;
Andrei Popescu6fa29582009-06-19 14:54:09 +010044import android.widget.MediaController;
45import android.widget.VideoView;
46
Andrei Popescu64b86a12009-09-15 20:34:18 +010047import java.io.ByteArrayOutputStream;
48import java.io.IOException;
Andrei Popescu6fa29582009-06-19 14:54:09 +010049import java.util.HashMap;
Andrei Popescu290c34a2009-09-17 15:55:24 +010050import java.util.Map;
Andrei Popescu6fa29582009-06-19 14:54:09 +010051
52/**
Andrei Popescu3c946a1a2009-07-03 08:20:53 +010053 * <p>Proxy for HTML5 video views.
Andrei Popescu6fa29582009-06-19 14:54:09 +010054 */
Andrei Popescu290c34a2009-09-17 15:55:24 +010055class HTML5VideoViewProxy extends Handler
56 implements MediaPlayer.OnPreparedListener,
Andrei Popescu50c86232009-09-30 16:51:25 +010057 MediaPlayer.OnCompletionListener,
58 MediaPlayer.OnErrorListener {
Andrei Popescu6fa29582009-06-19 14:54:09 +010059 // Logging tag.
60 private static final String LOGTAG = "HTML5VideoViewProxy";
61
Andrei Popescu3c946a1a2009-07-03 08:20:53 +010062 // Message Ids for WebCore thread -> UI thread communication.
Andrei Popescu50c86232009-09-30 16:51:25 +010063 private static final int PLAY = 100;
64 private static final int SEEK = 101;
65 private static final int PAUSE = 102;
66 private static final int ERROR = 103;
67 private static final int LOAD_DEFAULT_POSTER = 104;
Andrei Popescu6fa29582009-06-19 14:54:09 +010068
Andrei Popescu64b86a12009-09-15 20:34:18 +010069 // Message Ids to be handled on the WebCore thread
Andrei Popescu290c34a2009-09-17 15:55:24 +010070 private static final int PREPARED = 200;
71 private static final int ENDED = 201;
Andrei Popescu50c86232009-09-30 16:51:25 +010072 private static final int POSTER_FETCHED = 202;
Andrei Popescu64b86a12009-09-15 20:34:18 +010073
Andrei Popescu290c34a2009-09-17 15:55:24 +010074 // The C++ MediaPlayerPrivateAndroid object.
75 int mNativePointer;
Andrei Popescu64b86a12009-09-15 20:34:18 +010076 // The handler for WebCore thread messages;
77 private Handler mWebCoreHandler;
Andrei Popescu3c946a1a2009-07-03 08:20:53 +010078 // The WebView instance that created this view.
79 private WebView mWebView;
Andrei Popescu64b86a12009-09-15 20:34:18 +010080 // The poster image to be shown when the video is not playing.
Andrei Popescu50c86232009-09-30 16:51:25 +010081 // This ref prevents the bitmap from being GC'ed.
82 private Bitmap mPoster;
Andrei Popescu64b86a12009-09-15 20:34:18 +010083 // The poster downloader.
84 private PosterDownloader mPosterDownloader;
Andrei Popescu290c34a2009-09-17 15:55:24 +010085 // The seek position.
86 private int mSeekPosition;
Andrei Popescu64b86a12009-09-15 20:34:18 +010087 // A helper class to control the playback. This executes on the UI thread!
88 private static final class VideoPlayer {
89 // The proxy that is currently playing (if any).
90 private static HTML5VideoViewProxy mCurrentProxy;
91 // The VideoView instance. This is a singleton for now, at least until
92 // http://b/issue?id=1973663 is fixed.
93 private static VideoView mVideoView;
Andrei Popescubf385d72009-09-18 18:59:52 +010094 // The progress view.
95 private static View mProgressView;
96 // The container for the progress view and video view
97 private static FrameLayout mLayout;
Andrei Popescu3c946a1a2009-07-03 08:20:53 +010098
Andrei Popescu64b86a12009-09-15 20:34:18 +010099 private static final WebChromeClient.CustomViewCallback mCallback =
100 new WebChromeClient.CustomViewCallback() {
101 public void onCustomViewHidden() {
102 // At this point the videoview is pretty much destroyed.
103 // It listens to SurfaceHolder.Callback.SurfaceDestroyed event
104 // which happens when the video view is detached from its parent
105 // view. This happens in the WebChromeClient before this method
106 // is invoked.
107 mCurrentProxy.playbackEnded();
108 mCurrentProxy = null;
Andrei Popescubf385d72009-09-18 18:59:52 +0100109 mLayout.removeView(mVideoView);
Andrei Popescu64b86a12009-09-15 20:34:18 +0100110 mVideoView = null;
Andrei Popescubf385d72009-09-18 18:59:52 +0100111 if (mProgressView != null) {
112 mLayout.removeView(mProgressView);
113 mProgressView = null;
114 }
115 mLayout = null;
Andrei Popescu64b86a12009-09-15 20:34:18 +0100116 }
117 };
Andrei Popescu3c946a1a2009-07-03 08:20:53 +0100118
Andrei Popescu290c34a2009-09-17 15:55:24 +0100119 public static void play(String url, int time, HTML5VideoViewProxy proxy,
120 WebChromeClient client) {
Andrei Popescu64b86a12009-09-15 20:34:18 +0100121 if (mCurrentProxy != null) {
122 // Some other video is already playing. Notify the caller that its playback ended.
123 proxy.playbackEnded();
Andrei Popescu3c946a1a2009-07-03 08:20:53 +0100124 return;
125 }
Andrei Popescu64b86a12009-09-15 20:34:18 +0100126 mCurrentProxy = proxy;
Andrei Popescubf385d72009-09-18 18:59:52 +0100127 // Create a FrameLayout that will contain the VideoView and the
128 // progress view (if any).
129 mLayout = new FrameLayout(proxy.getContext());
130 FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
131 ViewGroup.LayoutParams.WRAP_CONTENT,
132 ViewGroup.LayoutParams.WRAP_CONTENT,
133 Gravity.CENTER);
Andrei Popescu64b86a12009-09-15 20:34:18 +0100134 mVideoView = new VideoView(proxy.getContext());
135 mVideoView.setWillNotDraw(false);
136 mVideoView.setMediaController(new MediaController(proxy.getContext()));
137 mVideoView.setVideoURI(Uri.parse(url));
Andrei Popescu290c34a2009-09-17 15:55:24 +0100138 mVideoView.setOnCompletionListener(proxy);
139 mVideoView.setOnPreparedListener(proxy);
Andrei Popescu50c86232009-09-30 16:51:25 +0100140 mVideoView.setOnErrorListener(proxy);
Andrei Popescu290c34a2009-09-17 15:55:24 +0100141 mVideoView.seekTo(time);
Andrei Popescubf385d72009-09-18 18:59:52 +0100142 mLayout.addView(mVideoView, layoutParams);
143 mProgressView = client.getVideoLoadingProgressView();
144 if (mProgressView != null) {
145 mLayout.addView(mProgressView, layoutParams);
146 mProgressView.setVisibility(View.VISIBLE);
147 }
148 mLayout.setVisibility(View.VISIBLE);
Andrei Popescu64b86a12009-09-15 20:34:18 +0100149 mVideoView.start();
Andrei Popescubf385d72009-09-18 18:59:52 +0100150 client.onShowCustomView(mLayout, mCallback);
Andrei Popescu3c946a1a2009-07-03 08:20:53 +0100151 }
Andrei Popescu290c34a2009-09-17 15:55:24 +0100152
153 public static void seek(int time, HTML5VideoViewProxy proxy) {
154 if (mCurrentProxy == proxy && time >= 0 && mVideoView != null) {
155 mVideoView.seekTo(time);
156 }
157 }
158
159 public static void pause(HTML5VideoViewProxy proxy) {
160 if (mCurrentProxy == proxy && mVideoView != null) {
161 mVideoView.pause();
162 }
163 }
Andrei Popescubf385d72009-09-18 18:59:52 +0100164
165 public static void onPrepared() {
Andrei Popescu50c86232009-09-30 16:51:25 +0100166 if (mProgressView == null || mLayout == null) {
167 return;
Andrei Popescubf385d72009-09-18 18:59:52 +0100168 }
Andrei Popescu50c86232009-09-30 16:51:25 +0100169 mProgressView.setVisibility(View.GONE);
170 mLayout.removeView(mProgressView);
171 mProgressView = null;
Andrei Popescubf385d72009-09-18 18:59:52 +0100172 }
Andrei Popescu290c34a2009-09-17 15:55:24 +0100173 }
174
175 // A bunch event listeners for our VideoView
176 // MediaPlayer.OnPreparedListener
177 public void onPrepared(MediaPlayer mp) {
Andrei Popescubf385d72009-09-18 18:59:52 +0100178 VideoPlayer.onPrepared();
Andrei Popescu290c34a2009-09-17 15:55:24 +0100179 Message msg = Message.obtain(mWebCoreHandler, PREPARED);
180 Map<String, Object> map = new HashMap<String, Object>();
181 map.put("dur", new Integer(mp.getDuration()));
182 map.put("width", new Integer(mp.getVideoWidth()));
183 map.put("height", new Integer(mp.getVideoHeight()));
184 msg.obj = map;
185 mWebCoreHandler.sendMessage(msg);
186 }
187
188 // MediaPlayer.OnCompletionListener;
189 public void onCompletion(MediaPlayer mp) {
190 playbackEnded();
191 }
192
Andrei Popescu50c86232009-09-30 16:51:25 +0100193 // MediaPlayer.OnErrorListener
194 public boolean onError(MediaPlayer mp, int what, int extra) {
195 sendMessage(obtainMessage(ERROR));
196 return false;
197 }
198
Andrei Popescu290c34a2009-09-17 15:55:24 +0100199 public void playbackEnded() {
200 Message msg = Message.obtain(mWebCoreHandler, ENDED);
201 mWebCoreHandler.sendMessage(msg);
Andrei Popescu64b86a12009-09-15 20:34:18 +0100202 }
Andrei Popescu3c946a1a2009-07-03 08:20:53 +0100203
Andrei Popescu64b86a12009-09-15 20:34:18 +0100204 // Handler for the messages from WebCore thread to the UI thread.
205 @Override
206 public void handleMessage(Message msg) {
207 // This executes on the UI thread.
208 switch (msg.what) {
Andrei Popescu64b86a12009-09-15 20:34:18 +0100209 case PLAY: {
210 String url = (String) msg.obj;
211 WebChromeClient client = mWebView.getWebChromeClient();
212 if (client != null) {
Andrei Popescu290c34a2009-09-17 15:55:24 +0100213 VideoPlayer.play(url, mSeekPosition, this, client);
Andrei Popescu64b86a12009-09-15 20:34:18 +0100214 }
215 break;
216 }
Andrei Popescu290c34a2009-09-17 15:55:24 +0100217 case SEEK: {
218 Integer time = (Integer) msg.obj;
219 mSeekPosition = time;
220 VideoPlayer.seek(mSeekPosition, this);
221 break;
222 }
223 case PAUSE: {
224 VideoPlayer.pause(this);
225 break;
226 }
Andrei Popescu50c86232009-09-30 16:51:25 +0100227 case ERROR: {
228 WebChromeClient client = mWebView.getWebChromeClient();
229 if (client != null) {
230 client.onHideCustomView();
231 }
232 break;
233 }
234 case LOAD_DEFAULT_POSTER: {
235 WebChromeClient client = mWebView.getWebChromeClient();
236 if (client != null) {
237 doSetPoster(client.getDefaultVideoPoster());
238 }
239 break;
240 }
Andrei Popescu64b86a12009-09-15 20:34:18 +0100241 }
242 }
243
Andrei Popescu64b86a12009-09-15 20:34:18 +0100244 // Everything below this comment executes on the WebCore thread, except for
245 // the EventHandler methods, which are called on the network thread.
246
247 // A helper class that knows how to download posters
248 private static final class PosterDownloader implements EventHandler {
249 // The request queue. This is static as we have one queue for all posters.
250 private static RequestQueue mRequestQueue;
251 private static int mQueueRefCount = 0;
252 // The poster URL
253 private String mUrl;
254 // The proxy we're doing this for.
255 private final HTML5VideoViewProxy mProxy;
256 // The poster bytes. We only touch this on the network thread.
257 private ByteArrayOutputStream mPosterBytes;
258 // The request handle. We only touch this on the WebCore thread.
259 private RequestHandle mRequestHandle;
260 // The response status code.
261 private int mStatusCode;
262 // The response headers.
263 private Headers mHeaders;
264 // The handler to handle messages on the WebCore thread.
265 private Handler mHandler;
266
267 public PosterDownloader(String url, HTML5VideoViewProxy proxy) {
268 mUrl = url;
269 mProxy = proxy;
270 mHandler = new Handler();
271 }
272 // Start the download. Called on WebCore thread.
273 public void start() {
274 retainQueue();
275 mRequestHandle = mRequestQueue.queueRequest(mUrl, "GET", null, this, null, 0);
276 }
277 // Cancel the download if active and release the queue. Called on WebCore thread.
278 public void cancelAndReleaseQueue() {
279 if (mRequestHandle != null) {
280 mRequestHandle.cancel();
281 mRequestHandle = null;
282 }
283 releaseQueue();
284 }
285 // EventHandler methods. Executed on the network thread.
286 public void status(int major_version,
287 int minor_version,
288 int code,
289 String reason_phrase) {
290 mStatusCode = code;
Andrei Popescu3c946a1a2009-07-03 08:20:53 +0100291 }
292
Andrei Popescu64b86a12009-09-15 20:34:18 +0100293 public void headers(Headers headers) {
294 mHeaders = headers;
295 }
296
297 public void data(byte[] data, int len) {
298 if (mPosterBytes == null) {
299 mPosterBytes = new ByteArrayOutputStream();
300 }
301 mPosterBytes.write(data, 0, len);
302 }
303
304 public void endData() {
305 if (mStatusCode == 200) {
306 if (mPosterBytes.size() > 0) {
307 Bitmap poster = BitmapFactory.decodeByteArray(
308 mPosterBytes.toByteArray(), 0, mPosterBytes.size());
Andrei Popescu50c86232009-09-30 16:51:25 +0100309 mProxy.doSetPoster(poster);
Andrei Popescu64b86a12009-09-15 20:34:18 +0100310 }
311 cleanup();
312 } else if (mStatusCode >= 300 && mStatusCode < 400) {
313 // We have a redirect.
314 mUrl = mHeaders.getLocation();
315 if (mUrl != null) {
316 mHandler.post(new Runnable() {
317 public void run() {
318 if (mRequestHandle != null) {
319 mRequestHandle.setupRedirect(mUrl, mStatusCode,
320 new HashMap<String, String>());
321 }
322 }
323 });
324 }
325 }
326 }
327
328 public void certificate(SslCertificate certificate) {
329 // Don't care.
330 }
331
332 public void error(int id, String description) {
333 cleanup();
334 }
335
336 public boolean handleSslErrorRequest(SslError error) {
337 // Don't care. If this happens, data() will never be called so
338 // mPosterBytes will never be created, so no need to call cleanup.
339 return false;
340 }
341 // Tears down the poster bytes stream. Called on network thread.
342 private void cleanup() {
343 if (mPosterBytes != null) {
344 try {
345 mPosterBytes.close();
346 } catch (IOException ignored) {
347 // Ignored.
348 } finally {
349 mPosterBytes = null;
350 }
351 }
352 }
353
354 // Queue management methods. Called on WebCore thread.
355 private void retainQueue() {
356 if (mRequestQueue == null) {
357 mRequestQueue = new RequestQueue(mProxy.getContext());
358 }
359 mQueueRefCount++;
360 }
361
362 private void releaseQueue() {
363 if (mQueueRefCount == 0) {
364 return;
365 }
366 if (--mQueueRefCount == 0) {
367 mRequestQueue.shutdown();
368 mRequestQueue = null;
369 }
Andrei Popescu3c946a1a2009-07-03 08:20:53 +0100370 }
371 }
Andrei Popescu6fa29582009-06-19 14:54:09 +0100372
373 /**
374 * Private constructor.
Andrei Popescu290c34a2009-09-17 15:55:24 +0100375 * @param webView is the WebView that hosts the video.
376 * @param nativePtr is the C++ pointer to the MediaPlayerPrivate object.
Andrei Popescu6fa29582009-06-19 14:54:09 +0100377 */
Andrei Popescu290c34a2009-09-17 15:55:24 +0100378 private HTML5VideoViewProxy(WebView webView, int nativePtr) {
Andrei Popescu6fa29582009-06-19 14:54:09 +0100379 // This handler is for the main (UI) thread.
380 super(Looper.getMainLooper());
Andrei Popescu3c946a1a2009-07-03 08:20:53 +0100381 // Save the WebView object.
382 mWebView = webView;
Andrei Popescu290c34a2009-09-17 15:55:24 +0100383 // Save the native ptr
384 mNativePointer = nativePtr;
Andrei Popescu64b86a12009-09-15 20:34:18 +0100385 // create the message handler for this thread
386 createWebCoreHandler();
Andrei Popescu6fa29582009-06-19 14:54:09 +0100387 }
388
Andrei Popescu64b86a12009-09-15 20:34:18 +0100389 private void createWebCoreHandler() {
390 mWebCoreHandler = new Handler() {
391 @Override
392 public void handleMessage(Message msg) {
393 switch (msg.what) {
Andrei Popescu290c34a2009-09-17 15:55:24 +0100394 case PREPARED: {
395 Map<String, Object> map = (Map<String, Object>) msg.obj;
396 Integer duration = (Integer) map.get("dur");
397 Integer width = (Integer) map.get("width");
398 Integer height = (Integer) map.get("height");
399 nativeOnPrepared(duration.intValue(), width.intValue(),
400 height.intValue(), mNativePointer);
401 break;
402 }
403 case ENDED:
404 nativeOnEnded(mNativePointer);
405 break;
Andrei Popescu50c86232009-09-30 16:51:25 +0100406 case POSTER_FETCHED:
407 Bitmap poster = (Bitmap) msg.obj;
408 nativeOnPosterFetched(poster, mNativePointer);
409 break;
Andrei Popescu3c946a1a2009-07-03 08:20:53 +0100410 }
Andrei Popescu64b86a12009-09-15 20:34:18 +0100411 }
412 };
Andrei Popescu6fa29582009-06-19 14:54:09 +0100413 }
414
Andrei Popescu64b86a12009-09-15 20:34:18 +0100415 private void doSetPoster(Bitmap poster) {
416 if (poster == null) {
417 return;
418 }
Andrei Popescu50c86232009-09-30 16:51:25 +0100419 // Save a ref to the bitmap and send it over to the WebCore thread.
420 mPoster = poster;
421 Message msg = Message.obtain(mWebCoreHandler, POSTER_FETCHED);
422 msg.obj = poster;
423 mWebCoreHandler.sendMessage(msg);
Andrei Popescu64b86a12009-09-15 20:34:18 +0100424 }
425
426 public Context getContext() {
427 return mWebView.getContext();
428 }
429
430 // The public methods below are all called from WebKit only.
Andrei Popescu6fa29582009-06-19 14:54:09 +0100431 /**
432 * Play a video stream.
433 * @param url is the URL of the video stream.
Andrei Popescu6fa29582009-06-19 14:54:09 +0100434 */
Andrei Popescu3c946a1a2009-07-03 08:20:53 +0100435 public void play(String url) {
Andrei Popescu64b86a12009-09-15 20:34:18 +0100436 if (url == null) {
437 return;
438 }
Andrei Popescu6fa29582009-06-19 14:54:09 +0100439 Message message = obtainMessage(PLAY);
Andrei Popescu64b86a12009-09-15 20:34:18 +0100440 message.obj = url;
Andrei Popescu6fa29582009-06-19 14:54:09 +0100441 sendMessage(message);
442 }
443
Andrei Popescu64b86a12009-09-15 20:34:18 +0100444 /**
Andrei Popescu290c34a2009-09-17 15:55:24 +0100445 * Seek into the video stream.
446 * @param time is the position in the video stream.
447 */
448 public void seek(int time) {
449 Message message = obtainMessage(SEEK);
450 message.obj = new Integer(time);
451 sendMessage(message);
452 }
453
454 /**
455 * Pause the playback.
456 */
457 public void pause() {
458 Message message = obtainMessage(PAUSE);
459 sendMessage(message);
460 }
461
462 /**
Andrei Popescu50c86232009-09-30 16:51:25 +0100463 * Tear down this proxy object.
Andrei Popescu64b86a12009-09-15 20:34:18 +0100464 */
Andrei Popescu50c86232009-09-30 16:51:25 +0100465 public void teardown() {
Andrei Popescu64b86a12009-09-15 20:34:18 +0100466 // This is called by the C++ MediaPlayerPrivate dtor.
467 // Cancel any active poster download.
468 if (mPosterDownloader != null) {
469 mPosterDownloader.cancelAndReleaseQueue();
470 }
Andrei Popescu50c86232009-09-30 16:51:25 +0100471 mNativePointer = 0;
Andrei Popescu64b86a12009-09-15 20:34:18 +0100472 }
473
474 /**
475 * Load the poster image.
476 * @param url is the URL of the poster image.
477 */
478 public void loadPoster(String url) {
479 if (url == null) {
Andrei Popescu50c86232009-09-30 16:51:25 +0100480 Message message = obtainMessage(LOAD_DEFAULT_POSTER);
481 sendMessage(message);
Andrei Popescu64b86a12009-09-15 20:34:18 +0100482 return;
483 }
484 // Cancel any active poster download.
485 if (mPosterDownloader != null) {
486 mPosterDownloader.cancelAndReleaseQueue();
487 }
488 // Load the poster asynchronously
489 mPosterDownloader = new PosterDownloader(url, this);
490 mPosterDownloader.start();
Patrick Scott0a5ce012009-07-02 08:56:10 -0400491 }
492
Andrei Popescu6fa29582009-06-19 14:54:09 +0100493 /**
Andrei Popescu3c946a1a2009-07-03 08:20:53 +0100494 * The factory for HTML5VideoViewProxy instances.
Andrei Popescu6fa29582009-06-19 14:54:09 +0100495 * @param webViewCore is the WebViewCore that is requesting the proxy.
496 *
Andrei Popescu3c946a1a2009-07-03 08:20:53 +0100497 * @return a new HTML5VideoViewProxy object.
Andrei Popescu6fa29582009-06-19 14:54:09 +0100498 */
Andrei Popescu290c34a2009-09-17 15:55:24 +0100499 public static HTML5VideoViewProxy getInstance(WebViewCore webViewCore, int nativePtr) {
500 return new HTML5VideoViewProxy(webViewCore.getWebView(), nativePtr);
Andrei Popescu6fa29582009-06-19 14:54:09 +0100501 }
Andrei Popescu290c34a2009-09-17 15:55:24 +0100502
503 private native void nativeOnPrepared(int duration, int width, int height, int nativePointer);
504 private native void nativeOnEnded(int nativePointer);
Andrei Popescu50c86232009-09-30 16:51:25 +0100505 private native void nativeOnPosterFetched(Bitmap poster, int nativePointer);
Andrei Popescu6fa29582009-06-19 14:54:09 +0100506}