root/content/public/android/java/src/org/chromium/content/browser/ContentView.java

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. newInstance
  2. newInstance
  3. newInstance
  4. getUrl
  5. getTitle
  6. getBackgroundColor
  7. getView
  8. getContentViewCore
  9. getRenderCoordinates
  10. destroy
  11. isAlive
  12. setContentViewClient
  13. getContentViewClient
  14. loadUrl
  15. canGoBack
  16. canGoForward
  17. goBack
  18. goForward
  19. fling
  20. evaluateJavaScript
  21. onShow
  22. onHide
  23. hideSelectActionBar
  24. drawChild
  25. onScrollChanged
  26. onSizeChanged
  27. onLayout
  28. onCreateInputConnection
  29. onCheckIsTextEditor
  30. onFocusChanged
  31. onWindowFocusChanged
  32. onKeyUp
  33. dispatchKeyEventPreIme
  34. dispatchKeyEvent
  35. onTouchEvent
  36. onHoverEvent
  37. onGenericMotionEvent
  38. performLongClick
  39. setCurrentMotionEventOffsets
  40. createOffsetMotionEvent
  41. onConfigurationChanged
  42. scrollBy
  43. scrollTo
  44. computeHorizontalScrollExtent
  45. computeHorizontalScrollOffset
  46. computeHorizontalScrollRange
  47. computeVerticalScrollExtent
  48. computeVerticalScrollOffset
  49. computeVerticalScrollRange
  50. awakenScrollBars
  51. awakenScrollBars
  52. getSingleTapX
  53. getSingleTapY
  54. onInitializeAccessibilityNodeInfo
  55. onInitializeAccessibilityEvent
  56. onAttachedToWindow
  57. onDetachedFromWindow
  58. onVisibilityChanged
  59. getScale
  60. setAccessibilityState
  61. exitFullscreen
  62. getContentScrollY
  63. getContentHeight
  64. super_onKeyUp
  65. super_dispatchKeyEventPreIme
  66. super_dispatchKeyEvent
  67. super_onGenericMotionEvent
  68. super_onConfigurationChanged
  69. super_awakenScrollBars

// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.content.browser;

import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.os.Build;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.widget.FrameLayout;

import com.google.common.annotations.VisibleForTesting;

import org.chromium.base.TraceEvent;
import org.chromium.ui.base.WindowAndroid;

/**
 * The containing view for {@link ContentViewCore} that exists in the Android UI hierarchy and
 * exposes the various {@link View} functionality to it.
 *
 * TODO(joth): Remove any methods overrides from this class that were added for WebView
 *             compatibility.
 */
