Merge "Make WebView.findAllAsync() and WebView.setFindListener() public."
diff --git a/api/current.txt b/api/current.txt
index 3e177ad..180ac91 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -25773,7 +25773,8 @@
     method public deprecated void emulateShiftHeld();
     method public static deprecated void enablePlatformNotifications();
     method public static java.lang.String findAddress(java.lang.String);
-    method public int findAll(java.lang.String);
+    method public deprecated int findAll(java.lang.String);
+    method public void findAllAsync(java.lang.String);
     method public void findNext(boolean);
     method public void flingScroll(int, int);
     method public void freeMemory();
@@ -25824,6 +25825,7 @@
     method public void saveWebArchive(java.lang.String, boolean, android.webkit.ValueCallback<java.lang.String>);
     method public void setCertificate(android.net.http.SslCertificate);
     method public void setDownloadListener(android.webkit.DownloadListener);
+    method public void setFindListener(android.webkit.WebView.FindListener);
     method public void setHorizontalScrollbarOverlay(boolean);
     method public void setHttpAuthUsernamePassword(java.lang.String, java.lang.String, java.lang.String, java.lang.String);
     method public void setInitialScale(int);
@@ -25842,6 +25844,10 @@
     field public static final java.lang.String SCHEME_TEL = "tel:";
   }
 
+  public static abstract interface WebView.FindListener {
+    method public abstract void onFindResultReceived(int, int, boolean);
+  }
+
   public static class WebView.HitTestResult {
     method public java.lang.String getExtra();
     method public int getType();
diff --git a/core/java/android/webkit/FindActionModeCallback.java b/core/java/android/webkit/FindActionModeCallback.java
index 6c331ac..6b7263c 100644
--- a/core/java/android/webkit/FindActionModeCallback.java
+++ b/core/java/android/webkit/FindActionModeCallback.java
@@ -148,8 +148,8 @@
         mInput.showSoftInput(mEditText, 0);
     }
 
