FileDocCategorySizeDatePackage
BrowserFrame.javaAPI DocAndroid 1.5 API28906Wed May 06 22:41:56 BST 2009android.webkit

BrowserFrame

public class BrowserFrame extends android.os.Handler

Fields Summary
private static final String
LOGTAG
private static final int
MAX_OUTSTANDING_REQUESTS
Cap the number of LoadListeners that will be instantiated, so we don't blow the GREF count. Attempting to queue more than this many requests will prompt an error() callback on the request's LoadListener
private final CallbackProxy
mCallbackProxy
private final WebSettings
mSettings
private final android.content.Context
mContext
private final WebViewDatabase
mDatabase
private final WebViewCore
mWebViewCore
boolean
mLoadInitFromJava
private int
mLoadType
private boolean
mFirstLayoutDone
private boolean
mCommitted
private boolean
mIsMainFrame
private HashMap
mJSInterfaceMap
static final int
FRAME_COMPLETED
static final int
POLICY_FUNCTION
static final int
FRAME_LOADTYPE_STANDARD
static final int
FRAME_LOADTYPE_BACK
static final int
FRAME_LOADTYPE_FORWARD
static final int
FRAME_LOADTYPE_INDEXEDBACKFORWARD
static final int
FRAME_LOADTYPE_RELOAD
static final int
FRAME_LOADTYPE_RELOADALLOWINGSTALEDATA
static final int
FRAME_LOADTYPE_SAME
static final int
FRAME_LOADTYPE_REDIRECT
static final int
FRAME_LOADTYPE_REPLACE
private static final int
TRANSITION_SWITCH_THRESHOLD
int
mNativeFrame
static JWebCoreJavaBridge
sJavaBridge
static final int
POLICY_USE
static final int
POLICY_IGNORE
private static final int
NODOMAIN
private static final int
LOADERROR
Constructors Summary
public BrowserFrame(android.content.Context context, WebViewCore w, CallbackProxy proxy, WebSettings settings)
Create a new BrowserFrame to be used in an application.

param
context An application context to use when retrieving assets.
param
w A WebViewCore used as the view for this frame.
param
proxy A CallbackProxy for posting messages to the UI thread and querying a client for information.
param
settings A WebSettings object that holds all settings. XXX: Called by WebCore thread.


                                                                                    
          
              
        // Create a global JWebCoreJavaBridge to handle timers and
        // cookies in the WebCore thread.
        if (sJavaBridge == null) {
            sJavaBridge = new JWebCoreJavaBridge();
            // set WebCore native cache size
            sJavaBridge.setCacheSize(4 * 1024 * 1024);
            // initialize CacheManager
            CacheManager.init(context);
            // create CookieSyncManager with current Context
            CookieSyncManager.createInstance(context);
        }
        AssetManager am = context.getAssets();
        nativeCreateFrame(w, am, proxy.getBackForwardList());

        mSettings = settings;
        mContext = context;
        mCallbackProxy = proxy;
        mDatabase = WebViewDatabase.getInstance(context);
        mWebViewCore = w;

        if (Config.LOGV) {
            Log.v(LOGTAG, "BrowserFrame constructor: this=" + this);
        }
    
Methods Summary
public voidaddJavascriptInterface(java.lang.Object obj, java.lang.String interfaceName)

        if (mJSInterfaceMap == null) {
            mJSInterfaceMap = new HashMap<String, Object>();
        }
        if (mJSInterfaceMap.containsKey(interfaceName)) {
            mJSInterfaceMap.remove(interfaceName);
        }
        mJSInterfaceMap.put(interfaceName, obj);
    
public native booleancacheDisabled()

voidcertificate(android.net.http.SslCertificate certificate)
We have received an SSL certificate for the main top-level page. !!!Called from the network thread!!!

        if (mIsMainFrame) {
            // we want to make this call even if the certificate is null
            // (ie, the site is not secure)
            mCallbackProxy.onReceivedCertificate(certificate);
        }
    
public native voidclearCache()

private voidcloseWindow(WebViewCore w)
Close this frame and window.

        mCallbackProxy.onCloseWindow(w.getWebView());
    
booleancommitted()

        return mCommitted;
    
private android.webkit.BrowserFramecreateWindow(boolean dialog, boolean userGesture)
Request a new window from the client.

