Commit e97088e9 authored by avi@chromium.org's avatar avi@chromium.org

Switch Android code to use ExecuteJavascriptInWebFrameCallbackResult.

BUG=168169
TEST=should all pass


Review URL: https://chromiumcodereview.appspot.com/11788005

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@175489 0039d316-1c4b-4281-b951-d872f2087c98
parent 31e13e95
...@@ -72,12 +72,6 @@ class TestAwContentsClient extends NullContentsClient { ...@@ -72,12 +72,6 @@ class TestAwContentsClient extends NullContentsClient {
mOnReceivedErrorHelper.notifyCalled(errorCode, description, failingUrl); mOnReceivedErrorHelper.notifyCalled(errorCode, description, failingUrl);
} }
@Override
public void onEvaluateJavaScriptResult(int id, String jsonResult) {
super.onEvaluateJavaScriptResult(id, jsonResult);
mOnEvaluateJavaScriptResultHelper.notifyCalled(id, jsonResult);
}
@Override @Override
public boolean onConsoleMessage(ConsoleMessage consoleMessage) { public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
mAddMessageToConsoleHelper.setLevel(consoleMessage.messageLevel().ordinal()); mAddMessageToConsoleHelper.setLevel(consoleMessage.messageLevel().ordinal());
......
...@@ -51,7 +51,8 @@ public class JSUtils { ...@@ -51,7 +51,8 @@ public class JSUtils {
"var evObj = document.createEvent('Events'); " + "var evObj = document.createEvent('Events'); " +
"evObj.initEvent('click', true, false); " + "evObj.initEvent('click', true, false); " +
"document.getElementById('" + linkId + "').dispatchEvent(evObj);" + "document.getElementById('" + linkId + "').dispatchEvent(evObj);" +
"console.log('element with id [" + linkId + "] clicked');"); "console.log('element with id [" + linkId + "] clicked');",
null);
} }
}); });
} }
......
...@@ -19,4 +19,10 @@ In particular, ~ at the start of a string means it's a regex. ...@@ -19,4 +19,10 @@ In particular, ~ at the start of a string means it's a regex.
</Match> </Match>
<!-- Ignore "reliance on default String encoding" warnings, as we're not multi-platform --> <!-- Ignore "reliance on default String encoding" warnings, as we're not multi-platform -->
<Bug pattern="DM_DEFAULT_ENCODING" /> <Bug pattern="DM_DEFAULT_ENCODING" />
<!-- Disabled due to impossible false positives found in -->
<!-- https://codereview.chromium.org/11788005/ (look in comments) -->
<Match>
<Method name="handleMessage" params="android.os.Message" returns="void" />
<Bug pattern="BC_IMPOSSIBLE_CAST" />
</Match>
</FindBugsFilter> </FindBugsFilter>
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "base/json/json_writer.h" #include "base/json/json_writer.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/utf_string_conversions.h" #include "base/utf_string_conversions.h"
#include "base/values.h"
#include "cc/layer.h" #include "cc/layer.h"
#include "content/browser/android/interstitial_page_delegate_android.h" #include "content/browser/android/interstitial_page_delegate_android.h"
#include "content/browser/android/load_url_params.h" #include "content/browser/android/load_url_params.h"
...@@ -174,10 +175,6 @@ ContentViewCoreImpl::ContentViewCoreImpl(JNIEnv* env, jobject obj, ...@@ -174,10 +175,6 @@ ContentViewCoreImpl::ContentViewCoreImpl(JNIEnv* env, jobject obj,
dpi_scale_ = device_info->GetDPIScale(); dpi_scale_ = device_info->GetDPIScale();
} }
notification_registrar_.Add(this,
NOTIFICATION_EXECUTE_JAVASCRIPT_RESULT,
NotificationService::AllSources());
// Currently, the only use case we have for overriding a user agent involves // Currently, the only use case we have for overriding a user agent involves
// spoofing a desktop Linux user agent for "Request desktop site". // spoofing a desktop Linux user agent for "Request desktop site".
// Automatically set it for all WebContents so that it is available when a // Automatically set it for all WebContents so that it is available when a
...@@ -272,25 +269,6 @@ void ContentViewCoreImpl::Observe(int type, ...@@ -272,25 +269,6 @@ void ContentViewCoreImpl::Observe(int type,
} }
break; break;
} }
case NOTIFICATION_EXECUTE_JAVASCRIPT_RESULT: {
if (!web_contents_ || Source<RenderViewHost>(source).ptr() !=
web_contents_->GetRenderViewHost()) {
return;
}
JNIEnv* env = base::android::AttachCurrentThread();
std::pair<int, Value*>* result_pair =
Details<std::pair<int, Value*> >(details).ptr();
std::string json;
base::JSONWriter::Write(result_pair->second, &json);
ScopedJavaLocalRef<jstring> j_json = ConvertUTF8ToJavaString(env, json);
ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
if (!j_obj.is_null()) {
Java_ContentViewCore_onEvaluateJavaScriptResult(env, j_obj.obj(),
static_cast<jint>(result_pair->first), j_json.obj());
}
break;
}
} }
} }
...@@ -1241,15 +1219,46 @@ void ContentViewCoreImpl::UndoScrollFocusedEditableNodeIntoView( ...@@ -1241,15 +1219,46 @@ void ContentViewCoreImpl::UndoScrollFocusedEditableNodeIntoView(
new ViewMsg_UndoScrollFocusedEditableNodeIntoView(host->GetRoutingID())); new ViewMsg_UndoScrollFocusedEditableNodeIntoView(host->GetRoutingID()));
} }
jint ContentViewCoreImpl::EvaluateJavaScript(JNIEnv* env, namespace {
void JavaScriptResultCallback(ScopedJavaGlobalRef<jobject>* message,
const base::Value* result) {
// |message| is passed as base::Owned, so it will automatically be deleted
// when the callback goes out of scope.
JNIEnv* env = base::android::AttachCurrentThread();
std::string json;
base::JSONWriter::Write(result, &json);
ScopedJavaLocalRef<jstring> j_json = ConvertUTF8ToJavaString(env, json);
Java_ContentViewCore_onEvaluateJavaScriptResult(env,
j_json.obj(),
message->obj());
}
} // namespace
void ContentViewCoreImpl::EvaluateJavaScript(JNIEnv* env,
jobject obj, jobject obj,
jstring script) { jstring script,
jobject message) {
RenderViewHost* host = web_contents_->GetRenderViewHost(); RenderViewHost* host = web_contents_->GetRenderViewHost();
DCHECK(host); DCHECK(host);
string16 script_utf16 = ConvertJavaStringToUTF16(env, script); if (!message) {
return host->ExecuteJavascriptInWebFrameNotifyResult(string16(), // No callback requested.
script_utf16); host->ExecuteJavascriptInWebFrame(string16(), // frame_xpath
ConvertJavaStringToUTF16(env, script));
return;
}
// Secure the message in a scoped object and give ownership of it to the
// callback.
ScopedJavaGlobalRef<jobject>* j_message = new ScopedJavaGlobalRef<jobject>();
j_message->Reset(env, message);
content::RenderViewHost::JavascriptResultCallback callback =
base::Bind(&JavaScriptResultCallback, base::Owned(j_message));
host->ExecuteJavascriptInWebFrameCallbackResult(
string16(), // frame_xpath
ConvertJavaStringToUTF16(env, script),
callback);
} }
bool ContentViewCoreImpl::GetUseDesktopUserAgent( bool ContentViewCoreImpl::GetUseDesktopUserAgent(
...@@ -1325,14 +1334,6 @@ jint Init(JNIEnv* env, jobject obj, ...@@ -1325,14 +1334,6 @@ jint Init(JNIEnv* env, jobject obj,
return reinterpret_cast<jint>(view); return reinterpret_cast<jint>(view);
} }
jint EvaluateJavaScript(JNIEnv* env, jobject obj, jstring script) {
ContentViewCoreImpl* view = static_cast<ContentViewCoreImpl*>(
ContentViewCore::GetNativeContentViewCore(env, obj));
DCHECK(view);
return view->EvaluateJavaScript(env, obj, script);
}
bool RegisterContentViewCore(JNIEnv* env) { bool RegisterContentViewCore(JNIEnv* env) {
if (!base::android::HasClass(env, kContentViewCoreClassPath)) { if (!base::android::HasClass(env, kContentViewCoreClassPath)) {
DLOG(ERROR) << "Unable to find class ContentViewCore!"; DLOG(ERROR) << "Unable to find class ContentViewCore!";
......
...@@ -157,7 +157,10 @@ class ContentViewCoreImpl : public ContentViewCore, ...@@ -157,7 +157,10 @@ class ContentViewCoreImpl : public ContentViewCore,
void ContinuePendingReload(JNIEnv* env, jobject obj); void ContinuePendingReload(JNIEnv* env, jobject obj);
jboolean NeedsReload(JNIEnv* env, jobject obj); jboolean NeedsReload(JNIEnv* env, jobject obj);
void ClearHistory(JNIEnv* env, jobject obj); void ClearHistory(JNIEnv* env, jobject obj);
jint EvaluateJavaScript(JNIEnv* env, jobject obj, jstring script); void EvaluateJavaScript(JNIEnv* env,
jobject obj,
jstring script,
jobject message);
int GetNativeImeAdapter(JNIEnv* env, jobject obj); int GetNativeImeAdapter(JNIEnv* env, jobject obj);
void SetFocus(JNIEnv* env, jobject obj, jboolean focused); void SetFocus(JNIEnv* env, jobject obj, jboolean focused);
void ScrollFocusedEditableNodeIntoView(JNIEnv* env, jobject obj); void ScrollFocusedEditableNodeIntoView(JNIEnv* env, jobject obj);
......
...@@ -420,17 +420,11 @@ public class ContentView extends FrameLayout implements ContentViewCore.Internal ...@@ -420,17 +420,11 @@ public class ContentView extends FrameLayout implements ContentViewCore.Internal
/** /**
* Injects the passed JavaScript code in the current page and evaluates it. * Injects the passed JavaScript code in the current page and evaluates it.
* Once evaluated, an asynchronous call to
* ContentViewClient.onJavaScriptEvaluationResult is made. Used in automation
* tests.
* *
* @return an id that is passed along in the asynchronous onJavaScriptEvaluationResult callback
* @throws IllegalStateException If the ContentView has been destroyed. * @throws IllegalStateException If the ContentView has been destroyed.
*
* TODO(nileshagrawal): Remove this method from the public interface.
*/ */
public int evaluateJavaScript(String script) throws IllegalStateException { public void evaluateJavaScript(String script) throws IllegalStateException {
return mContentViewCore.evaluateJavaScript(script); mContentViewCore.evaluateJavaScript(script, null);
} }
/** /**
......
...@@ -92,15 +92,6 @@ public class ContentViewClient { ...@@ -92,15 +92,6 @@ public class ContentViewClient {
public void onImeEvent() { public void onImeEvent() {
} }
/**
* A callback invoked after the JavaScript code passed to evaluateJavaScript
* has finished execution.
* Used in automation tests.
* @hide
*/
public void onEvaluateJavaScriptResult(int id, String jsonResult) {
}
// TODO (dtrainor): Should expose getScrollX/Y from ContentView or make // TODO (dtrainor): Should expose getScrollX/Y from ContentView or make
// computeHorizontalScrollOffset()/computeVerticalScrollOffset() public. // computeHorizontalScrollOffset()/computeVerticalScrollOffset() public.
/** /**
......
...@@ -18,6 +18,7 @@ import android.graphics.Rect; ...@@ -18,6 +18,7 @@ import android.graphics.Rect;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Message;
import android.os.ResultReceiver; import android.os.ResultReceiver;
import android.text.Editable; import android.text.Editable;
import android.util.Log; import android.util.Log;
...@@ -1049,17 +1050,19 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient { ...@@ -1049,17 +1050,19 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient {
} }
/** /**
* Injects the passed JavaScript code in the current page and evaluates it. * Injects the passed Javascript code in the current page and evaluates it.
* Once evaluated, an asynchronous call to * If a result is required, pass in a Message to be sent to its target.
* ContentViewClient.onJavaScriptEvaluationResult is made. Used in automation * Used in automation tests.
* tests.
* *
* @return an id that is passed along in the asynchronous onJavaScriptEvaluationResult callback * @param script The Javascript to execute.
* @param message The message to be fired off when a result is ready. The script's
* result will be json encoded in the Message's {@link Message#obj} field.
* If no result is required, pass null.
* @throws IllegalStateException If the ContentView has been destroyed. * @throws IllegalStateException If the ContentView has been destroyed.
*/ */
public int evaluateJavaScript(String script) throws IllegalStateException { public void evaluateJavaScript(String script, Message message) throws IllegalStateException {
checkIsAlive(); checkIsAlive();
return nativeEvaluateJavaScript(script); nativeEvaluateJavaScript(mNativeContentViewCore, script, message);
} }
/** /**
...@@ -1990,8 +1993,9 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient { ...@@ -1990,8 +1993,9 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient {
@SuppressWarnings("unused") @SuppressWarnings("unused")
@CalledByNative @CalledByNative
private void onEvaluateJavaScriptResult(int id, String jsonResult) { private static void onEvaluateJavaScriptResult(String jsonResult, Message message) {
getContentViewClient().onEvaluateJavaScriptResult(id, jsonResult); message.obj = jsonResult;
message.sendToTarget();
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
...@@ -2502,7 +2506,8 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient { ...@@ -2502,7 +2506,8 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient {
private native void nativeClearHistory(int nativeContentViewCoreImpl); private native void nativeClearHistory(int nativeContentViewCoreImpl);
private native int nativeEvaluateJavaScript(String script); private native void nativeEvaluateJavaScript(int nativeContentViewCoreImpl,
String script, Message message);
private native int nativeGetNativeImeAdapter(int nativeContentViewCoreImpl); private native int nativeGetNativeImeAdapter(int nativeContentViewCoreImpl);
......
...@@ -132,7 +132,7 @@ public class AccessibilityInjector extends WebContentsObserverAndroid { ...@@ -132,7 +132,7 @@ public class AccessibilityInjector extends WebContentsObserverAndroid {
if (onDeviceScriptInjectionEnabled && js != null && mContentViewCore.isAlive()) { if (onDeviceScriptInjectionEnabled && js != null && mContentViewCore.isAlive()) {
addOrRemoveAccessibilityApisIfNecessary(); addOrRemoveAccessibilityApisIfNecessary();
mContentViewCore.evaluateJavaScript(js); mContentViewCore.evaluateJavaScript(js, null);
mInjectedScriptEnabled = true; mInjectedScriptEnabled = true;
mScriptInjected = true; mScriptInjected = true;
} }
...@@ -183,7 +183,7 @@ public class AccessibilityInjector extends WebContentsObserverAndroid { ...@@ -183,7 +183,7 @@ public class AccessibilityInjector extends WebContentsObserverAndroid {
if (mContentViewCore.isAlive()) { if (mContentViewCore.isAlive()) {
String js = String.format(TOGGLE_CHROME_VOX_JAVASCRIPT, Boolean.toString( String js = String.format(TOGGLE_CHROME_VOX_JAVASCRIPT, Boolean.toString(
mInjectedScriptEnabled)); mInjectedScriptEnabled));
mContentViewCore.evaluateJavaScript(js); mContentViewCore.evaluateJavaScript(js, null);
if (!mInjectedScriptEnabled) { if (!mInjectedScriptEnabled) {
// Stop any TTS/Vibration right now. // Stop any TTS/Vibration right now.
......
...@@ -172,7 +172,7 @@ class JellyBeanAccessibilityInjector extends AccessibilityInjector { ...@@ -172,7 +172,7 @@ class JellyBeanAccessibilityInjector extends AccessibilityInjector {
final int resultId = mResultIdCounter.getAndIncrement(); final int resultId = mResultIdCounter.getAndIncrement();
final String js = String.format(JAVASCRIPT_ACTION_TEMPLATE, mInterfaceName, resultId, final String js = String.format(JAVASCRIPT_ACTION_TEMPLATE, mInterfaceName, resultId,
code); code);
contentView.evaluateJavaScript(js); contentView.evaluateJavaScript(js, null);
return getResultAndClear(resultId); return getResultAndClear(resultId);
} }
...@@ -228,7 +228,7 @@ class JellyBeanAccessibilityInjector extends AccessibilityInjector { ...@@ -228,7 +228,7 @@ class JellyBeanAccessibilityInjector extends AccessibilityInjector {
* request to a waiting (or potentially timed out) thread. * request to a waiting (or potentially timed out) thread.
* *
* @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 o fa request as a {@link String}. * @param result The result of a request as a {@link String}.
*/ */
@JavascriptInterface @JavascriptInterface
@SuppressWarnings("unused") @SuppressWarnings("unused")
...@@ -249,4 +249,4 @@ class JellyBeanAccessibilityInjector extends AccessibilityInjector { ...@@ -249,4 +249,4 @@ class JellyBeanAccessibilityInjector extends AccessibilityInjector {
} }
} }
} }
} }
\ No newline at end of file
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
package org.chromium.content.browser.test.util; package org.chromium.content.browser.test.util;
import android.os.Handler;
import android.os.Message;
import android.util.Log; import android.util.Log;
import org.chromium.content.browser.ContentView; import org.chromium.content.browser.ContentView;
...@@ -81,8 +83,7 @@ public class TestCallbackHelperContainer { ...@@ -81,8 +83,7 @@ public class TestCallbackHelperContainer {
} }
public static class OnEvaluateJavaScriptResultHelper extends CallbackHelper { public static class OnEvaluateJavaScriptResultHelper extends CallbackHelper {
private volatile Integer mRequestId; private boolean mRequestSent;
private volatile Integer mId;
private String mJsonResult; private String mJsonResult;
/** /**
...@@ -91,14 +92,24 @@ public class TestCallbackHelperContainer { ...@@ -91,14 +92,24 @@ public class TestCallbackHelperContainer {
* @param code A JavaScript code to be evaluated. * @param code A JavaScript code to be evaluated.
*/ */
public void evaluateJavaScript(ContentViewCore contentViewCore, String code) { public void evaluateJavaScript(ContentViewCore contentViewCore, String code) {
setRequestId(contentViewCore.evaluateJavaScript(code)); assert !mRequestSent;
Message message = Message.obtain(new Handler() {
@Override
public void handleMessage(Message msg) {
String json = (String)msg.obj;
notifyCalled(json);
}
});
contentViewCore.evaluateJavaScript(code, message);
mRequestSent = true;
mJsonResult = null;
} }
/** /**
* Returns true if the evaluation started by evaluateJavaScript() has completed. * Returns true if the evaluation started by evaluateJavaScript() has completed.
*/ */
public boolean hasValue() { public boolean hasValue() {
return mId != null; return mJsonResult != null;
} }
/** /**
...@@ -109,7 +120,8 @@ public class TestCallbackHelperContainer { ...@@ -109,7 +120,8 @@ public class TestCallbackHelperContainer {
public String getJsonResultAndClear() { public String getJsonResultAndClear() {
assert hasValue(); assert hasValue();
String result = mJsonResult; String result = mJsonResult;
setRequestId(null); mRequestSent = false;
mJsonResult = null;
return result; return result;
} }
...@@ -141,21 +153,8 @@ public class TestCallbackHelperContainer { ...@@ -141,21 +153,8 @@ public class TestCallbackHelperContainer {
return hasValue(); return hasValue();
} }
private void setRequestId(Integer requestId) { public void notifyCalled(String jsonResult) {
mRequestId = requestId; assert !hasValue();
mId = null;
mJsonResult = null;
}
public void notifyCalled(int id, String jsonResult) {
if (mRequestId == null) {
Log.w("TestCallbackHelperContainer",
"Received JavaScript eval result when request id was not set");
return;
}
if (id != mRequestId.intValue()) return;
assert mId == null;
mId = Integer.valueOf(id);
mJsonResult = jsonResult; mJsonResult = jsonResult;
notifyCalled(); notifyCalled();
} }
......
...@@ -35,16 +35,11 @@ public class TestContentViewClient extends ContentViewClient { ...@@ -35,16 +35,11 @@ public class TestContentViewClient extends ContentViewClient {
} }
/** /**
* ATTENTION!: When overriding the following methods, be sure to call * ATTENTION!: When overriding the following method, be sure to call
* the corresponding methods in the super class. Otherwise * the corresponding method in the super class. Otherwise
* {@link CallbackHelper#waitForCallback()} methods will * {@link CallbackHelper#waitForCallback()} methods will
* stop working! * stop working!
*/ */
@Override
public void onEvaluateJavaScriptResult(int id, String jsonResult) {
super.onEvaluateJavaScriptResult(id, jsonResult);
mOnEvaluateJavaScriptResultHelper.notifyCalled(id, jsonResult);
}
@Override @Override
public void onStartContentIntent(Context context, String contentUrl) { public void onStartContentIntent(Context context, String contentUrl) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment