Merge change 6356

* changes:
  Add fullscreen support back in.
diff --git a/core/java/android/webkit/HTML5VideoViewProxy.java b/core/java/android/webkit/HTML5VideoViewProxy.java
index 5b2c0e2..5a164f8 100644
--- a/core/java/android/webkit/HTML5VideoViewProxy.java
+++ b/core/java/android/webkit/HTML5VideoViewProxy.java
@@ -17,49 +17,148 @@
 package android.webkit;
 
 import android.content.Context;
+import android.media.MediaPlayer;
+import android.media.MediaPlayer.OnPreparedListener;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.util.Log;
+import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewGroup;
 import android.webkit.ViewManager.ChildView;
+import android.widget.AbsoluteLayout;
 import android.widget.MediaController;
 import android.widget.VideoView;
 
 import java.util.HashMap;
 
 /**
- * <p>A View that displays Videos. Instances of this class
- * are created on the WebCore thread. However, their code
- * executes on the UI thread. Right now there is only one
- * such view for fullscreen video rendering.
- *
+ * <p>Proxy for HTML5 video views.
  */
 class HTML5VideoViewProxy extends Handler {
     // Logging tag.
     private static final String LOGTAG = "HTML5VideoViewProxy";
 
-    // Message Ids
+    // Message Ids for WebCore thread -> UI thread communication.
     private static final int INIT              = 100;
     private static final int PLAY              = 101;
 
-    // The singleton instance.
-    private static HTML5VideoViewProxy sInstance;
-    // The context object used to initialize the VideoView and the
-    // MediaController.
-    private Context mContext;
+    // The WebView instance that created this view.
+    private WebView mWebView;
+    // The ChildView instance used by the ViewManager.
+    private ChildView mChildView;
+    // The VideoView instance. Note that we could
+    // also access this via mChildView.mView but it would
+    // always require cast, so it is more convenient to store
+    // it here as well.
+    private HTML5VideoView mVideoView;
+
+    // A VideoView subclass that responds to double-tap
+    // events by going fullscreen.
+    class HTML5VideoView extends VideoView {
+        // Used to save the layout parameters if the view
+        // is changed to fullscreen.
+        private AbsoluteLayout.LayoutParams mEmbeddedLayoutParams;
+        // Flag that denotes whether the view is fullscreen or not.
+        private boolean mIsFullscreen;
+        // Used to save the current playback position when
+        // transitioning to/from fullscreen.
+        private int mPlaybackPosition;
+        // The callback object passed to the host application. This callback
+        // is invoked when the host application dismisses our VideoView
+        // (e.g. the user presses the back key).
+        private WebChromeClient.CustomViewCallback mCallback =
+                new WebChromeClient.CustomViewCallback() {
+            public void onCustomViewHidden() {
+                playEmbedded();
+            }
+        };
+
+        // The OnPreparedListener, used to automatically resume
+        // playback when transitioning to/from fullscreen.
+        private MediaPlayer.OnPreparedListener mPreparedListener =
+                new MediaPlayer.OnPreparedListener() {
+            public void onPrepared(MediaPlayer mp) {
+                resumePlayback();
+            }
+        };
+
+        HTML5VideoView(Context context) {
+            super(context);
+        }
+
+        void savePlaybackPosition() {
+            if (isPlaying()) {
+                mPlaybackPosition = getCurrentPosition();
+            }
+        }
+
+        void resumePlayback() {
+            seekTo(mPlaybackPosition);
+            start();
+            setOnPreparedListener(null);
+        }
+
+        void playEmbedded() {
+            // Attach to the WebView.
+            mChildView.attachViewOnUIThread(mEmbeddedLayoutParams);
+            // Make sure we're visible
+            setVisibility(View.VISIBLE);
+            // Set the onPrepared listener so we start
+            // playing when the video view is reattached
+            // and its surface is recreated.
+            setOnPreparedListener(mPreparedListener);
+            mIsFullscreen = false;
+        }
+
+        void playFullScreen() {
+            WebChromeClient client = mWebView.getWebChromeClient();
+            if (client == null) {
+                return;
+            }
+            // Save the current layout params.
+            mEmbeddedLayoutParams =
+                    (AbsoluteLayout.LayoutParams) getLayoutParams();
+            // Detach from the WebView.
+            mChildView.removeViewOnUIThread();
+            // Attach to the browser UI.
+            client.onShowCustomView(this, mCallback);
+            // Set the onPrepared listener so we start
+            // playing when after the video view is reattached
+            // and its surface is recreated.
+            setOnPreparedListener(mPreparedListener);
+            mIsFullscreen = true;
+        }
+
+        @Override
+        public boolean onTouchEvent(MotionEvent ev) {
+            // TODO: implement properly (i.e. detect double tap)
+            if (mIsFullscreen || !isPlaying()) {
+                return super.onTouchEvent(ev);
+            }
+            playFullScreen();
+            return true;
+        }
+
+        @Override
+        public void onDetachedFromWindow() {
+            super.onDetachedFromWindow();
+            savePlaybackPosition();
+        }
+    }
 
     /**
      * Private constructor.
      * @param context is the application context.
      */
-    private HTML5VideoViewProxy(Context context) {
+    private HTML5VideoViewProxy(WebView webView) {
         // This handler is for the main (UI) thread.
         super(Looper.getMainLooper());
-        // Save the context object.
-        mContext = context;
+        // Save the WebView object.
+        mWebView = webView;
     }
 
     @Override
@@ -67,22 +166,23 @@
         // This executes on the UI thread.
         switch (msg.what) {
             case INIT:
-                ChildView child = (ChildView) msg.obj;
                 // Create the video view and set a default controller.
-                VideoView v = new VideoView(mContext);
+                mVideoView = new HTML5VideoView(mWebView.getContext());
                 // This is needed because otherwise there will be a black square
                 // stuck on the screen.
-                v.setWillNotDraw(false);
-                v.setMediaController(new MediaController(mContext));
-                child.mView = v;
+                mVideoView.setWillNotDraw(false);
+                mVideoView.setMediaController(new MediaController(mWebView.getContext()));
+                mChildView.mView = mVideoView;
                 break;
             case PLAY:
+                if (mVideoView == null) {
+                    return;
+                }
                 HashMap<String, Object> map =
                         (HashMap<String, Object>) msg.obj;
                 String url = (String) map.get("url");
-                VideoView view = (VideoView) map.get("view");
-                view.setVideoURI(Uri.parse(url));
-                view.start();
+                mVideoView.setVideoURI(Uri.parse(url));
+                mVideoView.start();
                 break;
         }
     }
@@ -92,46 +192,41 @@
      * @param url is the URL of the video stream.
      * @param webview is the WebViewCore that is requesting the playback.
      */
-    public void play(String url, ChildView child) {
-        // We need to know the webview that is requesting the playback.
+    public void play(String url) {
+         // We need to know the webview that is requesting the playback.
         Message message = obtainMessage(PLAY);
         HashMap<String, Object> map = new HashMap();
         map.put("url", url);
-        map.put("view", child.mView);
         message.obj = map;
         sendMessage(message);
     }
 
-    public ChildView createView(WebViewCore core) {
-        WebView w = core.getWebView();
-        if (w == null) {
-            return null;
+    public void createView() {
+        mChildView = mWebView.mViewManager.createView();
+        sendMessage(obtainMessage(INIT));
+    }
+
+    public void attachView(int x, int y, int width, int height) {
+        if (mChildView == null) {
+            return;
         }
-        ChildView child = w.mViewManager.createView();
-        sendMessage(obtainMessage(INIT, child));
-        return child;
+        mChildView.attachView(x, y, width, height);
     }
 
-    public void attachView(ChildView child, int x, int y, int width,
-            int height) {
-        child.attachView(x, y, width, height);
-    }
-
-    public void removeView(ChildView child) {
-        child.removeView();
+    public void removeView() {
+        if (mChildView == null) {
+            return;
+        }
+        mChildView.removeView();
     }
 
     /**
-     * The factory for HTML5VideoViewProxy instances. Right now,
-     * it only produces a singleton.
+     * The factory for HTML5VideoViewProxy instances.
      * @param webViewCore is the WebViewCore that is requesting the proxy.
      *
-     * @return the HTML5VideoViewProxy singleton.
+     * @return a new HTML5VideoViewProxy object.
      */
     public static HTML5VideoViewProxy getInstance(WebViewCore webViewCore) {
-        if (sInstance == null) {
-            sInstance = new HTML5VideoViewProxy(webViewCore.getWebView().getContext());
-        }
-        return sInstance;
+        return new HTML5VideoViewProxy(webViewCore.getWebView());
     }
 }
diff --git a/core/java/android/webkit/ViewManager.java b/core/java/android/webkit/ViewManager.java
index 476e85c..af33b4f 100644
--- a/core/java/android/webkit/ViewManager.java
+++ b/core/java/android/webkit/ViewManager.java
@@ -61,24 +61,32 @@
                     if (mView.getParent() != null) {
                         mView.setLayoutParams(lp);
                     } else {
-                        mWebView.addView(mView, lp);
-                        mChildren.add(ChildView.this);
+                        attachViewOnUIThread(lp);
                     }
                 }
             });
         }
 
