Merge "async find-on-page implementation via WebKit"
diff --git a/core/java/android/webkit/FindActionModeCallback.java b/core/java/android/webkit/FindActionModeCallback.java
index fffa90b..10b0885 100644
--- a/core/java/android/webkit/FindActionModeCallback.java
+++ b/core/java/android/webkit/FindActionModeCallback.java
@@ -43,7 +43,9 @@
     private Resources mResources;
     private boolean mMatchesFound;
     private int mNumberOfMatches;
+    private int mActiveMatchIndex;
     private ActionMode mActionMode;
+    private String mLastFind;
 
     FindActionModeCallback(Context context) {
         mCustomView = LayoutInflater.from(context).inflate(
@@ -132,16 +134,13 @@
             mWebView.clearMatches();
             mMatches.setVisibility(View.GONE);
             mMatchesFound = false;
+            mLastFind = null;
         } else {
             mMatchesFound = true;
-            mMatches.setVisibility(View.VISIBLE);
-            mNumberOfMatches = mWebView.findAll(find.toString());
-            if (0 == mNumberOfMatches) {
-                mMatches.setText(mResources.getString(
-                        com.android.internal.R.string.no_matches));
-            } else {
-                updateMatchesString();
-            }
+            mMatches.setVisibility(View.INVISIBLE);
+            mNumberOfMatches = 0;
+            mLastFind = find.toString();
+            mWebView.findAllAsync(mLastFind);
         }
     }
 
@@ -151,17 +150,31 @@
         mInput.showSoftInput(mEditText, 0);
     }
 
+    public void updateMatchCount(int matchIndex, int matchCount,
+        String findText) {
+        if (mLastFind != null && mLastFind.equals(findText)) {
+            mNumberOfMatches = matchCount;
+            mActiveMatchIndex = matchIndex;
+            updateMatchesString();
+        } else {
+            mMatches.setVisibility(View.INVISIBLE);
+            mNumberOfMatches = 0;
+        }
+    }
+
     /*
      * Update the string which tells the user how many matches were found, and
      * which match is currently highlighted.
-     * Not to be called when mNumberOfMatches is 0.
      */
     private void updateMatchesString() {
-        String template = mResources.getQuantityString(
+        if (mNumberOfMatches == 0) {
+            mMatches.setText(com.android.internal.R.string.no_matches);
+        } else {
+            mMatches.setText(mResources.getQuantityString(
                 com.android.internal.R.plurals.matches_found, mNumberOfMatches,
-                mWebView.findIndex() + 1, mNumberOfMatches);
-
-        mMatches.setText(template);
+                mActiveMatchIndex + 1, mNumberOfMatches));
+        }
+        mMatches.setVisibility(View.VISIBLE);
     }
 
     // OnLongClickListener implementation
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index a35106a..2304c25 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -914,7 +914,7 @@
     static final int REPLACE_BASE_CONTENT               = 123;
     static final int FORM_DID_BLUR                      = 124;
     static final int RETURN_LABEL                       = 125;
-    static final int FIND_AGAIN                         = 126;
+    static final int UPDATE_MATCH_COUNT                 = 126;
     static final int CENTER_FIT_RECT                    = 127;
     static final int REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID = 128;
     static final int SET_SCROLLBAR_MODES                = 129;
@@ -979,7 +979,7 @@
         "REPLACE_BASE_CONTENT", //           = 123;
         "FORM_DID_BLUR", //                  = 124;
         "RETURN_LABEL", //                   = 125;
-        "FIND_AGAIN", //                     = 126;
+        "UPDATE_MATCH_COUNT", //             = 126;
         "CENTER_FIT_RECT", //                = 127;
         "REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID", // = 128;
         "SET_SCROLLBAR_MODES", //            = 129;
@@ -1021,9 +1021,8 @@
 
     // keep these in sync with their counterparts in WebView.cpp
     private static final int DRAW_EXTRAS_NONE = 0;
-    private static final int DRAW_EXTRAS_FIND = 1;
-    private static final int DRAW_EXTRAS_SELECTION = 2;
-    private static final int DRAW_EXTRAS_CURSOR_RING = 3;
+    private static final int DRAW_EXTRAS_SELECTION = 1;
+    private static final int DRAW_EXTRAS_CURSOR_RING = 2;
 
     // keep this in sync with WebCore:ScrollbarMode in WebKit
     private static final int SCROLLBAR_AUTO = 0;
