Commit d50b3e15 authored by bsheedy's avatar bsheedy Committed by Commit Bot

Add VR Browser iframe tests

Adds versions of tests that interact with web contents (scrolling,
clicking, etc.) where the interaction tested is in a cross-origin
iframe.

In order to achieve this, also adds the ability to request the
focused iframe and execute JavaScript in it from Java.

Bug: 862153
Change-Id: Ic0a1e5bee38c4f962626bb576040dd56bfc69bbf
Reviewed-on: https://chromium-review.googlesource.com/1163831
Commit-Queue: Brian Sheedy <bsheedy@chromium.org>
Reviewed-by: default avatarMichael Thiessen <mthiesse@chromium.org>
Reviewed-by: default avatarBo <boliu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#582667}
parent e4aee4ff
......@@ -35,8 +35,10 @@ import org.chromium.content.browser.test.util.CriteriaHelper;
import org.chromium.content.browser.test.util.DOMUtils;
import org.chromium.content_public.browser.RenderCoordinates;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
/**
* End-to-end tests for Daydream controller input while in the VR browser.
......@@ -75,44 +77,95 @@ public class VrBrowserControllerInputTest {
*/
@Test
@MediumTest
public void testControllerScrolling() throws InterruptedException {
mVrTestRule.loadUrl(
VrBrowserTestFramework.getFileUrlForHtmlTestFile("test_controller_scrolling"),
PAGE_LOAD_TIMEOUT_S);
final RenderCoordinates coord =
RenderCoordinates.fromWebContents(mVrTestRule.getWebContents());
waitForPageToBeScrollable(coord);
public void testControllerScrolling() throws InterruptedException, Exception {
String url = VrBrowserTestFramework.getFileUrlForHtmlTestFile("test_controller_scrolling");
final AtomicReference<RenderCoordinates> coord = new AtomicReference<RenderCoordinates>();
Runnable waitScrollable = () -> {
coord.set(RenderCoordinates.fromWebContents(mVrTestRule.getWebContents()));
waitForPageToBeScrollable(coord.get());
};
Callable<Integer> getYCoord = () -> {
return coord.get().getScrollYPixInt();
};
Callable<Integer> getXCoord = () -> {
return coord.get().getScrollXPixInt();
};
testControllerScrollingImpl(url, waitScrollable, getYCoord, getXCoord);
}
// Test that scrolling down works
int startScrollPoint = coord.getScrollYPixInt();
// Arbitrary, but valid values to scroll smoothly
/**
* Verifies that scrolling via the Daydream controller's touchpad works in cross-origin iframes
* (file:// URLs appear to be always treated as different origins).
* Automation of a manual test in https://crbug.com/862153.
*/
@Test
@MediumTest
public void testControllerScrollingIframe() throws InterruptedException, Exception {
String url = VrBrowserTestFramework.getFileUrlForHtmlTestFile(
"test_controller_scrolling_iframe_outer");
Runnable waitScrollable = () -> {
// We need to focus the iframe before we can start running JavaScript in it.
mVrBrowserTestFramework.runJavaScriptOrFail(
"document.getElementById('fs_iframe').focus()", POLL_TIMEOUT_SHORT_MS);
mVrBrowserTestFramework.pollJavaScriptBooleanInFrameOrFail(
"document.documentElement.scrollHeight > document.documentElement.clientHeight",
POLL_TIMEOUT_LONG_MS);
};
Callable<Integer> getYCoord = () -> {
// Round necessary to prevent Integer from failing due to decimal points.
return Integer.valueOf(mVrBrowserTestFramework.runJavaScriptInFrameOrFail(
"Math.round(document.documentElement.scrollTop)", POLL_TIMEOUT_SHORT_MS));
};
Callable<Integer> getXCoord = () -> {
// Round necessary to prevent Integer from failing due to decimal points.
return Integer.valueOf(mVrBrowserTestFramework.runJavaScriptInFrameOrFail(
"Math.round(document.documentElement.scrollLeft)", POLL_TIMEOUT_SHORT_MS));
};
testControllerScrollingImpl(url, waitScrollable, getYCoord, getXCoord);
}
private void testControllerScrollingImpl(String url, Runnable waitScrollable,
Callable<Integer> getYCoord, Callable<Integer> getXCoord)
throws InterruptedException, Exception {
mVrTestRule.loadUrl(url, PAGE_LOAD_TIMEOUT_S);
waitScrollable.run();
// Test that scrolling down works.
int startScrollPoint = getYCoord.call().intValue();
// Arbitrary, but valid values to scroll smoothly.
int scrollSteps = 20;
int scrollSpeed = 60;
mController.scroll(EmulatedVrController.ScrollDirection.DOWN, scrollSteps, scrollSpeed);
// We need this second scroll down, otherwise the horizontal scrolling becomes flaky
// This actually seems to not be an issue in this test case anymore, but still occurs in
// the fling scroll test, so keep around here as an extra precaution.
// TODO(bsheedy): Figure out why this is the case
// TODO(bsheedy): Figure out why this is the case.
mController.scroll(EmulatedVrController.ScrollDirection.DOWN, scrollSteps, scrollSpeed);
int endScrollPoint = coord.getScrollYPixInt();
int endScrollPoint = getYCoord.call().intValue();
Assert.assertTrue("Controller failed to scroll down", startScrollPoint < endScrollPoint);
// Test that scrolling up works
// Test that scrolling up works.
startScrollPoint = endScrollPoint;
mController.scroll(EmulatedVrController.ScrollDirection.UP, scrollSteps, scrollSpeed);
endScrollPoint = coord.getScrollYPixInt();
endScrollPoint = getYCoord.call().intValue();
Assert.assertTrue("Controller failed to scroll up", startScrollPoint > endScrollPoint);
// Test that scrolling right works
startScrollPoint = coord.getScrollXPixInt();
// Test that scrolling right works.
startScrollPoint = getXCoord.call().intValue();
mController.scroll(EmulatedVrController.ScrollDirection.RIGHT, scrollSteps, scrollSpeed);
endScrollPoint = coord.getScrollXPixInt();
endScrollPoint = getXCoord.call().intValue();
Assert.assertTrue("Controller failed to scroll right", startScrollPoint < endScrollPoint);
// Test that scrolling left works
// Test that scrolling left works.
startScrollPoint = endScrollPoint;
mController.scroll(EmulatedVrController.ScrollDirection.LEFT, scrollSteps, scrollSpeed);
endScrollPoint = coord.getScrollXPixInt();
endScrollPoint = getXCoord.call().intValue();
Assert.assertTrue("Controller failed to scroll left", startScrollPoint > endScrollPoint);
}
......@@ -129,14 +182,14 @@ public class VrBrowserControllerInputTest {
RenderCoordinates.fromWebContents(mVrTestRule.getWebContents());
waitForPageToBeScrollable(coord);
// Arbitrary, but valid values to trigger fling scrolling
// Arbitrary, but valid values to trigger fling scrolling.
int scrollSteps = 10;
int scrollSpeed = 10;
// Test fling scrolling down
// Test fling scrolling down.
mController.scroll(EmulatedVrController.ScrollDirection.DOWN, scrollSteps, scrollSpeed);
final AtomicInteger endScrollPoint = new AtomicInteger(coord.getScrollYPixInt());
// Check that we continue to scroll past wherever we were when we let go of the touchpad
// Check that we continue to scroll past wherever we were when we let go of the touchpad.
CriteriaHelper.pollInstrumentationThread(
()
-> { return coord.getScrollYPixInt() > endScrollPoint.get(); },
......@@ -144,7 +197,7 @@ public class VrBrowserControllerInputTest {
POLL_CHECK_INTERVAL_LONG_MS);
mController.cancelFlingScroll();
// Test fling scrolling up
// Test fling scrolling up.
mController.scroll(EmulatedVrController.ScrollDirection.UP, scrollSteps, scrollSpeed);
endScrollPoint.set(coord.getScrollYPixInt());
CriteriaHelper.pollInstrumentationThread(
......@@ -157,7 +210,7 @@ public class VrBrowserControllerInputTest {
// horizontally, so scroll down a bit to ensure that isn't the case.
mController.scroll(EmulatedVrController.ScrollDirection.DOWN, 10, 60);
// Test fling scrolling right
// Test fling scrolling right.
mController.scroll(EmulatedVrController.ScrollDirection.RIGHT, scrollSteps, scrollSpeed);
endScrollPoint.set(coord.getScrollXPixInt());
CriteriaHelper.pollInstrumentationThread(
......@@ -167,7 +220,7 @@ public class VrBrowserControllerInputTest {
POLL_CHECK_INTERVAL_LONG_MS);
mController.cancelFlingScroll();
// Test fling scrolling left
// Test fling scrolling left.
mController.scroll(EmulatedVrController.ScrollDirection.LEFT, scrollSteps, scrollSpeed);
endScrollPoint.set(coord.getScrollXPixInt());
CriteriaHelper.pollInstrumentationThread(
......@@ -193,6 +246,27 @@ public class VrBrowserControllerInputTest {
VrBrowserTestFramework.getFileUrlForHtmlTestFile("test_navigation_2d_page"));
}
/**
* Verifies that controller clicks in the VR browser on cross-origin iframes are properly
* registered. This is done by clicking on a link in the iframe and ensuring that it causes a
* navigation.
* Automation of a manual test in https://crbug.com/862153.
*/
@Test
@MediumTest
public void testControllerClicksRegisterOnIframe() throws InterruptedException {
mVrTestRule.loadUrl(
VrBrowserTestFramework.getFileUrlForHtmlTestFile("test_iframe_clicks_outer"));
mController.performControllerClick();
// Wait until the iframe's current location matches the URL of the page that gets navigated
// to on click.
mVrBrowserTestFramework.pollJavaScriptBooleanInFrameOrFail("window.location.href == '"
+ VrBrowserTestFramework.getFileUrlForHtmlTestFile(
"test_iframe_clicks_inner_nav")
+ "'",
POLL_TIMEOUT_SHORT_MS);
}
/*
* Verifies that swiping up/down on the Daydream controller's touchpad
* scrolls a native page while in the VR browser.
......
......@@ -58,10 +58,25 @@ public class VrBrowserWebInputEditingTest {
@MediumTest
@CommandLineFlags.Add("enable-features=VrLaunchIntents")
public void testWebInputFocus() throws InterruptedException {
// Load page in VR and make sure the controller is pointed at the content quad.
mVrTestRule.loadUrl(
VrBrowserTestFramework.getFileUrlForHtmlTestFile("test_web_input_editing"),
PAGE_LOAD_TIMEOUT_S);
testWebInputFocusImpl(
VrBrowserTestFramework.getFileUrlForHtmlTestFile("test_web_input_editing"));
}
/**
* Verifies the same thing as testWebInputFocus, but with the input box in a cross-origin
* iframe.
* Automation of a manual test in https://crbug.com/862153
*/
@Test
@MediumTest
@CommandLineFlags.Add("enable-features=VrLaunchIntents")
public void testWebInputFocusIframe() throws InterruptedException {
testWebInputFocusImpl(VrBrowserTestFramework.getFileUrlForHtmlTestFile(
"test_web_input_editing_iframe_outer"));
}
private void testWebInputFocusImpl(String url) throws InterruptedException {
mVrTestRule.loadUrl(url, PAGE_LOAD_TIMEOUT_S);
VrBrowserTransitionUtils.forceEnterVrBrowserOrFail(POLL_TIMEOUT_LONG_MS);
VrShell vrShell = TestVrShellDelegate.getVrShellForTesting();
......
......@@ -17,12 +17,15 @@ import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.test.ChromeActivityTestRule;
import org.chromium.content.browser.test.util.CriteriaHelper;
import org.chromium.content.browser.test.util.JavaScriptUtils;
import org.chromium.content_public.browser.RenderFrameHost;
import org.chromium.content_public.browser.WebContents;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;
/**
* Class containing the core framework for all XR (VR and AR) testing, which requires
......@@ -114,6 +117,19 @@ public abstract class XrTestFramework {
return "Not reached";
}
/**
* Runs the given JavaScript in the focused frame, failing if a timeout/interrupt occurs.
*
* @param js The JavaScript to run.
* @param timeout The timeout in milliseconds before failure.
* @param webContents The WebContents object to get the focused frame from.
* @return The return value of the JavaScript.
*/
public static String runJavaScriptInFrameOrFail(
String js, int timeout, final WebContents webContents) {
return runJavaScriptInFrameInternal(js, timeout, webContents, true /* failOnTimeout */);
}
/**
* Polls the provided JavaScript boolean expression until the timeout is reached or the boolean
* is true.
......@@ -137,7 +153,32 @@ public abstract class XrTestFramework {
return Boolean.parseBoolean(result);
}, "Polling timed out", timeoutMs, POLL_CHECK_INTERVAL_LONG_MS);
} catch (AssertionError e) {
Log.d(TAG, "pollJavaScriptBoolean() timed out");
Log.d(TAG, "pollJavaScriptBoolean() timed out: " + e.toString());
return false;
}
return true;
}
/**
* Polls the provided JavaScript boolean expression in the focused frame until the timeout is
* reached or the boolean is true.
*
* @param boolExpression The JavaScript boolean expression to poll.
* @param timeoutMs The polling timeout in milliseconds.
* @param webContents The WebContents to get the focused frame from.
* @return True if the boolean evaluated to true, false if timed out.
*/
public static boolean pollJavaScriptBooleanInFrame(
final String boolExpression, int timeoutMs, final WebContents webContents) {
try {
CriteriaHelper.pollInstrumentationThread(() -> {
String result = "false";
result = runJavaScriptInFrameInternal(boolExpression, POLL_CHECK_INTERVAL_SHORT_MS,
webContents, false /* failOnTimeout */);
return Boolean.parseBoolean(result);
}, "Polling timed out", timeoutMs, POLL_CHECK_INTERVAL_LONG_MS);
} catch (AssertionError e) {
Log.d(TAG, "pollJavaScriptBooleanInFrame() timed out: " + e.toString());
return false;
}
return true;
......@@ -157,6 +198,20 @@ public abstract class XrTestFramework {
pollJavaScriptBoolean(boolExpression, timeoutMs, webContents));
}
/**
* Polls the provided JavaScript boolean expression in the focused frame, failing the test if
* it does not evaluate to true within the provided timeout.
*
* @param boolExpression The JavaScript boolean expression to poll.
* @param timeoutMs The polling timeout in milliseconds.
* @param webContents The WebContents to get the focused frame from.
*/
public static void pollJavaScriptBooleanInFrameOrFail(
String boolExpression, int timeoutMs, WebContents webContents) {
Assert.assertTrue("Timed out polling boolean expression in frame: " + boolExpression,
pollJavaScriptBooleanInFrame(boolExpression, timeoutMs, webContents));
}
/**
* Executes a JavaScript step function using the given WebContents.
*
......@@ -272,6 +327,27 @@ public abstract class XrTestFramework {
Assert.assertNotEquals(checkTestStatus(webContents), TestStatus.FAILED);
}
private static String runJavaScriptInFrameInternal(
String js, int timeout, final WebContents webContents, boolean failOnTimeout) {
final AtomicReference<RenderFrameHost> rfh = new AtomicReference<RenderFrameHost>();
ThreadUtils.runOnUiThreadBlocking(() -> { rfh.set(webContents.getFocusedFrame()); });
Assert.assertTrue("Did not get a focused frame", rfh.get() != null);
final CountDownLatch latch = new CountDownLatch(1);
final AtomicReference<String> result = new AtomicReference<String>();
rfh.get().executeJavaScriptForTests(js, (String r) -> {
result.set(r);
latch.countDown();
});
try {
if (!latch.await(timeout, TimeUnit.MILLISECONDS) && failOnTimeout) {
Assert.fail("Timed out running JavaScript in focused frame: " + js);
}
} catch (InterruptedException e) {
Assert.fail("Waiting for latch was interrupted: " + e.toString());
}
return result.get();
}
/**
* Must be constructed after the rule has been applied (e.g. in whatever method is
* tagged with @Before).
......@@ -310,6 +386,17 @@ public abstract class XrTestFramework {
return runJavaScriptOrFail(js, timeout, mFirstTabWebContents);
}
/**
* Helper method to run runJavaScriptInFrameOrFail with the first tab's WebContents.
*
* @param js The JavaScript to run.
* @param timeout The timeout in milliseconds before a failure.
* @return The return value of the JavaScript.
*/
public String runJavaScriptInFrameOrFail(String js, int timeout) {
return runJavaScriptInFrameOrFail(js, timeout, mFirstTabWebContents);
}
/**
* Helper function to run pollJavaScriptBoolean with the first tab's WebContents.
*
......@@ -321,6 +408,17 @@ public abstract class XrTestFramework {
return pollJavaScriptBoolean(boolExpression, timeoutMs, mFirstTabWebContents);
}
/**
* Helper function to run pollJavaScriptBooleanInFrame with the first tab's WebContents.
*
* @param boolExpression The JavaScript boolean expression to poll.
* @param timeoutMs The polling timeout in milliseconds.
* @return True if the boolean evaluated to true, false if timed out.
*/
public boolean pollJavaScriptInFrameBoolean(String boolExpression, int timeoutMs) {
return pollJavaScriptBooleanInFrame(boolExpression, timeoutMs, mFirstTabWebContents);
}
/**
* Helper function to run pollJavaScriptBooleanOrFail with the first tab's WebContents.
*
......@@ -331,6 +429,16 @@ public abstract class XrTestFramework {
pollJavaScriptBooleanOrFail(boolExpression, timeoutMs, mFirstTabWebContents);
}
/**
* Helper function to run pollJavaScriptBooleanInFrameOrFail with the first tab's WebContents.
*
* @param boolExpression The JavaScript boolean expression to poll.
* @param timeoutMs The polling timeout in milliseconds.
*/
public void pollJavaScriptBooleanInFrameOrFail(String boolExpression, int timeoutMs) {
pollJavaScriptBooleanInFrameOrFail(boolExpression, timeoutMs, mFirstTabWebContents);
}
/**
* Helper function to run executeStepAndWait using the first tab's WebContents.
*
......
<!doctype html>
<html>
<head>
<style>
iframe {
position: fixed;
top: 0px;
bottom: 0px;
left: 0px;
right: 0px;
width: 100%;
height: 100%;
border: none;
margin: 0;
}
</style>
</head>
<body>
<iframe src="test_controller_scrolling.html" id="fs_iframe"></iframe>
</body>
</html>
<!doctype html>
<html>
<head>
<style>
body {
background-color: blue;
}
div {
display: block;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: red;
}
</style>
<script>
function navigate() {
window.location.href = "test_iframe_clicks_inner_nav.html";
}
</script>
</head>
<body>
<div onclick="navigate()"></div>
</body>
</html>
<!doctype html>
<html>
<head>
<style>
body {
background-color: blue;
}
div {
display: block;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: yellow;
}
</style>
</head>
<body>
<div></div>
</body>
</html>
<!doctype html>
<html>
<head>
<style>
iframe {
position: fixed;
top: 0px;
bottom: 0px;
left: 0px;
right: 0px;
width: 100%;
height: 100%;
border: none;
margin: 0;
}
</style>
</head>
<body>
<iframe src="test_iframe_clicks_inner.html" id="fs_iframe"></iframe>
</body>
</html>
<!doctype html>
<html>
<head>
<style>
iframe {
position: fixed;
top: 0px;
bottom: 0px;
left: 0px;
right: 0px;
width: 100%;
height: 100%;
border: none;
margin: 0;
}
</style>
</head>
<body>
<iframe src="test_web_input_editing.html" id="fs_iframe"></iframe>
</body>
</html>
......@@ -10,6 +10,7 @@
#include "base/android/jni_string.h"
#include "base/android/unguessable_token_android.h"
#include "base/bind.h"
#include "base/json/json_string_value_serializer.h"
#include "base/logging.h"
#include "content/browser/frame_host/render_frame_host_delegate.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
......@@ -37,6 +38,15 @@ void OnGetCanonicalUrlForSharing(
base::android::RunStringCallbackAndroid(jcallback, url->spec());
}
void OnExecuteJavaScriptResult(const base::android::JavaRef<jobject>& jcallback,
const base::Value* value) {
std::string result;
JSONStringValueSerializer serializer(&result);
bool value_serialized = serializer.SerializeAndOmitBinaryValues(*value);
DCHECK(value_serialized);
base::android::RunStringCallbackAndroid(jcallback, result);
}
} // namespace
RenderFrameHostAndroid::RenderFrameHostAndroid(
......@@ -101,4 +111,16 @@ void RenderFrameHostAndroid::NotifyUserActivation(
render_frame_host_->NotifyUserActivation();
}
void RenderFrameHostAndroid::ExecuteJavaScriptForTests(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
const base::android::JavaParamRef<jstring>& jscript,
const base::android::JavaParamRef<jobject>& jcallback) {
base::string16 script(ConvertJavaStringToUTF16(env, jscript));
auto callback = base::BindRepeating(
&OnExecuteJavaScriptResult,
base::android::ScopedJavaGlobalRef<jobject>(env, jcallback));
render_frame_host_->ExecuteJavaScriptForTests(script, callback);
}
} // namespace content
......@@ -52,6 +52,14 @@ class RenderFrameHostAndroid : public base::SupportsUserData::Data {
void NotifyUserActivation(JNIEnv* env,
const base::android::JavaParamRef<jobject>&);
// TODO(https://crbug.com/873217): Move this and OnExecuteJavaScriptResult
// into a test-only RFH wrapper.
void ExecuteJavaScriptForTests(
JNIEnv* env,
const base::android::JavaParamRef<jobject>&,
const base::android::JavaParamRef<jstring>& jscript,
const base::android::JavaParamRef<jobject>& jcallback);
private:
RenderFrameHostImpl* const render_frame_host_;
service_manager::mojom::InterfaceProviderPtr interface_provider_ptr_;
......
......@@ -303,6 +303,12 @@ ScopedJavaLocalRef<jobject> WebContentsAndroid::GetMainFrame(
return web_contents_->GetMainFrame()->GetJavaRenderFrameHost();
}
ScopedJavaLocalRef<jobject> WebContentsAndroid::GetFocusedFrame(
JNIEnv* env,
const JavaParamRef<jobject>& obj) const {
return web_contents_->GetFocusedFrame()->GetJavaRenderFrameHost();
}
ScopedJavaLocalRef<jstring> WebContentsAndroid::GetTitle(
JNIEnv* env,
const JavaParamRef<jobject>& obj) const {
......
......@@ -52,6 +52,9 @@ class CONTENT_EXPORT WebContentsAndroid
base::android::ScopedJavaLocalRef<jobject> GetMainFrame(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj) const;
base::android::ScopedJavaLocalRef<jobject> GetFocusedFrame(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj) const;
base::android::ScopedJavaLocalRef<jstring> GetTitle(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj) const;
......
......@@ -95,6 +95,11 @@ public class RenderFrameHostImpl implements RenderFrameHost {
nativeNotifyUserActivation(mNativeRenderFrameHostAndroid);
}
@Override
public void executeJavaScriptForTests(String script, Callback<String> callback) {
nativeExecuteJavaScriptForTests(mNativeRenderFrameHostAndroid, script, callback);
}
/**
* Return the AndroidOverlay routing token for this RenderFrameHostImpl.
*/
......@@ -109,4 +114,6 @@ public class RenderFrameHostImpl implements RenderFrameHost {
private native UnguessableToken nativeGetAndroidOverlayRoutingToken(
long nativeRenderFrameHostAndroid);
private native void nativeNotifyUserActivation(long nativeRenderFrameHostAndroid);
private native void nativeExecuteJavaScriptForTests(
long nativeRenderFrameHostAndroid, String script, Callback<String> callback);
}
......@@ -341,6 +341,11 @@ public class WebContentsImpl implements WebContents, RenderFrameHostDelegate, Wi
return nativeGetMainFrame(mNativeWebContentsAndroid);
}
@Override
public RenderFrameHost getFocusedFrame() {
return nativeGetFocusedFrame(mNativeWebContentsAndroid);
}
@Override
public String getTitle() {
return nativeGetTitle(mNativeWebContentsAndroid);
......@@ -895,6 +900,7 @@ public class WebContentsImpl implements WebContents, RenderFrameHostDelegate, Wi
private native void nativeSetTopLevelNativeWindow(
long nativeWebContentsAndroid, WindowAndroid windowAndroid);
private native RenderFrameHost nativeGetMainFrame(long nativeWebContentsAndroid);
private native RenderFrameHost nativeGetFocusedFrame(long nativeWebContentsAndroid);
private native String nativeGetTitle(long nativeWebContentsAndroid);
private native String nativeGetVisibleURL(long nativeWebContentsAndroid);
private native String nativeGetEncoding(long nativeWebContentsAndroid);
......
......@@ -39,6 +39,15 @@ public interface RenderFrameHost {
*/
void notifyUserActivation();
/**
* Runs the given JavaScript in the RenderFrameHost.
*
* @param script A String containing the JavaScript to run.
* @param callback The Callback that will be called with the result of the JavaScript execution
* serialized to a String using JSONStringValueSerializer.
*/
void executeJavaScriptForTests(String script, Callback<String> callback);
/**
* Returns whether we're in incognito mode.
*
......
......@@ -130,6 +130,11 @@ public interface WebContents extends Parcelable {
*/
RenderFrameHost getMainFrame();
/**
* @return The focused frame in this WebContents.
*/
RenderFrameHost getFocusedFrame();
/**
* @return The title for the current visible page.
*/
......
......@@ -28,6 +28,9 @@ public class MockRenderFrameHost implements RenderFrameHost {
@Override
public void notifyUserActivation() {}
@Override
public void executeJavaScriptForTests(String script, Callback<String> callback) {}
@Override
public boolean isIncognito() {
return false;
......
......@@ -75,6 +75,11 @@ public class MockWebContents implements WebContents {
return renderFrameHost;
}
@Override
public RenderFrameHost getFocusedFrame() {
return renderFrameHost;
}
@Override
public String getTitle() {
return null;
......
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