Loading core/java/android/webkit/AccessibilityInjector.java +42 −7 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import org.json.JSONObject; import java.net.URI; import java.net.URISyntaxException; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; Loading @@ -53,7 +54,7 @@ class AccessibilityInjector { private final WebView mWebView; // The Java objects that are exposed to JavaScript. private TextToSpeech mTextToSpeech; private TextToSpeechWrapper mTextToSpeech; private CallbackHandler mCallback; // Lazily loaded helper objects. Loading Loading @@ -349,11 +350,8 @@ class AccessibilityInjector { if (mTextToSpeech != null) { return; } final String pkgName = mContext.getPackageName(); mTextToSpeech = new TextToSpeech(mContext, null, null, pkgName + ".**webview**", true); mWebView.addJavascriptInterface(mTextToSpeech, ALIAS_TTS_JS_INTERFACE); mTextToSpeech = new TextToSpeechWrapper(mContext); mWebViewClassic.addJavascriptInterface(mTextToSpeech, ALIAS_TTS_JS_INTERFACE, false); } /** Loading @@ -377,7 +375,7 @@ class AccessibilityInjector { } mCallback = new CallbackHandler(ALIAS_TRAVERSAL_JS_INTERFACE); mWebView.addJavascriptInterface(mCallback, ALIAS_TRAVERSAL_JS_INTERFACE); mWebViewClassic.addJavascriptInterface(mCallback, ALIAS_TRAVERSAL_JS_INTERFACE, false); } private void removeCallbackApis() { Loading Loading @@ -504,9 +502,45 @@ class AccessibilityInjector { final String jsonString = mAccessibilityJSONObject.toString(); final String jsCode = String.format(ACCESSIBILITY_ANDROIDVOX_TEMPLATE, jsonString); if (mCallback == null) return false; return mCallback.performAction(mWebView, jsCode); } /** * Used to protect the TextToSpeech class, only exposing the methods we want to expose. */ private static class TextToSpeechWrapper { private TextToSpeech mTextToSpeech; public TextToSpeechWrapper(Context context) { final String pkgName = context.getPackageName(); mTextToSpeech = new TextToSpeech(context, null, null, pkgName + ".**webview**", true); } @JavascriptInterface @SuppressWarnings("unused") public boolean isSpeaking() { return mTextToSpeech.isSpeaking(); } @JavascriptInterface @SuppressWarnings("unused") public int speak(String text, int queueMode, HashMap<String, String> params) { return mTextToSpeech.speak(text, queueMode, params); } @JavascriptInterface @SuppressWarnings("unused") public int stop() { return mTextToSpeech.stop(); } @SuppressWarnings("unused") protected void shutdown() { mTextToSpeech.shutdown(); } } /** * Exposes result interface to JavaScript. */ Loading Loading @@ -603,6 +637,7 @@ class AccessibilityInjector { * @param id The result id of the request as a {@link String}. * @param result The result of the request as a {@link String}. */ @JavascriptInterface @SuppressWarnings("unused") public void onResult(String id, String result) { final long resultId; Loading core/java/android/webkit/BrowserFrame.java +40 −12 Original line number Diff line number Diff line Loading @@ -88,8 +88,19 @@ class BrowserFrame extends Handler { // Is this frame the main frame? private boolean mIsMainFrame; // Javascript interface object private class JSObject { Object object; boolean requireAnnotation; public JSObject(Object object, boolean requireAnnotation) { this.object = object; this.requireAnnotation = requireAnnotation; } } // Attached Javascript interfaces private Map<String, Object> mJavaScriptObjects; private Map<String, JSObject> mJavaScriptObjects; private Set<Object> mRemovedJavaScriptObjects; // Key store handler when Chromium HTTP stack is used. Loading Loading @@ -233,10 +244,8 @@ class BrowserFrame extends Handler { } sConfigCallback.addHandler(this); mJavaScriptObjects = javascriptInterfaces; if (mJavaScriptObjects == null) { mJavaScriptObjects = new HashMap<String, Object>(); } mJavaScriptObjects = new HashMap<String, JSObject>(); addJavaScriptObjects(javascriptInterfaces); mRemovedJavaScriptObjects = new HashSet<Object>(); mSettings = settings; Loading Loading @@ -590,15 +599,34 @@ class BrowserFrame extends Handler { Iterator<String> iter = mJavaScriptObjects.keySet().iterator(); while (iter.hasNext()) { String interfaceName = iter.next(); Object object = mJavaScriptObjects.get(interfaceName); if (object != null) { JSObject jsobject = mJavaScriptObjects.get(interfaceName); if (jsobject != null && jsobject.object != null) { nativeAddJavascriptInterface(nativeFramePointer, mJavaScriptObjects.get(interfaceName), interfaceName); jsobject.object, interfaceName, jsobject.requireAnnotation); } } mRemovedJavaScriptObjects.clear(); } /* * Add javascript objects to the internal list of objects. The default behavior * is to allow access to inherited methods (no annotation needed). This is only * used when js objects are passed through a constructor (via a hidden constructor). * */ private void addJavaScriptObjects(Map<String, Object> javascriptInterfaces) { if (javascriptInterfaces == null) return; Iterator<String> iter = javascriptInterfaces.keySet().iterator(); while (iter.hasNext()) { String interfaceName = iter.next(); Object object = javascriptInterfaces.get(interfaceName); if (object != null) { mJavaScriptObjects.put(interfaceName, new JSObject(object, false)); } } } /** * This method is called by WebCore to check whether application * wants to hijack url loading Loading @@ -616,11 +644,11 @@ class BrowserFrame extends Handler { } } public void addJavascriptInterface(Object obj, String interfaceName) { public void addJavascriptInterface(Object obj, String interfaceName, boolean requireAnnotation) { assert obj != null; removeJavascriptInterface(interfaceName); mJavaScriptObjects.put(interfaceName, obj); mJavaScriptObjects.put(interfaceName, new JSObject(obj, requireAnnotation)); } public void removeJavascriptInterface(String interfaceName) { Loading Loading @@ -1246,7 +1274,7 @@ class BrowserFrame extends Handler { * Add a javascript interface to the main frame. */ private native void nativeAddJavascriptInterface(int nativeFramePointer, Object obj, String interfaceName); Object obj, String interfaceName, boolean requireAnnotation); public native void clearCache(); Loading core/java/android/webkit/JavascriptInterface.java 0 → 100644 +33 −0 Original line number Diff line number Diff line /* * Copyright (C) 2012 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.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Annotation that allows exposing methods to JavaScript. * * @hide */ @SuppressWarnings("javadoc") @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface JavascriptInterface { } No newline at end of file core/java/android/webkit/WebViewClassic.java +8 −0 Original line number Diff line number Diff line Loading @@ -4085,12 +4085,20 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc */ @Override public void addJavascriptInterface(Object object, String name) { addJavascriptInterface(object, name, false); } /** * @hide */ public void addJavascriptInterface(Object object, String name, boolean requireAnnotation) { if (object == null) { return; } WebViewCore.JSInterfaceData arg = new WebViewCore.JSInterfaceData(); arg.mObject = object; arg.mInterfaceName = name; arg.mRequireAnnotation = requireAnnotation; mWebViewCore.sendMessage(EventHub.ADD_JS_INTERFACE, arg); } Loading core/java/android/webkit/WebViewCore.java +2 −1 Original line number Diff line number Diff line Loading @@ -839,6 +839,7 @@ public final class WebViewCore { static class JSInterfaceData { Object mObject; String mInterfaceName; boolean mRequireAnnotation; } static class JSKeyData { Loading Loading @@ -1508,7 +1509,7 @@ public final class WebViewCore { case ADD_JS_INTERFACE: JSInterfaceData jsData = (JSInterfaceData) msg.obj; mBrowserFrame.addJavascriptInterface(jsData.mObject, jsData.mInterfaceName); jsData.mInterfaceName, jsData.mRequireAnnotation); break; case REMOVE_JS_INTERFACE: Loading Loading
core/java/android/webkit/AccessibilityInjector.java +42 −7 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import org.json.JSONObject; import java.net.URI; import java.net.URISyntaxException; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; Loading @@ -53,7 +54,7 @@ class AccessibilityInjector { private final WebView mWebView; // The Java objects that are exposed to JavaScript. private TextToSpeech mTextToSpeech; private TextToSpeechWrapper mTextToSpeech; private CallbackHandler mCallback; // Lazily loaded helper objects. Loading Loading @@ -349,11 +350,8 @@ class AccessibilityInjector { if (mTextToSpeech != null) { return; } final String pkgName = mContext.getPackageName(); mTextToSpeech = new TextToSpeech(mContext, null, null, pkgName + ".**webview**", true); mWebView.addJavascriptInterface(mTextToSpeech, ALIAS_TTS_JS_INTERFACE); mTextToSpeech = new TextToSpeechWrapper(mContext); mWebViewClassic.addJavascriptInterface(mTextToSpeech, ALIAS_TTS_JS_INTERFACE, false); } /** Loading @@ -377,7 +375,7 @@ class AccessibilityInjector { } mCallback = new CallbackHandler(ALIAS_TRAVERSAL_JS_INTERFACE); mWebView.addJavascriptInterface(mCallback, ALIAS_TRAVERSAL_JS_INTERFACE); mWebViewClassic.addJavascriptInterface(mCallback, ALIAS_TRAVERSAL_JS_INTERFACE, false); } private void removeCallbackApis() { Loading Loading @@ -504,9 +502,45 @@ class AccessibilityInjector { final String jsonString = mAccessibilityJSONObject.toString(); final String jsCode = String.format(ACCESSIBILITY_ANDROIDVOX_TEMPLATE, jsonString); if (mCallback == null) return false; return mCallback.performAction(mWebView, jsCode); } /** * Used to protect the TextToSpeech class, only exposing the methods we want to expose. */ private static class TextToSpeechWrapper { private TextToSpeech mTextToSpeech; public TextToSpeechWrapper(Context context) { final String pkgName = context.getPackageName(); mTextToSpeech = new TextToSpeech(context, null, null, pkgName + ".**webview**", true); } @JavascriptInterface @SuppressWarnings("unused") public boolean isSpeaking() { return mTextToSpeech.isSpeaking(); } @JavascriptInterface @SuppressWarnings("unused") public int speak(String text, int queueMode, HashMap<String, String> params) { return mTextToSpeech.speak(text, queueMode, params); } @JavascriptInterface @SuppressWarnings("unused") public int stop() { return mTextToSpeech.stop(); } @SuppressWarnings("unused") protected void shutdown() { mTextToSpeech.shutdown(); } } /** * Exposes result interface to JavaScript. */ Loading Loading @@ -603,6 +637,7 @@ class AccessibilityInjector { * @param id The result id of the request as a {@link String}. * @param result The result of the request as a {@link String}. */ @JavascriptInterface @SuppressWarnings("unused") public void onResult(String id, String result) { final long resultId; Loading
core/java/android/webkit/BrowserFrame.java +40 −12 Original line number Diff line number Diff line Loading @@ -88,8 +88,19 @@ class BrowserFrame extends Handler { // Is this frame the main frame? private boolean mIsMainFrame; // Javascript interface object private class JSObject { Object object; boolean requireAnnotation; public JSObject(Object object, boolean requireAnnotation) { this.object = object; this.requireAnnotation = requireAnnotation; } } // Attached Javascript interfaces private Map<String, Object> mJavaScriptObjects; private Map<String, JSObject> mJavaScriptObjects; private Set<Object> mRemovedJavaScriptObjects; // Key store handler when Chromium HTTP stack is used. Loading Loading @@ -233,10 +244,8 @@ class BrowserFrame extends Handler { } sConfigCallback.addHandler(this); mJavaScriptObjects = javascriptInterfaces; if (mJavaScriptObjects == null) { mJavaScriptObjects = new HashMap<String, Object>(); } mJavaScriptObjects = new HashMap<String, JSObject>(); addJavaScriptObjects(javascriptInterfaces); mRemovedJavaScriptObjects = new HashSet<Object>(); mSettings = settings; Loading Loading @@ -590,15 +599,34 @@ class BrowserFrame extends Handler { Iterator<String> iter = mJavaScriptObjects.keySet().iterator(); while (iter.hasNext()) { String interfaceName = iter.next(); Object object = mJavaScriptObjects.get(interfaceName); if (object != null) { JSObject jsobject = mJavaScriptObjects.get(interfaceName); if (jsobject != null && jsobject.object != null) { nativeAddJavascriptInterface(nativeFramePointer, mJavaScriptObjects.get(interfaceName), interfaceName); jsobject.object, interfaceName, jsobject.requireAnnotation); } } mRemovedJavaScriptObjects.clear(); } /* * Add javascript objects to the internal list of objects. The default behavior * is to allow access to inherited methods (no annotation needed). This is only * used when js objects are passed through a constructor (via a hidden constructor). * */ private void addJavaScriptObjects(Map<String, Object> javascriptInterfaces) { if (javascriptInterfaces == null) return; Iterator<String> iter = javascriptInterfaces.keySet().iterator(); while (iter.hasNext()) { String interfaceName = iter.next(); Object object = javascriptInterfaces.get(interfaceName); if (object != null) { mJavaScriptObjects.put(interfaceName, new JSObject(object, false)); } } } /** * This method is called by WebCore to check whether application * wants to hijack url loading Loading @@ -616,11 +644,11 @@ class BrowserFrame extends Handler { } } public void addJavascriptInterface(Object obj, String interfaceName) { public void addJavascriptInterface(Object obj, String interfaceName, boolean requireAnnotation) { assert obj != null; removeJavascriptInterface(interfaceName); mJavaScriptObjects.put(interfaceName, obj); mJavaScriptObjects.put(interfaceName, new JSObject(obj, requireAnnotation)); } public void removeJavascriptInterface(String interfaceName) { Loading Loading @@ -1246,7 +1274,7 @@ class BrowserFrame extends Handler { * Add a javascript interface to the main frame. */ private native void nativeAddJavascriptInterface(int nativeFramePointer, Object obj, String interfaceName); Object obj, String interfaceName, boolean requireAnnotation); public native void clearCache(); Loading
core/java/android/webkit/JavascriptInterface.java 0 → 100644 +33 −0 Original line number Diff line number Diff line /* * Copyright (C) 2012 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.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Annotation that allows exposing methods to JavaScript. * * @hide */ @SuppressWarnings("javadoc") @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface JavascriptInterface { } No newline at end of file
core/java/android/webkit/WebViewClassic.java +8 −0 Original line number Diff line number Diff line Loading @@ -4085,12 +4085,20 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc */ @Override public void addJavascriptInterface(Object object, String name) { addJavascriptInterface(object, name, false); } /** * @hide */ public void addJavascriptInterface(Object object, String name, boolean requireAnnotation) { if (object == null) { return; } WebViewCore.JSInterfaceData arg = new WebViewCore.JSInterfaceData(); arg.mObject = object; arg.mInterfaceName = name; arg.mRequireAnnotation = requireAnnotation; mWebViewCore.sendMessage(EventHub.ADD_JS_INTERFACE, arg); } Loading
core/java/android/webkit/WebViewCore.java +2 −1 Original line number Diff line number Diff line Loading @@ -839,6 +839,7 @@ public final class WebViewCore { static class JSInterfaceData { Object mObject; String mInterfaceName; boolean mRequireAnnotation; } static class JSKeyData { Loading Loading @@ -1508,7 +1509,7 @@ public final class WebViewCore { case ADD_JS_INTERFACE: JSInterfaceData jsData = (JSInterfaceData) msg.obj; mBrowserFrame.addJavascriptInterface(jsData.mObject, jsData.mInterfaceName); jsData.mInterfaceName, jsData.mRequireAnnotation); break; case REMOVE_JS_INTERFACE: Loading