return
The BrowserFrame object stored in the new WebView.

        WebView w = mCallbackProxy.createWindow(dialog, userGesture);
        if (w != null) {
            return w.getWebViewCore().getBrowserFrame();
        }
        return null;
    
private voiddecidePolicyForFormResubmission(int policyFunction)


        
        Message dontResend = obtainMessage(POLICY_FUNCTION, policyFunction,
                POLICY_IGNORE);
        Message resend = obtainMessage(POLICY_FUNCTION, policyFunction,
                POLICY_USE);
        mCallbackProxy.onFormResubmission(dontResend, resend);
    
public voiddestroy()
Destroy all native components of the BrowserFrame.

        nativeDestroyFrame();
        removeCallbacksAndMessages(null);
    
voiddidFirstLayout()

        if (!mFirstLayoutDone) {
            mFirstLayoutDone = true;
            // ensure {@link WebViewCore#webkitDraw} is called as we were
            // blocking the update in {@link #loadStarted}
            mWebViewCore.contentDraw();
        }
        mWebViewCore.mEndScaleZoom = true;
    
private voiddidReceiveIcon(android.graphics.Bitmap icon)
Send the icon to the activity for display.

param
icon A Bitmap representing a page's favicon.

        mCallbackProxy.onReceivedIcon(icon);
    
public voiddocumentAsText(android.os.Message callback)
Retrieves the visual text of the current frame, puts it as the object for the message and sends the message.

param
callback the message to use to send the visual text

        callback.obj = documentAsText();;
        callback.sendToTarget();
    
private native java.lang.StringdocumentAsText()
Return the text drawn on the screen as a string

public native booleandocumentHasImages()
Return true if the document has images.

public voidexternalRepresentation(android.os.Message callback)
Retrieves the render tree of this frame and puts it as the object for the message and sends the message.

param
callback the message to use to send the render tree

        callback.obj = externalRepresentation();;
        callback.sendToTarget();
    
private native java.lang.StringexternalRepresentation()
Return the render tree as a string

booleanfirstLayoutDone()

        return mFirstLayoutDone;
    
CallbackProxygetCallbackProxy()
Get the CallbackProxy for sending messages to the UI thread.

        return mCallbackProxy;
    
private native java.util.HashMapgetFormTextData()
Get form's "text" type data associated with the current frame.

return
HashMap If succeed, returns a list of name/value pair. Otherwise returns null.

java.lang.StringgetRawResFilename(int id)


       
        int resid;
        switch (id) {
            case NODOMAIN:
                resid = com.android.internal.R.raw.nodomain;
                break;

            case LOADERROR:
                resid = com.android.internal.R.raw.loaderror;
                break;

            default:
                Log.e(LOGTAG, "getRawResFilename got incompatible resource ID");
                return new String();
        }
        TypedValue value = new TypedValue();
        mContext.getResources().getValue(resid, value, true);
        return value.string.toString();
    
java.lang.StringgetUserAgentString()
Returns the User Agent used by this frame

        return mSettings.getUserAgentString();
    
private native java.lang.String[]getUsernamePassword()
Get username and password in the current frame. If found, String[0] is username and String[1] is password. Otherwise return NULL.

return
String[]

public voidgoBackOrForward(int steps)
Go back or forward the number of steps given.

param
steps A negative or positive number indicating the direction and number of steps to move.

        mLoadInitFromJava = true;
        nativeGoBackOrForward(steps);
        mLoadInitFromJava = false;
    
public voidhandleMessage(android.os.Message msg)
Handle messages posted to us.

param
msg The message to handle.

        switch (msg.what) {
            case FRAME_COMPLETED: {
                if (mSettings.getSavePassword() && hasPasswordField()) {
                    if (Config.DEBUG) {
                        Assert.assertNotNull(mCallbackProxy.getBackForwardList()
                                .getCurrentItem());
                    }
                    WebAddress uri = new WebAddress(
                            mCallbackProxy.getBackForwardList().getCurrentItem()
                            .getUrl());
                    String schemePlusHost = uri.mScheme + uri.mHost;
                    String[] up = mDatabase.getUsernamePassword(schemePlusHost);
                    if (up != null && up[0] != null) {
                        setUsernamePassword(up[0], up[1]);
                    }
                }
                CacheManager.trimCacheIfNeeded();
                break;
            }

            case POLICY_FUNCTION: {
                nativeCallPolicyFunction(msg.arg1, msg.arg2);
                break;
            }

            default:
                break;
        }
    
