diff options
author | Selim Gurun <sgurun@google.com> | 2012-09-04 16:45:53 -0700 |
---|---|---|
committer | Selim Gurun <sgurun@google.com> | 2012-10-05 10:07:29 -0700 |
commit | 66019c85693ec026e3826eb4b9a519a716f8594e (patch) | |
tree | 9f9dccd871003168b70ce33c4ddf3fb098ee0452 | |
parent | 154feb1e6a05cad89e2fe0ee188071b280c5f3e9 (diff) | |
download | base-66019c85693ec026e3826eb4b9a519a716f8594e.tar.gz |
DO NOT MERGE Control access to inherited methods of jsinterface objects
Bug: 7073422
Create the plumbing to use an annotation to allow access to
inherited methods of jsinterface objects. The default webview
behavior has not changed yet. However internally an a flag is
introduced to restrict javascript access to methods that have an annotation.
Change-Id: I0d8091da9b0aaecc0519863cf92b1fec2385da97
-rw-r--r-- | core/java/android/webkit/BrowserFrame.java | 50 | ||||
-rw-r--r-- | core/java/android/webkit/JavascriptInterface.java | 33 | ||||
-rw-r--r-- | core/java/android/webkit/WebView.java | 50 | ||||
-rw-r--r-- | core/java/android/webkit/WebViewCore.java | 3 |
4 files changed, 116 insertions, 20 deletions
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java index bb86269404b4..43e87960969a 100644 --- a/core/java/android/webkit/BrowserFrame.java +++ b/core/java/android/webkit/BrowserFrame.java @@ -87,8 +87,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. @@ -232,10 +243,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; @@ -603,15 +612,32 @@ 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 @@ -629,11 +655,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) { @@ -1344,7 +1370,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); /** * Enable or disable the native cache. diff --git a/core/java/android/webkit/JavascriptInterface.java b/core/java/android/webkit/JavascriptInterface.java new file mode 100644 index 000000000000..a5312a2c0bf0 --- /dev/null +++ b/core/java/android/webkit/JavascriptInterface.java @@ -0,0 +1,33 @@ +/* + * 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 diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 5c833e4d920e..bb029e6a9a75 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -428,6 +428,40 @@ public class WebView extends AbsoluteLayout } + /** + * A wrapper around text to speech. + */ + private static class TextToSpeechWrapper { + private TextToSpeech mTextToSpeech; + public TextToSpeechWrapper(Context context) { + final String pkgName = context.getPackageName(); + mTextToSpeech = new TextToSpeech(context, null, null, pkgName + ".**webview**"); + } + + @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(); + } + } + // A final CallbackProxy shared by WebViewCore and BrowserFrame. private final CallbackProxy mCallbackProxy; @@ -865,7 +899,7 @@ public class WebView extends AbsoluteLayout private static final String PATTERN_MATCH_AXS_URL_PARAMETER = "(\\?axs=(0|1))|(&axs=(0|1))"; // TextToSpeech instance exposed to JavaScript to the injected screenreader. - private TextToSpeech mTextToSpeech; + private TextToSpeechWrapper mTextToSpeech; // variable to cache the above pattern in case accessibility is enabled. private Pattern mMatchAxsUrlParameterPattern; @@ -1308,12 +1342,8 @@ public class WebView extends AbsoluteLayout // exposing the TTS for now ... final Context ctx = getContext(); if (ctx != null) { - final String packageName = ctx.getPackageName(); - if (packageName != null) { - mTextToSpeech = new TextToSpeech(getContext(), null, null, - packageName + ".**webview**"); - addJavascriptInterface(mTextToSpeech, ALIAS_ACCESSIBILITY_JS_INTERFACE); - } + mTextToSpeech = new TextToSpeechWrapper(ctx); + addJavascriptInterface(mTextToSpeech, ALIAS_ACCESSIBILITY_JS_INTERFACE, true); } } } @@ -4110,6 +4140,11 @@ public class WebView extends AbsoluteLayout * JavaScript. */ public void addJavascriptInterface(Object obj, String interfaceName) { + addJavascriptInterface(obj, interfaceName, false); + } + + private void addJavascriptInterface(Object obj, String interfaceName, + boolean requireAnnotation) { checkThread(); if (obj == null) { return; @@ -4117,6 +4152,7 @@ public class WebView extends AbsoluteLayout WebViewCore.JSInterfaceData arg = new WebViewCore.JSInterfaceData(); arg.mObject = obj; arg.mInterfaceName = interfaceName; + arg.mRequireAnnotation = requireAnnotation; mWebViewCore.sendMessage(EventHub.ADD_JS_INTERFACE, arg); } diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java index 2d15afb5ba46..361d676120de 100644 --- a/core/java/android/webkit/WebViewCore.java +++ b/core/java/android/webkit/WebViewCore.java @@ -755,6 +755,7 @@ public final class WebViewCore { static class JSInterfaceData { Object mObject; String mInterfaceName; + boolean mRequireAnnotation; } static class JSKeyData { @@ -1411,7 +1412,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: |