Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 06ee8cde authored by Selim Gurun's avatar Selim Gurun Committed by Android (Google) Code Review
Browse files

Merge "Remove defunct searchbox implementation from webview." into jb-mr1-dev

parents f625436c 0e9292b9
Loading
Loading
Loading
Loading
+0 −9
Original line number Diff line number Diff line
@@ -107,9 +107,6 @@ class BrowserFrame extends Handler {
    // Key store handler when Chromium HTTP stack is used.
    private KeyStoreHandler mKeyStoreHandler = null;

    // Implementation of the searchbox API.
    private final SearchBoxImpl mSearchBox;

    // message ids
    // a message posted when a frame loading is completed
    static final int FRAME_COMPLETED = 1001;
@@ -255,8 +252,6 @@ class BrowserFrame extends Handler {
        mDatabase = WebViewDatabaseClassic.getInstance(appContext);
        mWebViewCore = w;

        mSearchBox = new SearchBoxImpl(mWebViewCore, mCallbackProxy);

        AssetManager am = context.getAssets();
        nativeCreateFrame(w, am, proxy.getBackForwardList());

@@ -1217,10 +1212,6 @@ class BrowserFrame extends Handler {
        }
    }

    /*package*/ SearchBox getSearchBox() {
        return mSearchBox;
    }

    /**
     * Called by JNI when processing the X-Auto-Login header.
     */
+0 −47
Original line number Diff line number Diff line
@@ -117,11 +117,8 @@ class CallbackProxy extends Handler {
    private static final int ADD_HISTORY_ITEM                     = 135;
    private static final int HISTORY_INDEX_CHANGED                = 136;
    private static final int AUTH_CREDENTIALS                     = 137;
    private static final int NOTIFY_SEARCHBOX_LISTENERS           = 139;
    private static final int AUTO_LOGIN                           = 140;
    private static final int CLIENT_CERT_REQUEST                  = 141;
    private static final int SEARCHBOX_IS_SUPPORTED_CALLBACK      = 142;
    private static final int SEARCHBOX_DISPATCH_COMPLETE_CALLBACK = 143;
    private static final int PROCEEDED_AFTER_SSL_ERROR            = 144;

    // Message triggered by the client to resume execution
@@ -871,14 +868,6 @@ class CallbackProxy extends Handler {
                        host, realm, username, password);
                break;
            }
            case NOTIFY_SEARCHBOX_LISTENERS: {
                SearchBoxImpl searchBox = (SearchBoxImpl) mWebView.getSearchBox();

                @SuppressWarnings("unchecked")
                List<String> suggestions = (List<String>) msg.obj;
                searchBox.handleSuggestions(msg.getData().getString("query"), suggestions);
                break;
            }
            case AUTO_LOGIN: {
                if (mWebViewClient != null) {
                    String realm = msg.getData().getString("realm");
@@ -889,19 +878,6 @@ class CallbackProxy extends Handler {
                }
                break;
            }
            case SEARCHBOX_IS_SUPPORTED_CALLBACK: {
                SearchBoxImpl searchBox = (SearchBoxImpl) mWebView.getSearchBox();
                Boolean supported = (Boolean) msg.obj;
                searchBox.handleIsSupportedCallback(supported);
                break;
            }
            case SEARCHBOX_DISPATCH_COMPLETE_CALLBACK: {
                SearchBoxImpl searchBox = (SearchBoxImpl) mWebView.getSearchBox();
                Boolean success = (Boolean) msg.obj;
                searchBox.handleDispatchCompleteCallback(msg.getData().getString("function"),
                        msg.getData().getInt("id"), success);
                break;
            }
        }
    }