public booleanhandleUrl(java.lang.String url)
This method is called by WebCore to check whether application wants to hijack url loading

        if (mLoadInitFromJava == true) {
            return false;
        }
        if (mCallbackProxy.shouldOverrideUrlLoading(url)) {
            // if the url is hijacked, reset the state of the BrowserFrame
            didFirstLayout();
            return true;
        } else {
            return false;
        }
    
private native booleanhasPasswordField()

return
TRUE if there is a password field in the current frame

public voidloadData(java.lang.String baseUrl, java.lang.String data, java.lang.String mimeType, java.lang.String encoding, java.lang.String failUrl)
Load the content as if it was loaded by the provided base URL. The failUrl is used as the history entry for the load data. If null or an empty string is passed for the failUrl, then no history entry is created.

param
baseUrl Base URL used to resolve relative paths in the content
param
data Content to render in the browser
param
mimeType Mimetype of the data being passed in
param
encoding Character set encoding of the provided data.
param
failUrl URL to use if the content fails to load or null.

        mLoadInitFromJava = true;
        if (failUrl == null) {
            failUrl = "";
        }
        if (data == null) {
            data = "";
        }
        
        // Setup defaults for missing values. These defaults where taken from
        // WebKit's WebFrame.mm
        if (baseUrl == null || baseUrl.length() == 0) {
            baseUrl = "about:blank";
        }
        if (mimeType == null || mimeType.length() == 0) {
            mimeType = "text/html";
        }
        nativeLoadData(baseUrl, data, mimeType, encoding, failUrl);
        mLoadInitFromJava = false;
    
private voidloadFinished(java.lang.String url, int loadType, boolean isMainFrame)
native callback

Indicates the end of a new load. This method will be called once for the main frame.

        // mIsMainFrame and isMainFrame are better be equal!!!

        if (isMainFrame || loadType == FRAME_LOADTYPE_STANDARD) {
            if (isMainFrame) {
                resetLoadingStates();
                mCallbackProxy.switchOutDrawHistory();
                mCallbackProxy.onPageFinished(url);
            }
        }
    
private voidloadStarted(java.lang.String url, android.graphics.Bitmap favicon, int loadType, boolean isMainFrame)
native callback Indicates the beginning of a new load. This method will be called once for the main frame.

        mIsMainFrame = isMainFrame;

        if (isMainFrame || loadType == FRAME_LOADTYPE_STANDARD) {
            mLoadType = loadType;

            if (isMainFrame) {
                // Call onPageStarted for main frames.
                mCallbackProxy.onPageStarted(url, favicon);
                // as didFirstLayout() is only called for the main frame, reset 
                // mFirstLayoutDone only for the main frames
                mFirstLayoutDone = false;
                mCommitted = false;
                // remove pending draw to block update until mFirstLayoutDone is
                // set to true in didFirstLayout()
                mWebViewCore.removeMessages(WebViewCore.EventHub.WEBKIT_DRAW);
            }

            // Note: only saves committed form data in standard load
            if (loadType == FRAME_LOADTYPE_STANDARD
                    && mSettings.getSaveFormData()) {
                final WebHistoryItem h = mCallbackProxy.getBackForwardList()
                        .getCurrentItem();
                if (h != null) {
                    String currentUrl = h.getUrl();
                    if (currentUrl != null) {
                        mDatabase.setFormData(currentUrl, getFormTextData());
                    }
                }
            }
        }
    
intloadType()

        return mLoadType;
    
public voidloadUrl(java.lang.String url)
Load a url from the network or the filesystem into the main frame. Following the same behaviour as Safari, javascript: URLs are not passed to the main frame, instead they are evaluated immediately.

param
url The url to load.

        mLoadInitFromJava = true;
        if (URLUtil.isJavaScriptUrl(url)) {
            // strip off the scheme and evaluate the string
            stringByEvaluatingJavaScriptFromString(
                    url.substring("javascript:".length()));
        } else {
            nativeLoadUrl(url);
        }
        mLoadInitFromJava = false;
    
private native voidnativeAddJavascriptInterface(int nativeFramePointer, java.lang.Object obj, java.lang.String interfaceName)
Add a javascript interface to the main frame.

private native voidnativeCallPolicyFunction(int policyFunction, int decision)

private native voidnativeCreateFrame(WebViewCore w, android.content.res.AssetManager am, WebBackForwardList list)
Create a new native frame for a given WebView

