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