Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 11438c37 authored by Grace Kloba's avatar Grace Kloba
Browse files

Implement the full screen WebView plugin.

Use a NoTitleBar_Fullscreen dialog to implement the
full screen plugin. This runs in the same thread as
WebView (UI in the Browser case). One catch is that
the SurfaceView provided by the plugin needs to be
opaque if it doesn't want to see through the WebView.

The PluginFullScreenHolder translates the events to
the underline WebView. Special treatment in the touch
case as it needs to translate the coordinates.

WebView can't be panned, or double tap to zoom, or
long press to trigger the context menu while having
a full screen plugin.

Inside webkit, we also give the plugin element focus
when it goes to the full screen so that it takes key
events. While handling key events, we don't let it 
loose focus or scroll out.

Todo:
When a plugin goes to full screen, we should make
sure the embedded plugin is fully visible. Otherwise
when we translate the touch events back, they will be
outside of the visible rect and will be ignored.

This is part 1 of 2-project check in.
parent 1cb97eed
Loading
Loading
Loading
Loading
+0 −39
Original line number Original line Diff line number Diff line
@@ -108,8 +108,6 @@ class CallbackProxy extends Handler {
    private static final int RECEIVED_TOUCH_ICON_URL             = 132;
    private static final int RECEIVED_TOUCH_ICON_URL             = 132;
    private static final int GET_VISITED_HISTORY                 = 133;
    private static final int GET_VISITED_HISTORY                 = 133;
    private static final int OPEN_FILE_CHOOSER                   = 134;
    private static final int OPEN_FILE_CHOOSER                   = 134;
    private static final int SHOW_CUSTOM_VIEW                    = 135;
    private static final int HIDE_CUSTOM_VIEW                    = 136;


    // Message triggered by the client to resume execution
    // Message triggered by the client to resume execution
    private static final int NOTIFY                              = 200;
    private static final int NOTIFY                              = 200;
@@ -681,23 +679,6 @@ class CallbackProxy extends Handler {
                    mWebChromeClient.openFileChooser((UploadFile) msg.obj);
                    mWebChromeClient.openFileChooser((UploadFile) msg.obj);
                }
                }
                break;
                break;

            case SHOW_CUSTOM_VIEW:
                if (mWebChromeClient != null) {
                    HashMap<String, Object> map =
                            (HashMap<String, Object>) msg.obj;
                    View view = (View) map.get("view");
                    WebChromeClient.CustomViewCallback callback =
                            (WebChromeClient.CustomViewCallback) map.get("callback");
                    mWebChromeClient.onShowCustomView(view, callback);
                }
                break;

            case HIDE_CUSTOM_VIEW:
                if (mWebChromeClient != null) {
                    mWebChromeClient.onHideCustomView();
                }
                break;
        }
        }
    }
    }


@@ -1404,24 +1385,4 @@ class CallbackProxy extends Handler {
        }
        }
        return uploadFile.getResult();
        return uploadFile.getResult();
    }
    }

    /* package */ void showCustomView(View view, WebChromeClient.CustomViewCallback callback) {
        if (mWebChromeClient == null) {
            return;
        }
        Message msg = obtainMessage(SHOW_CUSTOM_VIEW);
        HashMap<String, Object> map = new HashMap<String, Object>();
        map.put("view", view);
        map.put("callback", callback);
        msg.obj = map;
        sendMessage(msg);
    }

    /* package */ void hideCustomView() {
        if (mWebChromeClient == null) {
            return;
        }
        Message msg = obtainMessage(HIDE_CUSTOM_VIEW);
        sendMessage(msg);
    }
}
}
+120 −0
Original line number Original line Diff line number Diff line
@@ -22,14 +22,99 @@
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 */
package android.webkit.plugin;
package android.webkit;