param
w A WebView that the frame draws into.
param
am AssetManager to use to get assets.
param
list The native side will add and remove items from this list as the native list changes.

public native voidnativeDestroyFrame()
Destroy the native frame.

private native voidnativeGoBackOrForward(int steps)
Go back or forward the number of steps given.

param
steps A negative or positive number indicating the direction and number of steps to move.

private native voidnativeLoadData(java.lang.String baseUrl, java.lang.String data, java.lang.String mimeType, java.lang.String encoding, java.lang.String failUrl)

private native voidnativeLoadUrl(java.lang.String url)
Returns false if the url is bad.

private native voidnativeStopLoading()

public native voidreload(boolean allowStale)
Reload the current main frame.

private voidreportError(int errorCode, java.lang.String description, java.lang.String failingUrl)
native callback Report an error to an activity.

param
errorCode The HTTP error code.
param
description A String description. TODO: Report all errors including resource errors but include some kind of domain identifier. Change errorCode to an enum for a cleaner interface.

        // As this is called for the main resource and loading will be stopped
        // after, reset the state variables.
        resetLoadingStates();
        mCallbackProxy.onReceivedError(errorCode, description, failingUrl);
    
private voidrequestFocus()
Try to focus this WebView.

        mCallbackProxy.onRequestFocus();
    
private voidresetLoadingStates()

        mCommitted = true;
        mWebViewCore.mEndScaleZoom = mFirstLayoutDone == false;
        mFirstLayoutDone = true;
    
private native voidsetCacheDisabled(boolean disabled)
Enable or disable the native cache.

private voidsetProgress(int newProgress)
Set the progress for the browser activity. Called by native code. Uses a delay so it does not happen too often.

param
newProgress An int between zero and one hundred representing the current progress percentage of loading the page.

        mCallbackProxy.onProgressChanged(newProgress);
        if (newProgress == 100) {
            sendMessageDelayed(obtainMessage(FRAME_COMPLETED), 100);
        }
        // FIXME: Need to figure out a better way to switch out of the history
        // drawing mode. Maybe we can somehow compare the history picture with 
        // the current picture, and switch when it contains more content.
        if (mFirstLayoutDone && newProgress > TRANSITION_SWITCH_THRESHOLD) {
            mCallbackProxy.switchOutDrawHistory();
        }
    
private voidsetTitle(java.lang.String title)
Punch-through for WebCore to set the document title. Inform the Activity of the new title.

param
title The new title of the document.

        // FIXME: The activity must call getTitle (a native method) to get the
        // title. We should try and cache the title if we can also keep it in
        // sync with the document.
        mCallbackProxy.onReceivedTitle(title);
    
private native voidsetUsernamePassword(java.lang.String username, java.lang.String password)
Set username and password to the proper fields in the current frame

param
username
param
password

private LoadListenerstartLoadingResource(int loaderHandle, java.lang.String url, java.lang.String method, java.util.HashMap headers, byte[] postData, int cacheMode, boolean isHighPriority, boolean synchronous)
Start loading a resource.

