Merge "DO NOT MERGE Control access to inherited methods of jsinterface objects" into jb-dev

This commit is contained in:
Geremy Condra
2012-10-09 21:32:08 -07:00
committed by Android (Google) Code Review
5 changed files with 125 additions and 20 deletions

View File

@ -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;
@ -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.
@ -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);
}
/**
@ -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() {
@ -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.
*/
@ -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;

View File

@ -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.
@ -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;
@ -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
@ -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) {
@ -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();

View File

@ -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 {
}

View File

@ -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);
}

View File

@ -839,6 +839,7 @@ public final class WebViewCore {
static class JSInterfaceData {
Object mObject;
String mInterfaceName;
boolean mRequireAnnotation;
}
static class JSKeyData {
@ -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: