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.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
@ -53,7 +54,7 @@ class AccessibilityInjector {
|
|||||||
private final WebView mWebView;
|
private final WebView mWebView;
|
||||||
|
|
||||||
// The Java objects that are exposed to JavaScript.
|
// The Java objects that are exposed to JavaScript.
|
||||||
private TextToSpeech mTextToSpeech;
|
private TextToSpeechWrapper mTextToSpeech;
|
||||||
private CallbackHandler mCallback;
|
private CallbackHandler mCallback;
|
||||||
|
|
||||||
// Lazily loaded helper objects.
|
// Lazily loaded helper objects.
|
||||||
@ -349,11 +350,8 @@ class AccessibilityInjector {
|
|||||||
if (mTextToSpeech != null) {
|
if (mTextToSpeech != null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
mTextToSpeech = new TextToSpeechWrapper(mContext);
|
||||||
final String pkgName = mContext.getPackageName();
|
mWebViewClassic.addJavascriptInterface(mTextToSpeech, ALIAS_TTS_JS_INTERFACE, false);
|
||||||
|
|
||||||
mTextToSpeech = new TextToSpeech(mContext, null, null, pkgName + ".**webview**", true);
|
|
||||||
mWebView.addJavascriptInterface(mTextToSpeech, ALIAS_TTS_JS_INTERFACE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -377,7 +375,7 @@ class AccessibilityInjector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mCallback = new CallbackHandler(ALIAS_TRAVERSAL_JS_INTERFACE);
|
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() {
|
private void removeCallbackApis() {
|
||||||
@ -504,9 +502,45 @@ class AccessibilityInjector {
|
|||||||
|
|
||||||
final String jsonString = mAccessibilityJSONObject.toString();
|
final String jsonString = mAccessibilityJSONObject.toString();
|
||||||
final String jsCode = String.format(ACCESSIBILITY_ANDROIDVOX_TEMPLATE, jsonString);
|
final String jsCode = String.format(ACCESSIBILITY_ANDROIDVOX_TEMPLATE, jsonString);
|
||||||
|
if (mCallback == null) return false;
|
||||||
return mCallback.performAction(mWebView, jsCode);
|
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.
|
* Exposes result interface to JavaScript.
|
||||||
*/
|
*/
|
||||||
@ -603,6 +637,7 @@ class AccessibilityInjector {
|
|||||||
* @param id The result id of the request as a {@link String}.
|
* @param id The result id of the request as a {@link String}.
|
||||||
* @param result The result of the request as a {@link String}.
|
* @param result The result of the request as a {@link String}.
|
||||||
*/
|
*/
|
||||||
|
@JavascriptInterface
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public void onResult(String id, String result) {
|
public void onResult(String id, String result) {
|
||||||
final long resultId;
|
final long resultId;
|
||||||
|
@ -88,8 +88,19 @@ class BrowserFrame extends Handler {
|
|||||||
// Is this frame the main frame?
|
// Is this frame the main frame?
|
||||||
private boolean mIsMainFrame;
|
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
|
// Attached Javascript interfaces
|
||||||
private Map<String, Object> mJavaScriptObjects;
|
private Map<String, JSObject> mJavaScriptObjects;
|
||||||
private Set<Object> mRemovedJavaScriptObjects;
|
private Set<Object> mRemovedJavaScriptObjects;
|
||||||
|
|
||||||
// Key store handler when Chromium HTTP stack is used.
|
// Key store handler when Chromium HTTP stack is used.
|
||||||
@ -233,10 +244,8 @@ class BrowserFrame extends Handler {
|
|||||||
}
|
}
|
||||||
sConfigCallback.addHandler(this);
|
sConfigCallback.addHandler(this);
|
||||||
|
|
||||||
mJavaScriptObjects = javascriptInterfaces;
|
mJavaScriptObjects = new HashMap<String, JSObject>();
|
||||||
if (mJavaScriptObjects == null) {
|
addJavaScriptObjects(javascriptInterfaces);
|
||||||
mJavaScriptObjects = new HashMap<String, Object>();
|
|
||||||
}
|
|
||||||
mRemovedJavaScriptObjects = new HashSet<Object>();
|
mRemovedJavaScriptObjects = new HashSet<Object>();
|
||||||
|
|
||||||
mSettings = settings;
|
mSettings = settings;
|
||||||
@ -590,15 +599,34 @@ class BrowserFrame extends Handler {
|
|||||||
Iterator<String> iter = mJavaScriptObjects.keySet().iterator();
|
Iterator<String> iter = mJavaScriptObjects.keySet().iterator();
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
String interfaceName = iter.next();
|
String interfaceName = iter.next();
|
||||||
Object object = mJavaScriptObjects.get(interfaceName);
|
JSObject jsobject = mJavaScriptObjects.get(interfaceName);
|
||||||
if (object != null) {
|
if (jsobject != null && jsobject.object != null) {
|
||||||
nativeAddJavascriptInterface(nativeFramePointer,
|
nativeAddJavascriptInterface(nativeFramePointer,
|
||||||
mJavaScriptObjects.get(interfaceName), interfaceName);
|
jsobject.object, interfaceName, jsobject.requireAnnotation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mRemovedJavaScriptObjects.clear();
|
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
|
* This method is called by WebCore to check whether application
|
||||||
* wants to hijack url loading
|
* 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;
|
assert obj != null;
|
||||||
removeJavascriptInterface(interfaceName);
|
removeJavascriptInterface(interfaceName);
|
||||||
|
mJavaScriptObjects.put(interfaceName, new JSObject(obj, requireAnnotation));
|
||||||
mJavaScriptObjects.put(interfaceName, obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeJavascriptInterface(String interfaceName) {
|
public void removeJavascriptInterface(String interfaceName) {
|
||||||
@ -1246,7 +1274,7 @@ class BrowserFrame extends Handler {
|
|||||||
* Add a javascript interface to the main frame.
|
* Add a javascript interface to the main frame.
|
||||||
*/
|
*/
|
||||||
private native void nativeAddJavascriptInterface(int nativeFramePointer,
|
private native void nativeAddJavascriptInterface(int nativeFramePointer,
|
||||||
Object obj, String interfaceName);
|
Object obj, String interfaceName, boolean requireAnnotation);
|
||||||
|
|
||||||
public native void clearCache();
|
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
|
@Override
|
||||||
public void addJavascriptInterface(Object object, String name) {
|
public void addJavascriptInterface(Object object, String name) {
|
||||||
|
addJavascriptInterface(object, name, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public void addJavascriptInterface(Object object, String name, boolean requireAnnotation) {
|
||||||
if (object == null) {
|
if (object == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
WebViewCore.JSInterfaceData arg = new WebViewCore.JSInterfaceData();
|
WebViewCore.JSInterfaceData arg = new WebViewCore.JSInterfaceData();
|
||||||
arg.mObject = object;
|
arg.mObject = object;
|
||||||
arg.mInterfaceName = name;
|
arg.mInterfaceName = name;
|
||||||
|
arg.mRequireAnnotation = requireAnnotation;
|
||||||
mWebViewCore.sendMessage(EventHub.ADD_JS_INTERFACE, arg);
|
mWebViewCore.sendMessage(EventHub.ADD_JS_INTERFACE, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -839,6 +839,7 @@ public final class WebViewCore {
|
|||||||
static class JSInterfaceData {
|
static class JSInterfaceData {
|
||||||
Object mObject;
|
Object mObject;
|
||||||
String mInterfaceName;
|
String mInterfaceName;
|
||||||
|
boolean mRequireAnnotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
static class JSKeyData {
|
static class JSKeyData {
|
||||||
@ -1508,7 +1509,7 @@ public final class WebViewCore {
|
|||||||
case ADD_JS_INTERFACE:
|
case ADD_JS_INTERFACE:
|
||||||
JSInterfaceData jsData = (JSInterfaceData) msg.obj;
|
JSInterfaceData jsData = (JSInterfaceData) msg.obj;
|
||||||
mBrowserFrame.addJavascriptInterface(jsData.mObject,
|
mBrowserFrame.addJavascriptInterface(jsData.mObject,
|
||||||
jsData.mInterfaceName);
|
jsData.mInterfaceName, jsData.mRequireAnnotation);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case REMOVE_JS_INTERFACE:
|
case REMOVE_JS_INTERFACE:
|
||||||
|
Reference in New Issue
Block a user