public class ContentView extends FrameLayout
        implements ContentViewCore.InternalAccessDelegate, PageInfo {

    private final ContentViewCore mContentViewCore;

    private float mCurrentTouchOffsetX;
    private float mCurrentTouchOffsetY;
    private final int[] mLocationInWindow = new int[2];

    /**
     * Creates an instance of a ContentView.
     * @param context The Context the view is running in, through which it can
     *                access the current theme, resources, etc.
     * @param nativeWebContents A pointer to the native web contents.
     * @param windowAndroid An instance of the WindowAndroid.
     * @return A ContentView instance.
     */
    public static ContentView newInstance(Context context, long nativeWebContents,
            WindowAndroid windowAndroid) {
        return newInstance(context, nativeWebContents, windowAndroid, null,
                android.R.attr.webViewStyle);
    }

    /**
     * Creates an instance of a ContentView.
     * @param context The Context the view is running in, through which it can
     *                access the current theme, resources, etc.
     * @param nativeWebContents A pointer to the native web contents.
     * @param windowAndroid An instance of the WindowAndroid.
     * @param attrs The attributes of the XML tag that is inflating the view.
     * @return A ContentView instance.
     */
    public static ContentView newInstance(Context context, long nativeWebContents,
            WindowAndroid windowAndroid, AttributeSet attrs) {
        // TODO(klobag): use the WebViewStyle as the default style for now. It enables scrollbar.
        // When ContentView is moved to framework, we can define its own style in the res.
        return newInstance(context, nativeWebContents, windowAndroid, attrs,
                android.R.attr.webViewStyle);
    }

    /**
     * Creates an instance of a ContentView.
     * @param context The Context the view is running in, through which it can
     *                access the current theme, resources, etc.
     * @param nativeWebContents A pointer to the native web contents.
     * @param windowAndroid An instance of the WindowAndroid.
     * @param attrs The attributes of the XML tag that is inflating the view.
     * @param defStyle The default style to apply to this view.
     * @return A ContentView instance.
     */
    public static ContentView newInstance(Context context, long nativeWebContents,
            WindowAndroid windowAndroid, AttributeSet attrs, int defStyle) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
            return new ContentView(context, nativeWebContents, windowAndroid, attrs, defStyle);
        } else {
            return new JellyBeanContentView(context, nativeWebContents, windowAndroid, attrs,
                    defStyle);
        }
    }

    protected ContentView(Context context, long nativeWebContents, WindowAndroid windowAndroid,
            AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        if (getScrollBarStyle() == View.SCROLLBARS_INSIDE_OVERLAY) {
            setHorizontalScrollBarEnabled(false);
            setVerticalScrollBarEnabled(false);
        }

        setFocusable(true);
        setFocusableInTouchMode(true);

        mContentViewCore = new ContentViewCore(context);
        mContentViewCore.initialize(this, this, nativeWebContents, windowAndroid);
    }

    /**
     * @return The URL of the page.
     */
    public String getUrl() {
        return mContentViewCore.getUrl();
    }

    // PageInfo implementation.

    @Override
    public String getTitle() {
        return mContentViewCore.getTitle();
    }

    @Override
    public int getBackgroundColor() {
        return mContentViewCore.getBackgroundColor();
    }

    @Override
    public View getView() {
        return this;
    }

    /**
     * @return The core component of the ContentView that handles JNI communication.  Should only be
     *         used for passing to native.
     */
    public ContentViewCore getContentViewCore() {
        return mContentViewCore;
    }

    /**
     * @return The cache of scales and positions used to convert coordinates from/to CSS.
     */
    public RenderCoordinates getRenderCoordinates() {
        return mContentViewCore.getRenderCoordinates();
    }

    /**
     * Destroy the internal state of the WebView. This method may only be called
     * after the WebView has been removed from the view system. No other methods
     * may be called on this WebView after this method has been called.
     */
    public void destroy() {
        mContentViewCore.destroy();
    }

    /**
     * Returns true initially, false after destroy() has been called.
     * It is illegal to call any other public method after destroy().
     */
    public boolean isAlive() {
        return mContentViewCore.isAlive();
    }

    public void setContentViewClient(ContentViewClient client) {
        mContentViewCore.setContentViewClient(client);
    }

    @VisibleForTesting
    public ContentViewClient getContentViewClient() {
        return mContentViewCore.getContentViewClient();
    }

    /**
     * Load url without fixing up the url string. Consumers of ContentView are responsible for
     * ensuring the URL passed in is properly formatted (i.e. the scheme has been added if left
     * off during user input).
     *
     * @param params Parameters for this load.
     */
    public void loadUrl(LoadUrlParams params) {
        mContentViewCore.loadUrl(params);
    }

    /**
     * @return Whether the current WebContents has a previous navigation entry.
     */
    public boolean canGoBack() {
        return mContentViewCore.canGoBack();
    }

    /**
     * @return Whether the current WebContents has a navigation entry after the current one.
     */
    public boolean canGoForward() {
        return mContentViewCore.canGoForward();
    }

    /**
     * Goes to the navigation entry before the current one.
     */
    public void goBack() {
        mContentViewCore.goBack();
    }

    /**
     * Goes to the navigation entry following the current one.
     */
    public void goForward() {
        mContentViewCore.goForward();
    }

    /**
     * Fling the ContentView from the current position.
     * @param x Fling touch starting position
     * @param y Fling touch starting position
     * @param velocityX Initial velocity of the fling (X) measured in pixels per second.
     * @param velocityY Initial velocity of the fling (Y) measured in pixels per second.
     */
    @VisibleForTesting
    public void fling(long timeMs, int x, int y, int velocityX, int velocityY) {
        mContentViewCore.flingForTest(timeMs, x, y, velocityX, velocityY);
    }

    /**
     * Injects the passed JavaScript code in the current page and evaluates it.
     *
     * @throws IllegalStateException If the ContentView has been destroyed.
     */
    public void evaluateJavaScript(String script) throws IllegalStateException {
        mContentViewCore.evaluateJavaScript(script, null);
    }

    /**
     * To be called when the ContentView is shown.
     **/
    public void onShow() {
        mContentViewCore.onShow();
    }

    /**
     * To be called when the ContentView is hidden.
     **/
    public void onHide() {
        mContentViewCore.onHide();
    }

    /**
     * Hides the select action bar.
     */
    public void hideSelectActionBar() {
        mContentViewCore.hideSelectActionBar();
    }

    // FrameLayout overrides.

    // Needed by ContentViewCore.InternalAccessDelegate
    @Override
    public boolean drawChild(Canvas canvas, View child, long drawingTime) {
        return super.drawChild(canvas, child, drawingTime);
    }

    // Needed by ContentViewCore.InternalAccessDelegate
    @Override
    public void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
    }

    @Override
    protected void onSizeChanged(int w, int h, int ow, int oh) {
        TraceEvent.begin();
        super.onSizeChanged(w, h, ow, oh);
        mContentViewCore.onSizeChanged(w, h, ow, oh);
        TraceEvent.end();
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        if (changed) {
            getLocationInWindow(mLocationInWindow);
            mContentViewCore.onLocationInWindowChanged(mLocationInWindow[0], mLocationInWindow[1]);
        }
    }

    @Override
    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
        return mContentViewCore.onCreateInputConnection(outAttrs);
    }

    @Override
    public boolean onCheckIsTextEditor() {
        return mContentViewCore.onCheckIsTextEditor();
    }

    @Override
    protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
        TraceEvent.begin();
        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
        mContentViewCore.onFocusChanged(gainFocus);
        TraceEvent.end();
    }

    @Override
    public void onWindowFocusChanged(boolean hasWindowFocus) {
        super.onWindowFocusChanged(hasWindowFocus);
        mContentViewCore.onWindowFocusChanged(hasWindowFocus);
    }

    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        return mContentViewCore.onKeyUp(keyCode, event);
    }

    @Override
    public boolean dispatchKeyEventPreIme(KeyEvent event) {
        return mContentViewCore.dispatchKeyEventPreIme(event);
    }

    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        if (isFocused()) {
            return mContentViewCore.dispatchKeyEvent(event);
        } else {
            return super.dispatchKeyEvent(event);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        MotionEvent offset = createOffsetMotionEvent(event);
        boolean consumed = mContentViewCore.onTouchEvent(offset);
        offset.recycle();
        return consumed;
    }

    /**
     * Mouse move events are sent on hover enter, hover move and hover exit.
     * They are sent on hover exit because sometimes it acts as both a hover
     * move and hover exit.
     */
    @Override
    public boolean onHoverEvent(MotionEvent event) {
        MotionEvent offset = createOffsetMotionEvent(event);
        boolean consumed = mContentViewCore.onHoverEvent(offset);
        offset.recycle();
        super.onHoverEvent(event);
        return consumed;
    }

    @Override
    public boolean onGenericMotionEvent(MotionEvent event) {
        return mContentViewCore.onGenericMotionEvent(event);
    }

    @Override
    public boolean performLongClick() {
        return false;
    }

    /**
     * Sets the current amount to offset incoming touch events by.  This is used to handle content
     * moving and not lining up properly with the android input system.
     * @param dx The X offset in pixels to shift touch events.
     * @param dy The Y offset in pixels to shift touch events.
     */
    public void setCurrentMotionEventOffsets(float dx, float dy) {
        mCurrentTouchOffsetX = dx;
        mCurrentTouchOffsetY = dy;
    }

    private MotionEvent createOffsetMotionEvent(MotionEvent src) {
        MotionEvent dst = MotionEvent.obtain(src);
        dst.offsetLocation(mCurrentTouchOffsetX, mCurrentTouchOffsetY);
        return dst;
    }

    @Override
    protected void onConfigurationChanged(Configuration newConfig) {
        mContentViewCore.onConfigurationChanged(newConfig);
    }

    /**
     * Currently the ContentView scrolling happens in the native side. In
     * the Java view system, it is always pinned at (0, 0). scrollBy() and scrollTo()
     * are overridden, so that View's mScrollX and mScrollY will be unchanged at
     * (0, 0). This is critical for drawing ContentView correctly.
     */
    @Override
    public void scrollBy(int x, int y) {
        mContentViewCore.scrollBy(x, y);
    }

    @Override
    public void scrollTo(int x, int y) {
        mContentViewCore.scrollTo(x, y);
    }

    @Override
    protected int computeHorizontalScrollExtent() {
        // TODO(dtrainor): Need to expose scroll events properly to public. Either make getScroll*
        // work or expose computeHorizontalScrollOffset()/computeVerticalScrollOffset as public.
        return mContentViewCore.computeHorizontalScrollExtent();
    }

    @Override
    protected int computeHorizontalScrollOffset() {
        return mContentViewCore.computeHorizontalScrollOffset();
    }

    @Override
    protected int computeHorizontalScrollRange() {
        return mContentViewCore.computeHorizontalScrollRange();
    }

    @Override
    protected int computeVerticalScrollExtent() {
        return mContentViewCore.computeVerticalScrollExtent();
    }

    @Override
    protected int computeVerticalScrollOffset() {
        return mContentViewCore.computeVerticalScrollOffset();
    }

    @Override
    protected int computeVerticalScrollRange() {
        return mContentViewCore.computeVerticalScrollRange();
    }

    // End FrameLayout overrides.

    @Override
    public boolean awakenScrollBars(int startDelay, boolean invalidate) {
        return mContentViewCore.awakenScrollBars(startDelay, invalidate);
    }

    @Override
    public boolean awakenScrollBars() {
        return super.awakenScrollBars();
    }

    public int getSingleTapX()  {
        return mContentViewCore.getSingleTapX();
    }

    public int getSingleTapY()  {
        return mContentViewCore.getSingleTapY();
    }

    @Override
    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
        super.onInitializeAccessibilityNodeInfo(info);
        mContentViewCore.onInitializeAccessibilityNodeInfo(info);
    }

    /**
     * Fills in scrolling values for AccessibilityEvents.
     * @param event Event being fired.
     */
    @Override
    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
        super.onInitializeAccessibilityEvent(event);
        mContentViewCore.onInitializeAccessibilityEvent(event);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        mContentViewCore.onAttachedToWindow();
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        mContentViewCore.onDetachedFromWindow();
    }

    @Override
    protected void onVisibilityChanged(View changedView, int visibility) {
        super.onVisibilityChanged(changedView, visibility);
        mContentViewCore.onVisibilityChanged(changedView, visibility);
    }

    /**
     * Return the current scale of the WebView
     * @return The current scale.
     */
    public float getScale() {
        return mContentViewCore.getScale();
    }

    /**
     * Enable or disable accessibility features.
     */
    public void setAccessibilityState(boolean state) {
        mContentViewCore.setAccessibilityState(state);
    }

    /**
     * Inform WebKit that Fullscreen mode has been exited by the user.
     */
    public void exitFullscreen() {
        mContentViewCore.exitFullscreen();
    }

    /**
     * Return content scroll y.
     *
     * @return The vertical scroll position in pixels.
     */
    public int getContentScrollY() {
        return mContentViewCore.computeVerticalScrollOffset();
    }

    /**
     * Return content height.
     *
     * @return The height of the content in pixels.
     */
    public int getContentHeight() {
        return mContentViewCore.computeVerticalScrollRange();
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////
    //              Start Implementation of ContentViewCore.InternalAccessDelegate               //
    ///////////////////////////////////////////////////////////////////////////////////////////////

    @Override
    public boolean super_onKeyUp(int keyCode, KeyEvent event) {
        return super.onKeyUp(keyCode, event);
    }

    @Override
    public boolean super_dispatchKeyEventPreIme(KeyEvent event) {
        return super.dispatchKeyEventPreIme(event);
    }

    @Override
    public boolean super_dispatchKeyEvent(KeyEvent event) {
        return super.dispatchKeyEvent(event);
    }

    @Override
    public boolean super_onGenericMotionEvent(MotionEvent event) {
        return super.onGenericMotionEvent(event);
    }

    @Override
    public void super_onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
    }

    @Override
    public boolean super_awakenScrollBars(int startDelay, boolean invalidate) {
        return super.awakenScrollBars(startDelay, invalidate);
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////
    //                End Implementation of ContentViewCore.InternalAccessDelegate               //
    ///////////////////////////////////////////////////////////////////////////////////////////////
}

/* [<][>][^][v][top][bottom][index][help] */