Added Java callback for JavaScript execution timeout.
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index 5f8acc8..17d3f94 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -98,6 +98,7 @@
     private static final int SCALE_CHANGED        = 123;
     private static final int RECEIVED_CERTIFICATE = 124;
     private static final int SWITCH_OUT_HISTORY   = 125;
+    private static final int JS_TIMEOUT           = 126;
 
     // Message triggered by the client to resume execution
     private static final int NOTIFY               = 200;
@@ -530,6 +531,18 @@
                 }
                 break;
 
+            case JS_TIMEOUT:
+                if(mWebChromeClient != null) {
+                    final JsResult res = (JsResult) msg.obj;
+                    if(mWebChromeClient.onJsTimeout()) {
+                        res.confirm();
+                    } else {
+                        res.cancel();
+                    }
+                    res.setReady();
+                }
+                break;
+
             case RECEIVED_CERTIFICATE:
                 mWebView.setCertificate((SslCertificate) msg.obj);
                 break;
@@ -1022,4 +1035,26 @@
         }
         return result.getResult();
     }
+
+    /**
+     * @hide pending API council approval
+     */
+    public boolean onJsTimeout() {
+        //always interrupt timedout JS by default
+        if (mWebChromeClient == null) {
+            return true;
+        }
+        JsResult result = new JsResult(this, true);
+        Message timeout = obtainMessage(JS_TIMEOUT, result);
+        synchronized (this) {
+            sendMessage(timeout);
+            try {
+                wait();
+            } catch (InterruptedException e) {
+                Log.e(LOGTAG, "Caught exception while waiting for jsUnload");
+                Log.e(LOGTAG, Log.getStackTraceString(e));
+            }
+        }
+        return result.getResult();
+    }
 }
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index f9400061..9d9763c 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -157,4 +157,19 @@
             JsResult result) {
         return false;
     }
+
+    /**
+     * Tell the client that a JavaScript execution timeout has occured. And the
+     * client may decide whether or not to interrupt the execution. If the
+     * client returns true, the JavaScript will be interrupted. If the client
+     * returns false, the execution will continue. Note that in the case of
+     * continuing execution, the timeout counter will be reset, and the callback
+     * will continue to occur if the script does not finish at the next check
+     * point.
+     * @return boolean Whether the JavaScript execution should be interrupted.
+     * @hide pending API Council approval
+     */
+    public boolean onJsTimeout() {
+        return true;
+    }
 }
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 58d8ae7..e9df453 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -263,6 +263,16 @@
         return mCallbackProxy.onJsBeforeUnload(url, message);
     }
 
+    /**
+     *
+     * Callback to notify that a JavaScript execution timeout has occured.
+     * @return True if the JavaScript execution should be interrupted. False
+     *         will continue the execution.
+     */
+    protected boolean jsInterrupt() {
+        return mCallbackProxy.onJsTimeout();
+    }
+
     //-------------------------------------------------------------------------
     // JNI methods
     //-------------------------------------------------------------------------