/**
import android.app.Dialog;
 *
import android.graphics.Rect;
 * @hide pending API solidification
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;

class PluginFullScreenHolder extends Dialog {

    private static final String LOGTAG = "FullScreenHolder";

    private final WebView mWebView;
    private final int mNpp;
    private int mX;
    private int mY;
    private int mWidth;
    private int mHeight;

    PluginFullScreenHolder(WebView webView, int npp) {
        super(webView.getContext(), android.R.style.Theme_NoTitleBar_Fullscreen);
        mWebView = webView;
        mNpp = npp;
    }

    Rect getBound() {
        return new Rect(mX, mY, mWidth, mHeight);
    }

    /*
     * x, y, width, height are in the caller's view coordinate system. (x, y) is
     * relative to the top left corner of the caller's view.
     */
     */
public interface FullScreenDrawingModel extends SurfaceDrawingModel {
    void updateBound(int x, int y, int width, int height) {
        mX = x;
        mY = y;
        mWidth = width;
        mHeight = height;
    }

    @Override
    public void onBackPressed() {
        mWebView.mPrivateHandler.obtainMessage(WebView.HIDE_FULLSCREEN)
                .sendToTarget();
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (event.isSystem()) {
            return super.onKeyDown(keyCode, event);
        }
        mWebView.onKeyDown(keyCode, event);
        // always return true as we are the handler
        return true;
    }

    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        if (event.isSystem()) {
            return super.onKeyUp(keyCode, event);
        }
        mWebView.onKeyUp(keyCode, event);
        // always return true as we are the handler
        return true;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        final float x = event.getX();
        final float y = event.getY();
        // TODO: find a way to know when the dialog size changed so that we can
        // cache the ratio
        final View decorView = getWindow().getDecorView();
        event.setLocation(mX + x * mWidth / decorView.getWidth(),
                mY + y * mHeight / decorView.getHeight());
        mWebView.onTouchEvent(event);
        // always return true as we are the handler
        return true;
    }


    public void onSurfaceRemoved();
    @Override
    public boolean onTrackballEvent(MotionEvent event) {
        mWebView.onTrackballEvent(event);
        // always return true as we are the handler
        return true;
    }

    @Override
    protected void onStop() {
        super.onStop();
        mWebView.getWebViewCore().sendMessage(
                WebViewCore.EventHub.HIDE_FULLSCREEN, mNpp, 0);
    }


}
}
+54 −8
Original line number Original line Diff line number Diff line
@@ -301,6 +301,9 @@ public class WebView extends AbsoluteLayout
    // Used by WebViewCore to create child views.
    // Used by WebViewCore to create child views.
    /* package */ final ViewManager mViewManager;
    /* package */ final ViewManager mViewManager;


    // Used to display in full screen mode
    PluginFullScreenHolder mFullScreenHolder;

    /**
    /**
     * Position of the last touch event.
     * Position of the last touch event.
     */
     */
@@ -487,6 +490,8 @@ public class WebView extends AbsoluteLayout
    static final int INVAL_RECT_MSG_ID                  = 26;
    static final int INVAL_RECT_MSG_ID                  = 26;
    static final int REQUEST_KEYBOARD                   = 27;
    static final int REQUEST_KEYBOARD                   = 27;
    static final int DO_MOTION_UP                       = 28;
    static final int DO_MOTION_UP                       = 28;
    static final int SHOW_FULLSCREEN                    = 29;
    static final int HIDE_FULLSCREEN                    = 30;


    static final String[] HandlerDebugString = {
    static final String[] HandlerDebugString = {
        "REMEMBER_PASSWORD", //              = 1;
        "REMEMBER_PASSWORD", //              = 1;
@@ -516,7 +521,9 @@ public class WebView extends AbsoluteLayout
        "WEBCORE_NEED_TOUCH_EVENTS", //      = 25;
        "WEBCORE_NEED_TOUCH_EVENTS", //      = 25;
        "INVAL_RECT_MSG_ID", //              = 26;
        "INVAL_RECT_MSG_ID", //              = 26;
        "REQUEST_KEYBOARD", //               = 27;
        "REQUEST_KEYBOARD", //               = 27;
        "DO_MOTION_UP" //                    = 28;
        "DO_MOTION_UP", //                   = 28;
        "SHOW_FULLSCREEN", //                = 29;
        "HIDE_FULLSCREEN" //                 = 30;
    };
    };


    // If the site doesn't use the viewport meta tag to specify the viewport,
    // If the site doesn't use the viewport meta tag to specify the viewport,
@@ -3993,6 +4000,11 @@ public class WebView extends AbsoluteLayout
                            || mTouchMode == TOUCH_DOUBLE_TAP_MODE) {
                            || mTouchMode == TOUCH_DOUBLE_TAP_MODE) {
                        mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
                        mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
                    }
                    }
                    if (mFullScreenHolder != null) {
                        // in full screen mode, the WebView can't be panned.
                        mTouchMode = TOUCH_DONE_MODE;
                        break;
                    }


                    // if it starts nearly horizontal or vertical, enforce it
                    // if it starts nearly horizontal or vertical, enforce it
                    int ax = Math.abs(deltaX);
                    int ax = Math.abs(deltaX);
@@ -4147,7 +4159,7 @@ public class WebView extends AbsoluteLayout
                            ted.mX = viewToContentX((int) x + mScrollX);
                            ted.mX = viewToContentX((int) x + mScrollX);
                            ted.mY = viewToContentY((int) y + mScrollY);
                            ted.mY = viewToContentY((int) y + mScrollY);
                            mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
                            mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
                        } else {
                        } else if (mFullScreenHolder == null) {
                            doDoubleTap();
                            doDoubleTap();
                        }
                        }
                        break;
                        break;
@@ -4163,8 +4175,9 @@ public class WebView extends AbsoluteLayout
                        if ((deltaX * deltaX + deltaY * deltaY) > mTouchSlopSquare) {
                        if ((deltaX * deltaX + deltaY * deltaY) > mTouchSlopSquare) {
                            Log.w(LOGTAG, "Miss a drag as we are waiting for" +
                            Log.w(LOGTAG, "Miss a drag as we are waiting for" +
                                    " WebCore's response for touch down.");
                                    " WebCore's response for touch down.");
                            if (computeHorizontalScrollExtent() < computeHorizontalScrollRange()
                            if (mFullScreenHolder == null
                                    || computeVerticalScrollExtent() < computeVerticalScrollRange()) {
                                    && (computeHorizontalScrollExtent() < computeHorizontalScrollRange()
                                    || computeVerticalScrollExtent() < computeVerticalScrollRange())) {
                                // we will not rewrite drag code here, but we
                                // we will not rewrite drag code here, but we
                                // will try fling if it applies.
                                // will try fling if it applies.
                                WebViewCore.pauseUpdate(mWebViewCore);
                                WebViewCore.pauseUpdate(mWebViewCore);
@@ -5115,7 +5128,7 @@ public class WebView extends AbsoluteLayout
            // exclude INVAL_RECT_MSG_ID since it is frequently output
            // exclude INVAL_RECT_MSG_ID since it is frequently output
            if (DebugFlags.WEB_VIEW && msg.what != INVAL_RECT_MSG_ID) {
            if (DebugFlags.WEB_VIEW && msg.what != INVAL_RECT_MSG_ID) {
                Log.v(LOGTAG, msg.what < REMEMBER_PASSWORD || msg.what
                Log.v(LOGTAG, msg.what < REMEMBER_PASSWORD || msg.what
                        > DO_MOTION_UP ? Integer.toString(msg.what)
                        > HIDE_FULLSCREEN ? Integer.toString(msg.what)
                        : HandlerDebugString[msg.what - REMEMBER_PASSWORD]);
                        : HandlerDebugString[msg.what - REMEMBER_PASSWORD]);
            }
            }
            if (mWebViewCore == null) {
            if (mWebViewCore == null) {
@@ -5146,7 +5159,9 @@ public class WebView extends AbsoluteLayout
                        mPreventDoubleTap = false;
                        mPreventDoubleTap = false;
                    }
                    }
                    if (mTouchMode == TOUCH_INIT_MODE) {
                    if (mTouchMode == TOUCH_INIT_MODE) {
                        mTouchMode = TOUCH_SHORTPRESS_START_MODE;
                        mTouchMode = mFullScreenHolder == null
                                ? TOUCH_SHORTPRESS_START_MODE
                                        : TOUCH_SHORTPRESS_MODE;
                        updateSelection();
                        updateSelection();
                    } else if (mTouchMode == TOUCH_DOUBLE_TAP_MODE) {
                    } else if (mTouchMode == TOUCH_DOUBLE_TAP_MODE) {
                        mTouchMode = TOUCH_DONE_MODE;
                        mTouchMode = TOUCH_DONE_MODE;
@@ -5164,9 +5179,11 @@ public class WebView extends AbsoluteLayout
                        mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
                        mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
                    } else if (mPreventDrag == PREVENT_DRAG_NO) {
                    } else if (mPreventDrag == PREVENT_DRAG_NO) {
                        mTouchMode = TOUCH_DONE_MODE;
                        mTouchMode = TOUCH_DONE_MODE;
                        if (mFullScreenHolder == null) {
                            performLongClick();
                            performLongClick();
                            rebuildWebTextView();
                            rebuildWebTextView();
                        }
                        }
                    }
                    break;
                    break;
                }
                }
                case RELEASE_SINGLE_TAP: {
                case RELEASE_SINGLE_TAP: {
@@ -5466,6 +5483,35 @@ public class WebView extends AbsoluteLayout
                    doMotionUp(msg.arg1, msg.arg2, (Boolean) msg.obj);
                    doMotionUp(msg.arg1, msg.arg2, (Boolean) msg.obj);
                    break;
                    break;


                case SHOW_FULLSCREEN:
                    WebViewCore.PluginFullScreenData data
                            = (WebViewCore.PluginFullScreenData) msg.obj;
                    if (data.mNpp != 0 && data.mView != null) {
                        if (mFullScreenHolder != null) {
                            Log.w(LOGTAG,
                                    "Should not have another full screen.");
                            mFullScreenHolder.dismiss();
                        }
                        mFullScreenHolder = new PluginFullScreenHolder(
                                WebView.this, data.mNpp);
                        mFullScreenHolder.setContentView(data.mView);
                        mFullScreenHolder.setCancelable(false);
                        mFullScreenHolder.setCanceledOnTouchOutside(false);
                    }
                    mFullScreenHolder.updateBound(contentToViewX(data.mDocX)
                            - mScrollX, contentToViewY(data.mDocY) - mScrollY,
                            contentToViewDimension(data.mDocWidth),
                            contentToViewDimension(data.mDocHeight));
                    mFullScreenHolder.show();
                    break;

                case HIDE_FULLSCREEN:
                    if (mFullScreenHolder != null) {
                        mFullScreenHolder.dismiss();
                        mFullScreenHolder = null;
                    }
                    break;

                default:
                default:
                    super.handleMessage(msg);
                    super.handleMessage(msg);
                    break;
                    break;
+47 −15
Original line number Original line Diff line number Diff line
@@ -41,7 +41,6 @@ import android.view.KeyEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.SurfaceView;
import android.view.View;
import android.view.View;
import android.webkit.plugin.FullScreenDrawingModel;
import android.webkit.plugin.SurfaceDrawingModel;
import android.webkit.plugin.SurfaceDrawingModel;
import android.webkit.plugin.WebkitPlugin;
import android.webkit.plugin.WebkitPlugin;


@@ -737,6 +736,15 @@ final class WebViewCore {
        boolean mRemember;
        boolean mRemember;
    }
    }


    static class PluginFullScreenData {
        View mView;
        int mNpp;
        int mDocX;
        int mDocY;
        int mDocWidth;
        int mDocHeight;
    }

        static final String[] HandlerDebugString = {
        static final String[] HandlerDebugString = {
            "UPDATE_FRAME_CACHE_IF_LOADING", // = 98
            "UPDATE_FRAME_CACHE_IF_LOADING", // = 98
            "SCROLL_TEXT_INPUT", // = 99
            "SCROLL_TEXT_INPUT", // = 99
@@ -870,6 +878,8 @@ final class WebViewCore {


        static final int POPULATE_VISITED_LINKS = 181;
        static final int POPULATE_VISITED_LINKS = 181;


        static final int HIDE_FULLSCREEN = 182;

        // private message ids
        // private message ids
        private static final int DESTROY =     200;
        private static final int DESTROY =     200;


@@ -1313,6 +1323,10 @@ final class WebViewCore {
                                    message);
                                    message);
                            break;
                            break;
                        }
                        }

                        case HIDE_FULLSCREEN:
                            nativeFullScreenPluginHidden(msg.arg1);
                            break;
                    }
                    }
                }
                }
            };
            };