-    public void updateMatchCount(int matchIndex, int matchCount, boolean isNewFind) {
-        if (!isNewFind) {
+    public void updateMatchCount(int matchIndex, int matchCount, boolean isEmptyFind) {
+        if (!isEmptyFind) {
             mNumberOfMatches = matchCount;
             mActiveMatchIndex = matchIndex;
             updateMatchesString();
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 9492e38..84632c6 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -313,7 +313,6 @@
 
     /**
      * Interface to listen for find results.
-     * @hide
      */
     public interface FindListener {
         /**
@@ -1249,8 +1248,7 @@
      * Register the listener to be notified as find-on-page operations progress.
      * This will replace the current listener.
      *
-     * @param listener An implementation of {@link WebView#FindListener}.
-     * @hide
+     * @param listener An implementation of {@link FindListener}.
      */
     public void setFindListener(FindListener listener) {
         checkThread();
@@ -1258,11 +1256,15 @@
     }
 
     /**
-     * Highlight and scroll to the next occurance of String in findAll.
-     * Wraps the page infinitely, and scrolls.  Must be called after
-     * calling findAll.
+     * Highlight and scroll to the next match found by {@link #findAll} or
+     * {@link #findAllAsync}, wrapping around page boundaries as necessary.
+     * Notifies any registered {@link FindListener}. If neither
+     * {@link #findAll} nor {@link #findAllAsync(String)} has been called yet,
+     * or if {@link #clearMatches} has been called since the last find
+     * operation, this function does nothing.
      *
      * @param forward Direction to search.
+     * @see #setFindListener
      */
     public void findNext(boolean forward) {
         checkThread();
@@ -1271,10 +1273,13 @@
 
     /**
      * Find all instances of find on the page and highlight them.
+     * Notifies any registered {@link FindListener}.
      *
      * @param find  String to find.
      * @return int  The number of occurances of the String "find"
      *              that were found.
+     * @deprecated {@link #findAllAsync} is preferred.
+     * @see #setFindListener
      */
     public int findAll(String find) {
         checkThread();
@@ -1283,10 +1288,12 @@
 
     /**
      * Find all instances of find on the page and highlight them,
-     * asynchronously.
+     * asynchronously. Notifies any registered {@link FindListener}.
+     * Successive calls to this or {@link #findAll} will cancel any
+     * pending searches.
      *
      * @param find  String to find.
-     * @hide
+     * @see #setFindListener
      */
     public void findAllAsync(String find) {
         checkThread();
@@ -1333,8 +1340,9 @@
         return getFactory().getStatics().findAddress(addr);
     }
 
-    /*
-     * Clear the highlighting surrounding text matches created by findAll.
+    /**
+     * Clear the highlighting surrounding text matches created by
+     * {@link #findAll} or {@link #findAllAsync}.
      */
     public void clearMatches() {
         checkThread();
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index 4c118ac..586fcb1 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -3588,7 +3588,9 @@
     @Override
     public void findNext(boolean forward) {
         if (0 == mNativeClass) return; // client isn't initialized
-        mWebViewCore.sendMessage(EventHub.FIND_NEXT, forward ? 1 : 0);
+        if (mFindRequest != null) {
+            mWebViewCore.sendMessage(EventHub.FIND_NEXT, forward ? 1 : 0, mFindRequest);
+        }
     }
 
     /**
@@ -3605,28 +3607,26 @@
 
     private int findAllBody(String find, boolean isAsync) {
         if (0 == mNativeClass) return 0; // client isn't initialized
-        mLastFind = find;
+        mFindRequest = null;
         if (find == null) return 0;
         mWebViewCore.removeMessages(EventHub.FIND_ALL);
-        WebViewCore.FindAllRequest request = new
-            WebViewCore.FindAllRequest(find);
+        mFindRequest = new WebViewCore.FindAllRequest(find);
         if (isAsync) {
-            mWebViewCore.sendMessage(EventHub.FIND_ALL, request);
+            mWebViewCore.sendMessage(EventHub.FIND_ALL, mFindRequest);
             return 0; // no need to wait for response
         }
-        synchronized(request) {
+        synchronized(mFindRequest) {
             try {
-                mWebViewCore.sendMessageAtFrontOfQueue(EventHub.FIND_ALL,
-                    request);
-                while (request.mMatchCount == -1) {
-                    request.wait();
+                mWebViewCore.sendMessageAtFrontOfQueue(EventHub.FIND_ALL, mFindRequest);
+                while (mFindRequest.mMatchCount == -1) {
+                    mFindRequest.wait();
                 }
             }
             catch (InterruptedException e) {
                 return 0;
             }
+            return mFindRequest.mMatchCount;
         }
-        return request.mMatchCount;
     }
 
     /**
@@ -3657,7 +3657,7 @@
             return true;
         }
         if (text == null) {
-            text = mLastFind;
+            text = mFindRequest == null ? null : mFindRequest.mSearchText;
         }
         if (text != null) {
             mFindCallback.setText(text);
@@ -3683,9 +3683,8 @@
     // or not we draw the highlights for matches.
     private boolean mFindIsUp;
 
-    // Keep track of the last string sent, so we can search again when find is
-    // reopened.
-    private String mLastFind;
+    // Keep track of the last find request sent.
+    private WebViewCore.FindAllRequest mFindRequest = null;
 
     /**
      * Return the first substring consisting of the address of a physical
@@ -8476,13 +8475,27 @@
                 }
 
                 case UPDATE_MATCH_COUNT: {
-                    boolean isNewFind = mLastFind == null || !mLastFind.equals(msg.obj);
-                    if (mFindCallback != null)
-                        mFindCallback.updateMatchCount(msg.arg1, msg.arg2, isNewFind);
-                    if (mFindListener != null)
-                        mFindListener.onFindResultReceived(msg.arg1, msg.arg2, true);
+                    WebViewCore.FindAllRequest request = (WebViewCore.FindAllRequest)msg.obj;
+                    if (request == null) {
+                        if (mFindCallback != null) {
+                            mFindCallback.updateMatchCount(0, 0, true);
+                        }
+                    } else if (request == mFindRequest) {
+                        int matchCount, matchIndex;
+                        synchronized (mFindRequest) {
+                            matchCount = request.mMatchCount;
+                            matchIndex = request.mMatchIndex;
+                        }
+                        if (mFindCallback != null) {
+                            mFindCallback.updateMatchCount(matchIndex, matchCount, false);
+                        }
+                        if (mFindListener != null) {
+                            mFindListener.onFindResultReceived(matchIndex, matchCount, true);
+                        }
+                    }
                     break;
                 }
+
                 case CLEAR_CARET_HANDLE:
                     selectionDone();
                     break;
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index b4ebc09..5549d89 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -1041,9 +1041,11 @@
         public FindAllRequest(String text) {
             mSearchText = text;
             mMatchCount = -1;
+            mMatchIndex = -1;
         }
-        public String mSearchText;
+        public final String mSearchText;
         public int mMatchCount;
+        public int mMatchIndex;
     }
 
     /**
@@ -1777,21 +1779,32 @@
                             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) {
+                            FindAllRequest request = (FindAllRequest)msg.obj;
+                            if (request != null) {
+                                int matchCount = nativeFindAll(mNativeClass, request.mSearchText);
+                                int matchIndex = nativeFindNext(mNativeClass, true);
+                                synchronized (request) {
+                                    request.mMatchCount = matchCount;
+                                    request.mMatchIndex = matchIndex;
                                     request.notify();
                                 }
+                            } else {
+                                nativeFindAll(mNativeClass, null);
                             }
+                            Message.obtain(mWebViewClassic.mPrivateHandler,
+                                    WebViewClassic.UPDATE_MATCH_COUNT, request).sendToTarget();
                             break;
                         }
-                        case FIND_NEXT:
-                            nativeFindNext(mNativeClass, msg.arg1 != 0);
+                        case FIND_NEXT: {
+                            FindAllRequest request = (FindAllRequest)msg.obj;
+                            int matchIndex = nativeFindNext(mNativeClass, msg.arg1 != 0);
+                            synchronized (request) {
+                                request.mMatchIndex = matchIndex;
+                            }
+                            Message.obtain(mWebViewClassic.mPrivateHandler,
+                                    WebViewClassic.UPDATE_MATCH_COUNT, request).sendToTarget();
                             break;
+                        }
                     }
                 }
             };
@@ -2825,17 +2838,6 @@
                 .sendToTarget();
     }
 
-    // called by JNI
-    private void updateMatchCount(int matchIndex, int matchCount,
-        String findText) {
-        if (mWebViewClassic == null) {
-            return;
-        }
-        Message.obtain(mWebViewClassic.mPrivateHandler,
-                WebViewClassic.UPDATE_MATCH_COUNT, matchIndex, matchCount,
-                findText).sendToTarget();
-    }
-
     private native void nativeRevealSelection(int nativeClass);
     private native String nativeRequestLabel(int nativeClass, int framePtr,
             int nodePtr);
@@ -3086,7 +3088,7 @@
     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);
+    private native int nativeFindNext(int nativeClass, boolean forward);
 
     /**
      * Deletes editable text between two points. Note that the selection may