param
loaderHandle The native ResourceLoader that is the target of the data.
param
url The url to load.
param
method The http method.
param
headers The http headers.
param
postData If the method is "POST" postData is sent as the request body. Is null when empty.
param
cacheMode The cache mode to use when loading this resource.
param
isHighPriority True if this resource needs to be put at the front of the network queue.
param
synchronous True if the load is synchronous.
return
A newly created LoadListener object.

        PerfChecker checker = new PerfChecker();

        if (mSettings.getCacheMode() != WebSettings.LOAD_DEFAULT) {
            cacheMode = mSettings.getCacheMode();
        }

        if (method.equals("POST")) {
            // Don't use the cache on POSTs when issuing a normal POST
            // request.
            if (cacheMode == WebSettings.LOAD_NORMAL) {
                cacheMode = WebSettings.LOAD_NO_CACHE;
            }
            if (mSettings.getSavePassword() && hasPasswordField()) {
                try {
                    if (Config.DEBUG) {
                        Assert.assertNotNull(mCallbackProxy.getBackForwardList()
                                .getCurrentItem());
                    }
                    WebAddress uri = new WebAddress(mCallbackProxy
                            .getBackForwardList().getCurrentItem().getUrl());
                    String schemePlusHost = uri.mScheme + uri.mHost;
                    String[] ret = getUsernamePassword();
                    // Has the user entered a username/password pair and is
                    // there some POST data
                    if (ret != null && postData != null && 
                            ret[0].length() > 0 && ret[1].length() > 0) {
                        // Check to see if the username & password appear in
                        // the post data (there could be another form on the
                        // page and that was posted instead.
                        String postString = new String(postData);
                        if (postString.contains(URLEncoder.encode(ret[0])) &&
                                postString.contains(URLEncoder.encode(ret[1]))) {
                            String[] saved = mDatabase.getUsernamePassword(
                                    schemePlusHost);
                            if (saved != null) {
                                // null username implies that user has chosen not to
                                // save password
                                if (saved[0] != null) {
                                    // non-null username implies that user has
                                    // chosen to save password, so update the 
                                    // recorded password
                                    mDatabase.setUsernamePassword(
                                            schemePlusHost, ret[0], ret[1]);
                                }
                            } else {
                                // CallbackProxy will handle creating the resume
                                // message
                                mCallbackProxy.onSavePassword(schemePlusHost, ret[0], 
                                        ret[1], null);
                            }
                        }
                    }
                } catch (ParseException ex) {
                    // if it is bad uri, don't save its password
                }
                
            }
        }

        // is this resource the main-frame top-level page?
        boolean isMainFramePage = mIsMainFrame;

        if (Config.LOGV) {
            Log.v(LOGTAG, "startLoadingResource: url=" + url + ", method="
                    + method + ", postData=" + postData + ", isHighPriority="
                    + isHighPriority + ", isMainFramePage=" + isMainFramePage);
        }

        // Create a LoadListener
        LoadListener loadListener = LoadListener.getLoadListener(mContext, this, url,
                loaderHandle, synchronous, isMainFramePage);

        mCallbackProxy.onLoadResource(url);

        if (LoadListener.getNativeLoaderCount() > MAX_OUTSTANDING_REQUESTS) {
            loadListener.error(
                    android.net.http.EventHandler.ERROR, mContext.getString(
                            com.android.internal.R.string.httpErrorTooManyRequests));
            loadListener.notifyError();
            loadListener.tearDown();
            return null;
        }

        // during synchronous load, the WebViewCore thread is blocked, so we
        // need to endCacheTransaction first so that http thread won't be 
        // blocked in setupFile() when createCacheFile.
        if (synchronous) {
            CacheManager.endCacheTransaction();
        }

        FrameLoader loader = new FrameLoader(loadListener, mSettings,
                method, isHighPriority);
        loader.setHeaders(headers);
        loader.setPostData(postData);
        // Set the load mode to the mode used for the current page.
        // If WebKit wants validation, go to network directly.
        loader.setCacheMode(headers.containsKey("If-Modified-Since")
                || headers.containsKey("If-None-Match") ? 
                        WebSettings.LOAD_NO_CACHE : cacheMode);
        // Set referrer to current URL?
        if (!loader.executeLoad()) {
            checker.responseAlert("startLoadingResource fail");
        }
        checker.responseAlert("startLoadingResource succeed");

        if (synchronous) {
            CacheManager.startCacheTransaction();
        }

        return !synchronous ? loadListener : null;
    
public voidstopLoading()
Stop loading the current page.

        if (mIsMainFrame) {
            resetLoadingStates();
        }
        nativeStopLoading();
    
public native java.lang.StringstringByEvaluatingJavaScriptFromString(java.lang.String script)
stringByEvaluatingJavaScriptFromString will execute the JS passed in in the context of this browser frame.

param
script A javascript string to execute
return
string result of execution or null

private voidtransitionToCommitted(int loadType, boolean isMainFrame)
native callback Indicates the WebKit has committed to the new load

        // loadType is not used yet
        if (isMainFrame) {
            mCommitted = true;
        }
    
private voidupdateVisitedHistory(java.lang.String url, boolean isReload)
Tell the activity to update its global history.

        mCallbackProxy.doUpdateVisitedHistory(url, isReload);
    
private voidwindowObjectCleared(int nativeFramePointer)

        if (mJSInterfaceMap != null) {
            Iterator iter = mJSInterfaceMap.keySet().iterator();
            while (iter.hasNext())  {
                String interfaceName = (String) iter.next();
                nativeAddJavascriptInterface(nativeFramePointer,
                        mJSInterfaceMap.get(interfaceName), interfaceName);
            }
        }