@@ -3711,7 +3710,7 @@
     public void findNext(boolean forward) {
         checkThread();
         if (0 == mNativeClass) return; // client isn't initialized
-        nativeFindNext(forward);
+        mWebViewCore.sendMessage(EventHub.FIND_NEXT, forward ? 1 : 0);
     }
 
     /*
@@ -3721,13 +3720,40 @@
      *              that were found.
      */
     public int findAll(String find) {
+        return findAllBody(find, false);
+    }
+
+    /**
+     * @hide
+     */
+    public void findAllAsync(String find) {
+        findAllBody(find, true);
+    }
+
+    private int findAllBody(String find, boolean isAsync) {
         checkThread();
         if (0 == mNativeClass) return 0; // client isn't initialized
-        int result = find != null ? nativeFindAll(find.toLowerCase(),
-                find.toUpperCase(), find.equalsIgnoreCase(mLastFind)) : 0;
-        invalidate();
         mLastFind = find;
-        return result;
+        mWebViewCore.removeMessages(EventHub.FIND_ALL);
+        WebViewCore.FindAllRequest request = new
+            WebViewCore.FindAllRequest(find);
+        if (isAsync) {
+            mWebViewCore.sendMessage(EventHub.FIND_ALL, request);
+            return 0; // no need to wait for response
+        }
+        synchronized(request) {
+            try {
+                mWebViewCore.sendMessageAtFrontOfQueue(EventHub.FIND_ALL,
+                    request);
+                while (request.mMatchCount == -1) {
+                    request.wait();
+                }
+            }
+            catch (InterruptedException e) {
+                return 0;
+            }
+        }
+        return request.mMatchCount;
     }
 
     /**
@@ -3763,6 +3789,7 @@
         }
         if (text != null) {
             mFindCallback.setText(text);
+            mFindCallback.findAll();
         }
         return true;
     }
@@ -3782,14 +3809,6 @@
         nativeSetFindIsUp(isUp);
     }
 
-    /**
-     * Return the index of the currently highlighted match.
-     */
-    int findIndex() {
-        if (0 == mNativeClass) return -1;
-        return nativeFindIndex();
-    }
-
     // Used to know whether the find dialog is open.  Affects whether
     // or not we draw the highlights for matches.
     private boolean mFindIsUp;
@@ -3856,10 +3875,11 @@
         checkThread();
         if (mNativeClass == 0)
             return;
-        nativeSetFindIsEmpty();
-        invalidate();
+        mWebViewCore.removeMessages(EventHub.FIND_ALL);
+        mWebViewCore.sendMessage(EventHub.FIND_ALL, null);
     }
 
+
     /**
      * Called when the find ActionMode ends.
      */
@@ -4954,12 +4974,12 @@
 
         // decide which adornments to draw
         int extras = DRAW_EXTRAS_NONE;
