summaryrefslogtreecommitdiff
path: root/core/java/android/webkit/SearchBoxImpl.java
diff options
context:
space:
mode:
authorNarayan Kamath <narayan@google.com>2011-02-22 12:05:34 +0000
committerNarayan Kamath <narayan@google.com>2011-03-01 11:11:00 +0000
commit9497c5f8c4bc7c47789e5ccde01179abc31ffeb2 (patch)
tree3f5080139a3fd6809df6b7ce077e885def2d7e36 /core/java/android/webkit/SearchBoxImpl.java
parent43cdf9b4191e18b5a4d646d23b06438c0e10b8dd (diff)
A Java implementation of the SearchBox API.
Implemented as a Java bridge object and a JS adapter. Works on both V8 and JSC. Change-Id: I8a4268fb3c6688b5ece9e27c11724c0776017255
Diffstat (limited to 'core/java/android/webkit/SearchBoxImpl.java')
-rw-r--r--core/java/android/webkit/SearchBoxImpl.java227
1 files changed, 227 insertions, 0 deletions
diff --git a/core/java/android/webkit/SearchBoxImpl.java b/core/java/android/webkit/SearchBoxImpl.java
new file mode 100644
index 000000000000..480f5d7a5b44
--- /dev/null
+++ b/core/java/android/webkit/SearchBoxImpl.java
@@ -0,0 +1,227 @@
+/*
+ * 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.util.Log;
+import android.webkit.WebViewCore.EventHub;
+
+import java.util.ArrayList;
+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 = %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(); }";
+
+ private final List<SearchBoxListener> mListeners;
+ private final WebViewCore mWebViewCore;
+ private final CallbackProxy mCallbackProxy;
+
+ SearchBoxImpl(WebViewCore webViewCore, CallbackProxy callbackProxy) {
+ mListeners = new ArrayList<SearchBoxListener>();
+ mWebViewCore = webViewCore;
+ mCallbackProxy = callbackProxy;
+ }
+
+ @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() {
+ dispatchEvent("change");
+ }
+
+ @Override
+ public void onsubmit() {
+ dispatchEvent("submit");
+ }
+
+ @Override
+ public void onresize() {
+ dispatchEvent("resize");
+ }
+
+ @Override
+ public void oncancel() {
+ dispatchEvent("cancel");
+ }
+
+ private void dispatchEvent(String eventName) {
+ final String js = String.format(DISPATCH_EVENT_SCRIPT, eventName);
+ 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);
+ }
+ }
+
+ // This is used as a hackish alternative to javascript escaping.
+ // There appears to be no such functionality in the core framework.
+ private 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);
+ }
+ }
+ }
+}