BrowserFrame.java revision 658ab7d787f64987d7c45aae08e5a12a073afe78
1/*
2 * Copyright (C) 2006 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;
20import android.content.res.AssetManager;
21import android.graphics.Bitmap;
22import android.net.ParseException;
23import android.net.WebAddress;
24import android.net.http.SslCertificate;
25import android.os.Handler;
26import android.os.Message;
27import android.util.Log;
28import android.util.TypedValue;
29
30import junit.framework.Assert;
31
32import java.net.URLEncoder;
33import java.util.HashMap;
34import java.util.Iterator;
35
36class BrowserFrame extends Handler {
37
38    private static final String LOGTAG = "webkit";
39
40    /**
41     * Cap the number of LoadListeners that will be instantiated, so
42     * we don't blow the GREF count.  Attempting to queue more than
43     * this many requests will prompt an error() callback on the
44     * request's LoadListener
45     */
46    private final static int MAX_OUTSTANDING_REQUESTS = 300;
47
48    private final CallbackProxy mCallbackProxy;
49    private final WebSettings mSettings;
50    private final Context mContext;
51    private final WebViewDatabase mDatabase;
52    private final WebViewCore mWebViewCore;
53    /* package */ boolean mLoadInitFromJava;
54    private int mLoadType;
55    private boolean mFirstLayoutDone = true;
56    private boolean mCommitted = true;
57
58    // Is this frame the main frame?
59    private boolean mIsMainFrame;
60
61    // Attached Javascript interfaces
62    private HashMap mJSInterfaceMap;
63
64    // message ids
65    // a message posted when a frame loading is completed
66    static final int FRAME_COMPLETED = 1001;
67    // a message posted when the user decides the policy
68    static final int POLICY_FUNCTION = 1003;
69
70    // Note: need to keep these in sync with FrameLoaderTypes.h in native
71    static final int FRAME_LOADTYPE_STANDARD = 0;
72    static final int FRAME_LOADTYPE_BACK = 1;
73    static final int FRAME_LOADTYPE_FORWARD = 2;
74    static final int FRAME_LOADTYPE_INDEXEDBACKFORWARD = 3;
75    static final int FRAME_LOADTYPE_RELOAD = 4;
76    static final int FRAME_LOADTYPE_RELOADALLOWINGSTALEDATA = 5;
77    static final int FRAME_LOADTYPE_SAME = 6;
78    static final int FRAME_LOADTYPE_REDIRECT = 7;
79    static final int FRAME_LOADTYPE_REPLACE = 8;
80
81    // A progress threshold to switch from history Picture to live Picture
82    private static final int TRANSITION_SWITCH_THRESHOLD = 75;
83
84    // This is a field accessed by native code as well as package classes.
85    /*package*/ int mNativeFrame;
86
87    // Static instance of a JWebCoreJavaBridge to handle timer and cookie
88    // requests from WebCore.
89    static JWebCoreJavaBridge sJavaBridge;
90
91    /**
92     * Create a new BrowserFrame to be used in an application.
93     * @param context An application context to use when retrieving assets.
94     * @param w A WebViewCore used as the view for this frame.
95     * @param proxy A CallbackProxy for posting messages to the UI thread and
96     *              querying a client for information.
97     * @param settings A WebSettings object that holds all settings.
98     * XXX: Called by WebCore thread.
99     */
100    public BrowserFrame(Context context, WebViewCore w, CallbackProxy proxy,
101            WebSettings settings) {
102        // Create a global JWebCoreJavaBridge to handle timers and
103        // cookies in the WebCore thread.
104        if (sJavaBridge == null) {
105            sJavaBridge = new JWebCoreJavaBridge();
106            // set WebCore native cache size
107            sJavaBridge.setCacheSize(4 * 1024 * 1024);
108            // initialize CacheManager
109            CacheManager.init(context);
110            // create CookieSyncManager with current Context
111            CookieSyncManager.createInstance(context);
112            // create PluginManager with current Context
113            PluginManager.getInstance(context);
114        }
115        AssetManager am = context.getAssets();
116        nativeCreateFrame(w, am, proxy.getBackForwardList());
117
118        mSettings = settings;
119        mContext = context;
120        mCallbackProxy = proxy;
121        mDatabase = WebViewDatabase.getInstance(context);
122        mWebViewCore = w;
123
124        if (WebView.LOGV_ENABLED) {
125            Log.v(LOGTAG, "BrowserFrame constructor: this=" + this);
126        }
127    }
128
129    /**
130     * Load a url from the network or the filesystem into the main frame.
131     * Following the same behaviour as Safari, javascript: URLs are not
132     * passed to the main frame, instead they are evaluated immediately.
133     * @param url The url to load.
134     */
135    public void loadUrl(String url) {
136        mLoadInitFromJava = true;
137        if (URLUtil.isJavaScriptUrl(url)) {
138            // strip off the scheme and evaluate the string
139            stringByEvaluatingJavaScriptFromString(
140                    url.substring("javascript:".length()));
141        } else {
142            nativeLoadUrl(url);
143        }
144        mLoadInitFromJava = false;
145    }
146
147    /**
148     * Load the content as if it was loaded by the provided base URL. The
149     * failUrl is used as the history entry for the load data. If null or
150     * an empty string is passed for the failUrl, then no history entry is
151     * created.
152     *
153     * @param baseUrl Base URL used to resolve relative paths in the content
154     * @param data Content to render in the browser
155     * @param mimeType Mimetype of the data being passed in
156     * @param encoding Character set encoding of the provided data.
157     * @param failUrl URL to use if the content fails to load or null.
158     */
159    public void loadData(String baseUrl, String data, String mimeType,
160            String encoding, String failUrl) {
161        mLoadInitFromJava = true;
162        if (failUrl == null) {
163            failUrl = "";
164        }
165        if (data == null) {
166            data = "";
167        }
168
169        // Setup defaults for missing values. These defaults where taken from
170        // WebKit's WebFrame.mm
171        if (baseUrl == null || baseUrl.length() == 0) {
172            baseUrl = "about:blank";
173        }
174        if (mimeType == null || mimeType.length() == 0) {
175            mimeType = "text/html";
176        }
177        nativeLoadData(baseUrl, data, mimeType, encoding, failUrl);
178        mLoadInitFromJava = false;
179    }
180
181    /**
182     * Go back or forward the number of steps given.
183     * @param steps A negative or positive number indicating the direction
184     *              and number of steps to move.
185     */
186    public void goBackOrForward(int steps) {
187        mLoadInitFromJava = true;
188        nativeGoBackOrForward(steps);
189        mLoadInitFromJava = false;
190    }
191
192    /**
193     * native callback
194     * Report an error to an activity.
195     * @param errorCode The HTTP error code.
196     * @param description A String description.
197     * TODO: Report all errors including resource errors but include some kind
198     * of domain identifier. Change errorCode to an enum for a cleaner
199     * interface.
200     */
201    private void reportError(final int errorCode, final String description,
202            final String failingUrl) {
203        // As this is called for the main resource and loading will be stopped
204        // after, reset the state variables.
205        resetLoadingStates();
206        mCallbackProxy.onReceivedError(errorCode, description, failingUrl);
207    }
208
209    private void resetLoadingStates() {
210        mCommitted = true;
211        mWebViewCore.mEndScaleZoom = mFirstLayoutDone == false;
212        mFirstLayoutDone = true;
213    }
214
215    /* package */boolean committed() {
216        return mCommitted;
217    }
218
219    /* package */boolean firstLayoutDone() {
220        return mFirstLayoutDone;
221    }
222
223    /* package */int loadType() {
224        return mLoadType;
225    }
226
227    /* package */void didFirstLayout() {
228        if (!mFirstLayoutDone) {
229            mFirstLayoutDone = true;
230            // ensure {@link WebViewCore#webkitDraw} is called as we were
231            // blocking the update in {@link #loadStarted}
232            mWebViewCore.contentDraw();
233        }
234        mWebViewCore.mEndScaleZoom = true;
235    }
236
237    /**
238     * native callback
239     * Indicates the beginning of a new load.
240     * This method will be called once for the main frame.
241     */
242    private void loadStarted(String url, Bitmap favicon, int loadType,
243            boolean isMainFrame) {
244        mIsMainFrame = isMainFrame;
245
246        if (isMainFrame || loadType == FRAME_LOADTYPE_STANDARD) {
247            mLoadType = loadType;
248
249            if (isMainFrame) {
250                // Call onPageStarted for main frames.
251                mCallbackProxy.onPageStarted(url, favicon);
252                // as didFirstLayout() is only called for the main frame, reset
253                // mFirstLayoutDone only for the main frames
254                mFirstLayoutDone = false;
255                mCommitted = false;
256                // remove pending draw to block update until mFirstLayoutDone is
257                // set to true in didFirstLayout()
258                mWebViewCore.removeMessages(WebViewCore.EventHub.WEBKIT_DRAW);
259            }
260
261            // Note: only saves committed form data in standard load
262            if (loadType == FRAME_LOADTYPE_STANDARD
263                    && mSettings.getSaveFormData()) {
264                final WebHistoryItem h = mCallbackProxy.getBackForwardList()
265                        .getCurrentItem();
266                if (h != null) {
267                    String currentUrl = h.getUrl();
268                    if (currentUrl != null) {
269                        mDatabase.setFormData(currentUrl, getFormTextData());
270                    }
271                }
272            }
273        }
274    }
275
276    /**
277     * native callback
278     * Indicates the WebKit has committed to the new load
279     */
280    private void transitionToCommitted(int loadType, boolean isMainFrame) {
281        // loadType is not used yet
282        if (isMainFrame) {
283            mCommitted = true;
284        }
285    }
286
287    /**
288     * native callback
289     * <p>
290     * Indicates the end of a new load.
291     * This method will be called once for the main frame.
292     */
293    private void loadFinished(String url, int loadType, boolean isMainFrame) {
294        // mIsMainFrame and isMainFrame are better be equal!!!
295
296        if (isMainFrame || loadType == FRAME_LOADTYPE_STANDARD) {
297            if (isMainFrame) {
298                resetLoadingStates();
299                mCallbackProxy.switchOutDrawHistory();
300                mCallbackProxy.onPageFinished(url);
301            }
302        }
303    }
304
305    /**
306     * We have received an SSL certificate for the main top-level page.
307     *
308     * !!!Called from the network thread!!!
309     */
310    void certificate(SslCertificate certificate) {
311        if (mIsMainFrame) {
312            // we want to make this call even if the certificate is null
313            // (ie, the site is not secure)
314            mCallbackProxy.onReceivedCertificate(certificate);
315        }
316    }
317
318    /**
319     * Destroy all native components of the BrowserFrame.
320     */
321    public void destroy() {
322        nativeDestroyFrame();
323        removeCallbacksAndMessages(null);
324    }
325
326    /**
327     * Handle messages posted to us.
328     * @param msg The message to handle.
329     */
330    @Override
331    public void handleMessage(Message msg) {
332        switch (msg.what) {
333            case FRAME_COMPLETED: {
334                if (mSettings.getSavePassword() && hasPasswordField()) {
335                    if (WebView.DEBUG) {
336                        Assert.assertNotNull(mCallbackProxy.getBackForwardList()
337                                .getCurrentItem());
338                    }
339                    WebAddress uri = new WebAddress(
340                            mCallbackProxy.getBackForwardList().getCurrentItem()
341                            .getUrl());
342                    String schemePlusHost = uri.mScheme + uri.mHost;
343                    String[] up = mDatabase.getUsernamePassword(schemePlusHost);
344                    if (up != null && up[0] != null) {
345                        setUsernamePassword(up[0], up[1]);
346                    }
347                }
348                CacheManager.trimCacheIfNeeded();
349                break;
350            }
351
352            case POLICY_FUNCTION: {
353                nativeCallPolicyFunction(msg.arg1, msg.arg2);
354                break;
355            }
356
357            default:
358                break;
359        }
360    }
361
362    /**
363     * Punch-through for WebCore to set the document
364     * title. Inform the Activity of the new title.
365     * @param title The new title of the document.
366     */
367    private void setTitle(String title) {
368        // FIXME: The activity must call getTitle (a native method) to get the
369        // title. We should try and cache the title if we can also keep it in
370        // sync with the document.
371        mCallbackProxy.onReceivedTitle(title);
372    }
373
374    /**
375     * Retrieves the render tree of this frame and puts it as the object for
376     * the message and sends the message.
377     * @param callback the message to use to send the render tree
378     */
379    public void externalRepresentation(Message callback) {
380        callback.obj = externalRepresentation();;
381        callback.sendToTarget();
382    }
383
384    /**
385     * Return the render tree as a string
386     */
387    private native String externalRepresentation();
388
389    /**
390     * Retrieves the visual text of the current frame, puts it as the object for
391     * the message and sends the message.
392     * @param callback the message to use to send the visual text
393     */
394    public void documentAsText(Message callback) {
395        callback.obj = documentAsText();;
396        callback.sendToTarget();
397    }
398
399    /**
400     * Return the text drawn on the screen as a string
401     */
402    private native String documentAsText();
403
404    /*
405     * This method is called by WebCore to inform the frame that
406     * the Javascript window object has been cleared.
407     * We should re-attach any attached js interfaces.
408     */
409    private void windowObjectCleared(int nativeFramePointer) {
410        if (mJSInterfaceMap != null) {
411            Iterator iter = mJSInterfaceMap.keySet().iterator();
412            while (iter.hasNext())  {
413                String interfaceName = (String) iter.next();
414                nativeAddJavascriptInterface(nativeFramePointer,
415                        mJSInterfaceMap.get(interfaceName), interfaceName);
416            }
417        }
418    }
419
420    /**
421     * This method is called by WebCore to check whether application
422     * wants to hijack url loading
423     */
424    public boolean handleUrl(String url) {
425        if (mLoadInitFromJava == true) {
426            return false;
427        }
428        if (mCallbackProxy.shouldOverrideUrlLoading(url)) {
429            // if the url is hijacked, reset the state of the BrowserFrame
430            didFirstLayout();
431            return true;
432        } else {
433            return false;
434        }
435    }
436
437    public void addJavascriptInterface(Object obj, String interfaceName) {
438        if (mJSInterfaceMap == null) {
439            mJSInterfaceMap = new HashMap<String, Object>();
440        }
441        if (mJSInterfaceMap.containsKey(interfaceName)) {
442            mJSInterfaceMap.remove(interfaceName);
443        }
444        mJSInterfaceMap.put(interfaceName, obj);
445    }
446
447    /**
448     * Start loading a resource.
449     * @param loaderHandle The native ResourceLoader that is the target of the
450     *                     data.
451     * @param url The url to load.
452     * @param method The http method.
453     * @param headers The http headers.
454     * @param postData If the method is "POST" postData is sent as the request
455     *                 body. Is null when empty.
456     * @param cacheMode The cache mode to use when loading this resource.
457     * @param isHighPriority True if this resource needs to be put at the front
458     *                       of the network queue.
459     * @param synchronous True if the load is synchronous.
460     * @return A newly created LoadListener object.
461     */
462    private LoadListener startLoadingResource(int loaderHandle,
463                                              String url,
464                                              String method,
465                                              HashMap headers,
466                                              byte[] postData,
467                                              int cacheMode,
468                                              boolean isHighPriority,
469                                              boolean synchronous) {
470        PerfChecker checker = new PerfChecker();
471
472        if (mSettings.getCacheMode() != WebSettings.LOAD_DEFAULT) {
473            cacheMode = mSettings.getCacheMode();
474        }
475
476        if (method.equals("POST")) {
477            // Don't use the cache on POSTs when issuing a normal POST
478            // request.
479            if (cacheMode == WebSettings.LOAD_NORMAL) {
480                cacheMode = WebSettings.LOAD_NO_CACHE;
481            }
482            if (mSettings.getSavePassword() && hasPasswordField()) {
483                try {
484                    if (WebView.DEBUG) {
485                        Assert.assertNotNull(mCallbackProxy.getBackForwardList()
486                                .getCurrentItem());
487                    }
488                    WebAddress uri = new WebAddress(mCallbackProxy
489                            .getBackForwardList().getCurrentItem().getUrl());
490                    String schemePlusHost = uri.mScheme + uri.mHost;
491                    String[] ret = getUsernamePassword();
492                    // Has the user entered a username/password pair and is
493                    // there some POST data
494                    if (ret != null && postData != null &&
495                            ret[0].length() > 0 && ret[1].length() > 0) {
496                        // Check to see if the username & password appear in
497                        // the post data (there could be another form on the
498                        // page and that was posted instead.
499                        String postString = new String(postData);
500                        if (postString.contains(URLEncoder.encode(ret[0])) &&
501                                postString.contains(URLEncoder.encode(ret[1]))) {
502                            String[] saved = mDatabase.getUsernamePassword(
503                                    schemePlusHost);
504                            if (saved != null) {
505                                // null username implies that user has chosen not to
506                                // save password
507                                if (saved[0] != null) {
508                                    // non-null username implies that user has
509                                    // chosen to save password, so update the
510                                    // recorded password
511                                    mDatabase.setUsernamePassword(
512                                            schemePlusHost, ret[0], ret[1]);
513                                }
514                            } else {
515                                // CallbackProxy will handle creating the resume
516                                // message
517                                mCallbackProxy.onSavePassword(schemePlusHost, ret[0],
518                                        ret[1], null);
519                            }
520                        }
521                    }
522                } catch (ParseException ex) {
523                    // if it is bad uri, don't save its password
524                }
525
526            }
527        }
528
529        // is this resource the main-frame top-level page?
530        boolean isMainFramePage = mIsMainFrame;
531
532        if (WebView.LOGV_ENABLED) {
533            Log.v(LOGTAG, "startLoadingResource: url=" + url + ", method="
534                    + method + ", postData=" + postData + ", isHighPriority="
535                    + isHighPriority + ", isMainFramePage=" + isMainFramePage);
536        }
537
538        // Create a LoadListener
539        LoadListener loadListener = LoadListener.getLoadListener(mContext, this, url,
540                loaderHandle, synchronous, isMainFramePage);
541
542        mCallbackProxy.onLoadResource(url);
543
544        if (LoadListener.getNativeLoaderCount() > MAX_OUTSTANDING_REQUESTS) {
545            loadListener.error(
546                    android.net.http.EventHandler.ERROR, mContext.getString(
547                            com.android.internal.R.string.httpErrorTooManyRequests));
548            loadListener.notifyError();
549            loadListener.tearDown();
550            return null;
551        }
552
553        // during synchronous load, the WebViewCore thread is blocked, so we
554        // need to endCacheTransaction first so that http thread won't be
555        // blocked in setupFile() when createCacheFile.
556        if (synchronous) {
557            CacheManager.endCacheTransaction();
558        }
559
560        FrameLoader loader = new FrameLoader(loadListener, mSettings,
561                method, isHighPriority);
562        loader.setHeaders(headers);
563        loader.setPostData(postData);
564        // Set the load mode to the mode used for the current page.
565        // If WebKit wants validation, go to network directly.
566        loader.setCacheMode(headers.containsKey("If-Modified-Since")
567                || headers.containsKey("If-None-Match") ?
568                        WebSettings.LOAD_NO_CACHE : cacheMode);
569        // Set referrer to current URL?
570        if (!loader.executeLoad()) {
571            checker.responseAlert("startLoadingResource fail");
572        }
573        checker.responseAlert("startLoadingResource succeed");
574
575        if (synchronous) {
576            CacheManager.startCacheTransaction();
577        }
578
579        return !synchronous ? loadListener : null;
580    }
581
582    /**
583     * Set the progress for the browser activity.  Called by native code.
584     * Uses a delay so it does not happen too often.
585     * @param newProgress An int between zero and one hundred representing
586     *                    the current progress percentage of loading the page.
587     */
588    private void setProgress(int newProgress) {
589        mCallbackProxy.onProgressChanged(newProgress);
590        if (newProgress == 100) {
591            sendMessageDelayed(obtainMessage(FRAME_COMPLETED), 100);
592        }
593        // FIXME: Need to figure out a better way to switch out of the history
594        // drawing mode. Maybe we can somehow compare the history picture with
595        // the current picture, and switch when it contains more content.
596        if (mFirstLayoutDone && newProgress > TRANSITION_SWITCH_THRESHOLD) {
597            mCallbackProxy.switchOutDrawHistory();
598        }
599    }
600
601    /**
602     * Send the icon to the activity for display.
603     * @param icon A Bitmap representing a page's favicon.
604     */
605    private void didReceiveIcon(Bitmap icon) {
606        mCallbackProxy.onReceivedIcon(icon);
607    }
608
609    /**
610     * Request a new window from the client.
611     * @return The BrowserFrame object stored in the new WebView.
612     */
613    private BrowserFrame createWindow(boolean dialog, boolean userGesture) {
614        WebView w = mCallbackProxy.createWindow(dialog, userGesture);
615        if (w != null) {
616            return w.getWebViewCore().getBrowserFrame();
617        }
618        return null;
619    }
620
621    /**
622     * Try to focus this WebView.
623     */
624    private void requestFocus() {
625        mCallbackProxy.onRequestFocus();
626    }
627
628    /**
629     * Close this frame and window.
630     */
631    private void closeWindow(WebViewCore w) {
632        mCallbackProxy.onCloseWindow(w.getWebView());
633    }
634
635    // XXX: Must match PolicyAction in FrameLoaderTypes.h in webcore
636    static final int POLICY_USE = 0;
637    static final int POLICY_IGNORE = 2;
638
639    private void decidePolicyForFormResubmission(int policyFunction) {
640        Message dontResend = obtainMessage(POLICY_FUNCTION, policyFunction,
641                POLICY_IGNORE);
642        Message resend = obtainMessage(POLICY_FUNCTION, policyFunction,
643                POLICY_USE);
644        mCallbackProxy.onFormResubmission(dontResend, resend);
645    }
646
647    /**
648     * Tell the activity to update its global history.
649     */
650    private void updateVisitedHistory(String url, boolean isReload) {
651        mCallbackProxy.doUpdateVisitedHistory(url, isReload);
652    }
653
654    /**
655     * Get the CallbackProxy for sending messages to the UI thread.
656     */
657    /* package */ CallbackProxy getCallbackProxy() {
658        return mCallbackProxy;
659    }
660
661    /**
662     * Returns the User Agent used by this frame
663     */
664    String getUserAgentString() {
665        return mSettings.getUserAgentString();
666    }
667
668    // these ids need to be in sync with enum RAW_RES_ID in WebFrame
669    private static final int NODOMAIN = 1;
670    private static final int LOADERROR = 2;
671
672    String getRawResFilename(int id) {
673        int resid;
674        switch (id) {
675            case NODOMAIN:
676                resid = com.android.internal.R.raw.nodomain;
677                break;
678
679            case LOADERROR:
680                resid = com.android.internal.R.raw.loaderror;
681                break;
682
683            default:
684                Log.e(LOGTAG, "getRawResFilename got incompatible resource ID");
685                return new String();
686        }
687        TypedValue value = new TypedValue();
688        mContext.getResources().getValue(resid, value, true);
689        return value.string.toString();
690    }
691
692    //==========================================================================
693    // native functions
694    //==========================================================================
695
696    /**
697     * Create a new native frame for a given WebView
698     * @param w     A WebView that the frame draws into.
699     * @param am    AssetManager to use to get assets.
700     * @param list  The native side will add and remove items from this list as
701     *              the native list changes.
702     */
703    private native void nativeCreateFrame(WebViewCore w, AssetManager am,
704            WebBackForwardList list);
705
706    /**
707     * Destroy the native frame.
708     */
709    public native void nativeDestroyFrame();
710
711    private native void nativeCallPolicyFunction(int policyFunction,
712            int decision);
713
714    /**
715     * Reload the current main frame.
716     */
717    public native void reload(boolean allowStale);
718
719    /**
720     * Go back or forward the number of steps given.
721     * @param steps A negative or positive number indicating the direction
722     *              and number of steps to move.
723     */
724    private native void nativeGoBackOrForward(int steps);
725
726    /**
727     * stringByEvaluatingJavaScriptFromString will execute the
728     * JS passed in in the context of this browser frame.
729     * @param script A javascript string to execute
730     *
731     * @return string result of execution or null
732     */
733    public native String stringByEvaluatingJavaScriptFromString(String script);
734
735    /**
736     * Add a javascript interface to the main frame.
737     */
738    private native void nativeAddJavascriptInterface(int nativeFramePointer,
739            Object obj, String interfaceName);
740
741    /**
742     * Enable or disable the native cache.
743     */
744    /* FIXME: The native cache is always on for now until we have a better
745     * solution for our 2 caches. */
746    private native void setCacheDisabled(boolean disabled);
747
748    public native boolean cacheDisabled();
749
750    public native void clearCache();
751
752    /**
753     * Returns false if the url is bad.
754     */
755    private native void nativeLoadUrl(String url);
756
757    private native void nativeLoadData(String baseUrl, String data,
758            String mimeType, String encoding, String failUrl);
759
760    /**
761     * Stop loading the current page.
762     */
763    public void stopLoading() {
764        if (mIsMainFrame) {
765            resetLoadingStates();
766        }
767        nativeStopLoading();
768    }
769
770    private native void nativeStopLoading();
771
772    /**
773     * Return true if the document has images.
774     */
775    public native boolean documentHasImages();
776
777    /**
778     * @return TRUE if there is a password field in the current frame
779     */
780    private native boolean hasPasswordField();
781
782    /**
783     * Get username and password in the current frame. If found, String[0] is
784     * username and String[1] is password. Otherwise return NULL.
785     * @return String[]
786     */
787    private native String[] getUsernamePassword();
788
789    /**
790     * Set username and password to the proper fields in the current frame
791     * @param username
792     * @param password
793     */
794    private native void setUsernamePassword(String username, String password);
795
796    /**
797     * Get form's "text" type data associated with the current frame.
798     * @return HashMap If succeed, returns a list of name/value pair. Otherwise
799     *         returns null.
800     */
801    private native HashMap getFormTextData();
802}
803