-        if (mFindIsUp) {
-            extras = DRAW_EXTRAS_FIND;
-        } else if (mSelectingText) {
-            extras = DRAW_EXTRAS_SELECTION;
-        } else if (drawCursorRing) {
-            extras = DRAW_EXTRAS_CURSOR_RING;
+        if (!mFindIsUp) {
+            if (mSelectingText) {
+                extras = DRAW_EXTRAS_SELECTION;
+            } else if (drawCursorRing) {
+                extras = DRAW_EXTRAS_CURSOR_RING;
+            }
         }
         if (DebugFlags.WEB_VIEW) {
             Log.v(LOGTAG, "mFindIsUp=" + mFindIsUp
@@ -8884,13 +8904,6 @@
                     }
                     break;
 
-                case FIND_AGAIN:
-                    // Ignore if find has been dismissed.
-                    if (mFindIsUp && mFindCallback != null) {
-                        mFindCallback.findAll();
-                    }
-                    break;
-
                 case DRAG_HELD_MOTIONLESS:
                     mHeldMotionless = MOTIONLESS_TRUE;
                     invalidate();
@@ -9095,6 +9108,14 @@
                     break;
                 }
 
+                case UPDATE_MATCH_COUNT: {
+                    if (mFindCallback != null) {
+                        mFindCallback.updateMatchCount(msg.arg1, msg.arg2,
+                            (String) msg.obj);
+                    }
+                    break;
+                }
+
                 default:
                     super.handleMessage(msg);
                     break;
@@ -9931,9 +9952,6 @@
     private native void     nativeUpdateDrawGLFunction(Rect rect, Rect viewRect,
             RectF visibleRect, float scale);
     private native void     nativeExtendSelection(int x, int y);
-    private native int      nativeFindAll(String findLower, String findUpper,
-            boolean sameAsLastSearch);
-    private native void     nativeFindNext(boolean forward);
     /* package */ native int      nativeFocusCandidateFramePointer();
     /* package */ native boolean  nativeFocusCandidateHasNextTextfield();
     /* package */ native boolean  nativeFocusCandidateIsPassword();
@@ -9991,9 +10009,7 @@
     private native boolean  nativePointInNavCache(int x, int y, int slop);
     private native void     nativeSelectBestAt(Rect rect);
     private native void     nativeSelectAt(int x, int y);
-    private native int      nativeFindIndex();
     private native void     nativeSetExtendSelection();
-    private native void     nativeSetFindIsEmpty();
     private native void     nativeSetFindIsUp(boolean isUp);
     private native void     nativeSetHeightCanMeasure(boolean measure);
     private native boolean  nativeSetBaseLayer(int nativeInstance,
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index b6c5612..4b1ae37 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -1001,6 +1001,15 @@
             "REMOVE_JS_INTERFACE", // = 149;
         };
 
+    static class FindAllRequest {
+        public FindAllRequest(String text) {
+            mSearchText = text;
+            mMatchCount = -1;
+        }
+        public String mSearchText;
+        public int mMatchCount;
+    }
+
     /**
      * @hide
      */
@@ -1142,6 +1151,10 @@
         // for updating state on trust storage change
         static final int TRUST_STORAGE_UPDATED = 220;
 
+        // find-on-page controls
+        static final int FIND_ALL = 220;
+        static final int FIND_NEXT = 221;
+
         // Private handler for WebCore messages.
         private Handler mHandler;
         // Message queue for containing messages before the WebCore thread is
@@ -1785,6 +1798,22 @@
                         case SELECT_ALL:
                             nativeSelectAll(mNativeClass);
                             break;
+                        case FIND_ALL: {
+                            FindAllRequest request = (FindAllRequest) msg.obj;
+                            if (request == null) {
+                                nativeFindAll(mNativeClass, null);
+                            } else {
+                                request.mMatchCount = nativeFindAll(
+                                    mNativeClass, request.mSearchText);
+                                synchronized(request) {
+                                    request.notify();
+                                }
+                            }
+                            break;
+                        }
+                        case FIND_NEXT:
+                            nativeFindNext(mNativeClass, msg.arg1 != 0);
+                            break;
                     }
                 }
             };
@@ -2783,13 +2812,6 @@
     }
 
     // called by JNI
-    private void sendFindAgain() {
-        if (mWebView == null) return;
-        Message.obtain(mWebView.mPrivateHandler,
-                WebView.FIND_AGAIN).sendToTarget();
-    }
-
-    // called by JNI
     private void initEditField(int pointer, String text, int start, int end) {
         if (mWebView == null) {
             return;
@@ -2802,6 +2824,17 @@
                 .sendToTarget();
     }
 
+    // called by JNI
+    private void updateMatchCount(int matchIndex, int matchCount,
+        String findText) {
+        if (mWebView == null) {
+            return;
+        }
+        Message.obtain(mWebView.mPrivateHandler,
+                WebView.UPDATE_MATCH_COUNT, matchIndex, matchCount,
+                findText).sendToTarget();
+    }
+
     private native void nativeUpdateFrameCacheIfLoading(int nativeClass);
     private native void nativeRevealSelection(int nativeClass);
     private native String nativeRequestLabel(int nativeClass, int framePtr,
@@ -3055,6 +3088,8 @@
 
     private native void nativeAutoFillForm(int nativeClass, int queryId);
     private native void nativeScrollLayer(int nativeClass, int layer, Rect rect);
+    private native int nativeFindAll(int nativeClass, String text);
+    private native void nativeFindNext(int nativeClass, boolean forward);
 
     /**
      * Deletes editable text between two points. Note that the selection may