@@ -1629,29 +1605,6 @@ class CallbackProxy extends Handler {
        return mContext instanceof Activity;
    }

    void onSearchboxSuggestionsReceived(String query, List<String> suggestions) {
        Message msg = obtainMessage(NOTIFY_SEARCHBOX_LISTENERS);
        msg.obj = suggestions;
        msg.getData().putString("query", query);

        sendMessage(msg);
    }

    void onIsSupportedCallback(boolean isSupported) {
        Message msg = obtainMessage(SEARCHBOX_IS_SUPPORTED_CALLBACK);
        msg.obj = Boolean.valueOf(isSupported);
        sendMessage(msg);
    }

    void onSearchboxDispatchCompleteCallback(String function, int id, boolean success) {
        Message msg = obtainMessage(SEARCHBOX_DISPATCH_COMPLETE_CALLBACK);
        msg.obj = Boolean.valueOf(success);
        msg.getData().putString("function", function);
        msg.getData().putInt("id", id);

        sendMessage(msg);
    }

    private synchronized void sendMessageToUiThreadSync(Message msg) {
        sendMessage(msg);
        WebCoreThreadWatchdog.pause();
+0 −109
Original line number Diff line number Diff line
/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package android.webkit;

import java.util.List;

/**
 * Defines the interaction between the browser/renderer and the page running on
 * a given WebView frame, if the page supports the chromium SearchBox API.
 *
 * http://dev.chromium.org/searchbox
 *
 * The browser or container app can query the page for search results using
 * SearchBox.query() and receive suggestions by registering a listener on the
 * SearchBox object.
 *
 * @hide
 */
public interface SearchBox {
    /**
     * Sets the current searchbox query. Note that the caller must call
     * onchange() to ensure that the search page processes this query.
     */
    void setQuery(String query);

    /**
     * Verbatim is true if the caller suggests that the search page
     * treat the current query as a verbatim search query (as opposed to a
     * partially typed search query). As with setQuery, onchange() must be
     * called to ensure that the search page processes the query.
     */
    void setVerbatim(boolean verbatim);

    /**
     * These attributes must contain the offset to the characters that immediately
     * follow the start and end of the selection in the search box. If there is
     * no such selection, then both selectionStart and selectionEnd must be the offset
     * to the character that immediately follows the text entry cursor. In the case
     * that there is no explicit text entry cursor, the cursor is
     * implicitly at the end of the input.
     */
    void setSelection(int selectionStart, int selectionEnd);

    /**
     * Sets the dimensions of the view (if any) that overlaps the current
     * window object. This is to ensure that the page renders results in
     * a manner that allows them to not be obscured by such a view. Note
     * that a call to onresize() is required if these dimensions change.
     */
    void setDimensions(int x, int y, int width, int height);

    /**
     * Notify the search page of any changes to the searchbox. Such as
     * a change in the typed query (onchange), the user commiting a given query
     * (onsubmit), or a change in size of a suggestions dropdown (onresize).
     *
     * @param listener an optional listener to notify of the success of the operation,
     *      indicating if the javascript function existed and could be called or not.
     *      It will be called on the UI thread.
     */
    void onchange(SearchBoxListener listener);
    void onsubmit(SearchBoxListener listener);
    void onresize(SearchBoxListener listener);
    void oncancel(SearchBoxListener listener);

    /**
     * Add and remove listeners to the given Searchbox. Listeners are notified
     * of any suggestions to the query that the underlying search engine might
     * provide.
     */
    void addSearchBoxListener(SearchBoxListener l);
    void removeSearchBoxListener(SearchBoxListener l);

    /**
     * Indicates if the searchbox API is supported in the current page.
     */
    void isSupported(IsSupportedCallback callback);

    /**
     * Listeners (if any) will be called on the thread that created the
     * webview.
     */
    public abstract class SearchBoxListener {
        public void onSuggestionsReceived(String query, List<String> suggestions) {}
        public void onChangeComplete(boolean called) {}
        public void onSubmitComplete(boolean called) {}
        public void onResizeComplete(boolean called) {}
        public void onCancelComplete(boolean called) {}
    }

    interface IsSupportedCallback {
        void searchBoxIsSupported(boolean supported);
    }
}
+0 −304
Original line number Diff line number Diff line
/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.webkit;

import android.text.TextUtils;
import android.util.Log;
import android.webkit.WebViewCore.EventHub;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONStringer;

/**
 * The default implementation of the SearchBox interface. Implemented
 * as a java bridge object and a javascript adapter that is called into
 * by the page hosted in the frame.
 */
final class SearchBoxImpl implements SearchBox {
    private static final String TAG = "WebKit.SearchBoxImpl";

    /* package */ static final String JS_INTERFACE_NAME = "searchBoxJavaBridge_";

    /* package */ static final String JS_BRIDGE
            = "(function()"
            + "{"
            + "if (!window.chrome) {"
            + "  window.chrome = {};"
            + "}"
            + "if (!window.chrome.searchBox) {"
            + "  var sb = window.chrome.searchBox = {};"
            + "  sb.setSuggestions = function(suggestions) {"
            + "    if (window.searchBoxJavaBridge_) {"
            + "      window.searchBoxJavaBridge_.setSuggestions(JSON.stringify(suggestions));"
            + "    }"
            + "  };"
            + "  sb.setValue = function(valueArray) { sb.value = valueArray[0]; };"
            + "  sb.value = '';"
            + "  sb.x = 0;"
            + "  sb.y = 0;"
            + "  sb.width = 0;"
            + "  sb.height = 0;"
            + "  sb.selectionStart = 0;"
            + "  sb.selectionEnd = 0;"
            + "  sb.verbatim = false;"
            + "}"
            + "})();";

    private static final String SET_QUERY_SCRIPT
            = "if (window.chrome && window.chrome.searchBox) {"
            + "  window.chrome.searchBox.setValue(%s);"
            + "}";

    private static final String SET_VERBATIM_SCRIPT
            =  "if (window.chrome && window.chrome.searchBox) {"
            + "  window.chrome.searchBox.verbatim = %1$s;"
            + "}";

    private static final String SET_SELECTION_SCRIPT
            = "if (window.chrome && window.chrome.searchBox) {"
            + "  var f = window.chrome.searchBox;"
            + "  f.selectionStart = %d"
            + "  f.selectionEnd = %d"
            + "}";

    private static final String SET_DIMENSIONS_SCRIPT
            = "if (window.chrome && window.chrome.searchBox) { "
            + "  var f = window.chrome.searchBox;"
            + "  f.x = %d;"
            + "  f.y = %d;"
            + "  f.width = %d;"
            + "  f.height = %d;"
            + "}";

    private static final String DISPATCH_EVENT_SCRIPT
            = "if (window.chrome && window.chrome.searchBox && window.chrome.searchBox.on%1$s) {"
            + "  window.chrome.searchBox.on%1$s();"
            + "  window.searchBoxJavaBridge_.dispatchCompleteCallback('%1$s', %2$d, true);"
            + "} else {"
            + "  window.searchBoxJavaBridge_.dispatchCompleteCallback('%1$s', %2$d, false);"
            + "}";

    private static final String EVENT_CHANGE = "change";
    private static final String EVENT_SUBMIT = "submit";
    private static final String EVENT_RESIZE = "resize";
    private static final String EVENT_CANCEL = "cancel";

    private static final String IS_SUPPORTED_SCRIPT
            = "if (window.searchBoxJavaBridge_) {"
            + "  if (window.chrome && window.chrome.sv) {"
            + "    window.searchBoxJavaBridge_.isSupportedCallback(true);"
            + "  } else {"
            + "    window.searchBoxJavaBridge_.isSupportedCallback(false);"
            + "  }}";

    private final List<SearchBoxListener> mListeners;
    private final WebViewCore mWebViewCore;
    private final CallbackProxy mCallbackProxy;
    private IsSupportedCallback mSupportedCallback;
    private int mNextEventId = 1;
    private final HashMap<Integer, SearchBoxListener> mEventCallbacks;

    SearchBoxImpl(WebViewCore webViewCore, CallbackProxy callbackProxy) {
        mListeners = new ArrayList<SearchBoxListener>();
        mWebViewCore = webViewCore;
        mCallbackProxy = callbackProxy;
        mEventCallbacks = new HashMap<Integer, SearchBoxListener>();
    }

    @Override
    public void setQuery(String query) {
        final String formattedQuery = jsonSerialize(query);
        if (formattedQuery != null) {
            final String js = String.format(SET_QUERY_SCRIPT, formattedQuery);
            dispatchJs(js);
        }
    }

    @Override
    public void setVerbatim(boolean verbatim) {
        final String js = String.format(SET_VERBATIM_SCRIPT, String.valueOf(verbatim));
        dispatchJs(js);
    }


    @Override
    public void setSelection(int selectionStart, int selectionEnd) {
        final String js = String.format(SET_SELECTION_SCRIPT, selectionStart, selectionEnd);
        dispatchJs(js);
    }

    @Override
    public void setDimensions(int x, int y, int width, int height) {
        final String js = String.format(SET_DIMENSIONS_SCRIPT, x, y, width, height);
        dispatchJs(js);
    }

    @Override
    public void onchange(SearchBoxListener callback) {
        dispatchEvent(EVENT_CHANGE, callback);
    }

    @Override
    public void onsubmit(SearchBoxListener callback) {
        dispatchEvent(EVENT_SUBMIT, callback);
    }

    @Override
    public void onresize(SearchBoxListener callback) {
        dispatchEvent(EVENT_RESIZE, callback);
    }

    @Override
    public void oncancel(SearchBoxListener callback) {
        dispatchEvent(EVENT_CANCEL, callback);
    }

    private void dispatchEvent(String eventName, SearchBoxListener callback) {
        int eventId;
        if (callback != null) {
            synchronized(this) {
                eventId = mNextEventId++;
                mEventCallbacks.put(eventId, callback);
            }
        } else {
            eventId = 0;
        }
        final String js = String.format(DISPATCH_EVENT_SCRIPT, eventName, eventId);
        dispatchJs(js);
    }

    private void dispatchJs(String js) {
        mWebViewCore.sendMessage(EventHub.EXECUTE_JS, js);
    }

    @Override
    public void addSearchBoxListener(SearchBoxListener l) {
        synchronized (mListeners) {
            mListeners.add(l);
        }
    }

    @Override
    public void removeSearchBoxListener(SearchBoxListener l) {
        synchronized (mListeners) {
            mListeners.remove(l);
        }
    }

    @Override
    public void isSupported(IsSupportedCallback callback) {
        mSupportedCallback = callback;
        dispatchJs(IS_SUPPORTED_SCRIPT);
    }

    // Called by Javascript through the Java bridge.
    public void isSupportedCallback(boolean isSupported) {
        mCallbackProxy.onIsSupportedCallback(isSupported);
    }

    public void handleIsSupportedCallback(boolean isSupported) {
        IsSupportedCallback callback = mSupportedCallback;
        mSupportedCallback = null;
        if (callback != null) {
            callback.searchBoxIsSupported(isSupported);
        }
    }

    // Called by Javascript through the Java bridge.
    public void dispatchCompleteCallback(String function, int id, boolean successful) {
        mCallbackProxy.onSearchboxDispatchCompleteCallback(function, id, successful);
    }

    public void handleDispatchCompleteCallback(String function, int id, boolean successful) {
        if (id != 0) {
            SearchBoxListener listener;
            synchronized(this) {
                listener = mEventCallbacks.get(id);
                mEventCallbacks.remove(id);
            }
            if (listener != null) {
                if (TextUtils.equals(EVENT_CHANGE, function)) {
                    listener.onChangeComplete(successful);
                } else if (TextUtils.equals(EVENT_SUBMIT, function)) {
                    listener.onSubmitComplete(successful);
                } else if (TextUtils.equals(EVENT_RESIZE, function)) {
                    listener.onResizeComplete(successful);
                } else if (TextUtils.equals(EVENT_CANCEL, function)) {
                    listener.onCancelComplete(successful);
                }
            }
        }
    }

    // This is used as a hackish alternative to javascript escaping.
    // There appears to be no such functionality in the core framework.
    private static String jsonSerialize(String query) {
        JSONStringer stringer = new JSONStringer();
        try {
            stringer.array().value(query).endArray();
        } catch (JSONException e) {
            Log.w(TAG, "Error serializing query : " + query);
            return null;
        }
        return stringer.toString();
    }

    // Called by Javascript through the Java bridge.
    public void setSuggestions(String jsonArguments) {
        if (jsonArguments == null) {
            return;
        }

        String query = null;
        List<String> suggestions = new ArrayList<String>();
        try {
            JSONObject suggestionsJson = new JSONObject(jsonArguments);
            query = suggestionsJson.getString("query");

            final JSONArray suggestionsArray = suggestionsJson.getJSONArray("suggestions");
            for (int i = 0; i < suggestionsArray.length(); ++i) {
                final JSONObject suggestion = suggestionsArray.getJSONObject(i);
                final String value = suggestion.getString("value");
                if (value != null) {
                    suggestions.add(value);
                }
                // We currently ignore the "type" of the suggestion. This isn't
                // documented anywhere in the API documents.
                // final String type = suggestions.getString("type");
            }
        } catch (JSONException je) {
            Log.w(TAG, "Error parsing json [" + jsonArguments + "], exception = " + je);
            return;
        }

        mCallbackProxy.onSearchboxSuggestionsReceived(query, suggestions);
    }

    /* package */ void handleSuggestions(String query, List<String> suggestions) {
        synchronized (mListeners) {
            for (int i = mListeners.size() - 1; i >= 0; i--) {
                mListeners.get(i).onSuggestionsReceived(query, suggestions);
            }
        }
    }
}
+1 −4
Original line number Diff line number Diff line
@@ -5367,11 +5367,8 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
     * This is an implementation detail.
     */
    public SearchBox getSearchBox() {
        if ((mWebViewCore == null) || (mWebViewCore.getBrowserFrame() == null)) {
        return null;
    }
        return mWebViewCore.getBrowserFrame().getSearchBox();
    }

    /**
     * Returns the currently highlighted text as a string.