+        void attachViewOnUIThread(AbsoluteLayout.LayoutParams lp) {
+            mWebView.addView(mView, lp);
+            mChildren.add(this);
+        }
+
         void removeView() {
             if (mView == null) {
                 return;
             }
             mWebView.mPrivateHandler.post(new Runnable() {
                 public void run() {
-                    mWebView.removeView(mView);
-                    mChildren.remove(ChildView.this);
+                    removeViewOnUIThread();
                 }
             });
         }
+
+        void removeViewOnUIThread() {
+            mWebView.removeView(mView);
+            mChildren.remove(this);
+        }
     }
 
     ViewManager(WebView w) {
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 19e39ed..dd43b8b 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -45,13 +45,29 @@
     public void onReceivedIcon(WebView view, Bitmap icon) {}
 
     /**
-     * Notify the host application that the current page would
-     * like to show a custom View.
-     * @param view is the View object to be shown.
+     * A callback interface used by the host application to notify
+     * the current page that its custom view has been dismissed.
      *
      * @hide pending council approval
      */
-    public void onShowCustomView(View view) {}
+    public interface CustomViewCallback {
+        /**
+         * Invoked when the host application dismisses the
+         * custom view.
+         */
+        public void onCustomViewHidden();
+    }
+
+    /**
+     * Notify the host application that the current page would
+     * like to show a custom View.
+     * @param view is the View object to be shown.
+     * @param callback is the callback to be invoked if and when the view
+     * is dismissed.
+     *
+     * @hide pending council approval
+     */
+    public void onShowCustomView(View view, CustomViewCallback callback) {};
 
     /**
      * Notify the host application that the current page would