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