@@ -2236,35 +2250,53 @@ final class WebViewCore {


    // called by JNI. PluginWidget function to launch a full-screen view using a
    // called by JNI. PluginWidget function to launch a full-screen view using a
    // View object provided by the plugin class.
    // View object provided by the plugin class.
    private void showFullScreenPlugin(WebkitPlugin webkitPlugin, final int npp) {
    private void showFullScreenPlugin(WebkitPlugin webkitPlugin, final int npp,
            int x, int y, int width, int height) {
        if (mWebView == null) {
        if (mWebView == null) {
            return;
            return;
        }
        }


        final FullScreenDrawingModel surface = webkitPlugin.getFullScreenSurface();
        final SurfaceDrawingModel surface = webkitPlugin.getFullScreenSurface();
        if(surface == null) {
        if(surface == null) {
            Log.e(LOGTAG, "Attempted to create an full-screen surface with a null drawing model");
            Log.e(LOGTAG, "Attempted to create an full-screen surface with a " +
                    "null drawing model");
            return;
            return;
        }
        }


        WebChromeClient.CustomViewCallback callback = new WebChromeClient.CustomViewCallback() {
        PluginFullScreenData data = new PluginFullScreenData();
            public void onCustomViewHidden() {
        data.mView = surface.getSurface();
                if (surface != null) {
        data.mNpp = npp;
                    surface.onSurfaceRemoved();
        data.mDocX = x;
                    nativeFullScreenPluginHidden(npp);
        data.mDocY = y;
                }
        data.mDocWidth = width;
        data.mDocHeight = height;
        mWebView.mPrivateHandler.obtainMessage(WebView.SHOW_FULLSCREEN, data)
                .sendToTarget();
    }
    }
        };


        mCallbackProxy.showCustomView(surface.getSurface(), callback);
    // called by JNI
    private void hideFullScreenPlugin() {
        if (mWebView == null) {
            return;
        }
        mWebView.mPrivateHandler.obtainMessage(WebView.HIDE_FULLSCREEN)
                .sendToTarget();
    }
    }


    private void hideFullScreenPlugin() {
    // called by JNI
    private void updateFullScreenPlugin(int x, int y, int width, int height) {
        if (mWebView == null) {
        if (mWebView == null) {
            return;
            return;
        }
        }


        mCallbackProxy.hideCustomView();
        PluginFullScreenData data = new PluginFullScreenData();
        data.mDocX = x;
        data.mDocY = y;
        data.mDocWidth = width;
        data.mDocHeight = height;
        // null mView and mNpp to indicate it is an update
        mWebView.mPrivateHandler.obtainMessage(WebView.SHOW_FULLSCREEN, data)
                .sendToTarget();
    }
    }


    // called by JNI.  PluginWidget functions for creating an embedded View for
    // called by JNI.  PluginWidget functions for creating an embedded View for
+2 −2
Original line number Original line Diff line number Diff line
@@ -31,6 +31,6 @@ package android.webkit.plugin;
public interface WebkitPlugin {
public interface WebkitPlugin {


    SurfaceDrawingModel getEmbeddedSurface();
    SurfaceDrawingModel getEmbeddedSurface();
    FullScreenDrawingModel getFullScreenSurface();
    SurfaceDrawingModel getFullScreenSurface();


}
}
Loading