Merge "DO NOT MERGE Control access to inherited methods of jsinterface objects" into jb-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
c2e3be5a8b
@ -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;
|
||||
|
@ -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();
|
||||
|
||||
|
33
core/java/android/webkit/JavascriptInterface.java
Normal file
33
core/java/android/webkit/JavascriptInterface.java
Normal 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 {
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
|
Reference in New Issue
Block a user