Add CTS tests for PostMessage API
Bug: 21034542
Change-Id: I7c2a6a5ff5cd4cff7bcd7b83051cea55099ec655
diff --git a/libs/deviceutillegacy/src/android/webkit/cts/WebViewOnUiThread.java b/libs/deviceutillegacy/src/android/webkit/cts/WebViewOnUiThread.java
index 5cd6f30..6f310dd 100644
--- a/libs/deviceutillegacy/src/android/webkit/cts/WebViewOnUiThread.java
+++ b/libs/deviceutillegacy/src/android/webkit/cts/WebViewOnUiThread.java
@@ -21,6 +21,7 @@
import android.graphics.Bitmap;
import android.graphics.Picture;
import android.graphics.Rect;
+import android.net.Uri;
import android.os.Bundle;
import android.os.Looper;
import android.os.Message;
@@ -36,6 +37,8 @@
import android.webkit.ValueCallback;
import android.webkit.WebBackForwardList;
import android.webkit.WebChromeClient;
+import android.webkit.WebMessage;
+import android.webkit.WebMessagePort;
import android.webkit.WebSettings;
import android.webkit.WebView.HitTestResult;
import android.webkit.WebView.PictureListener;
@@ -307,6 +310,24 @@
});
}
+ public WebMessagePort[] createWebMessageChannel() {
+ return getValue(new ValueGetter<WebMessagePort[]>() {
+ @Override
+ public WebMessagePort[] capture() {
+ return mWebView.createWebMessageChannel();
+ }
+ });
+ }
+
+ public void postMessageToMainFrame(final WebMessage message, final Uri targetOrigin) {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mWebView.postMessageToMainFrame(message, targetOrigin);
+ }
+ });
+ }
+
public void addJavascriptInterface(final Object object, final String name) {
runOnUiThread(new Runnable() {
@Override
diff --git a/tests/tests/webkit/src/android/webkit/cts/PostMessageTest.java b/tests/tests/webkit/src/android/webkit/cts/PostMessageTest.java
new file mode 100644
index 0000000..e393bb6
--- /dev/null
+++ b/tests/tests/webkit/src/android/webkit/cts/PostMessageTest.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2015 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.cts;
+
+import android.cts.util.NullWebViewUtils;
+import android.cts.util.PollingCheck;
+import android.net.Uri;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+import android.webkit.WebMessage;
+import android.webkit.WebMessagePort;
+import android.webkit.WebView;
+
+import java.util.concurrent.CountDownLatch;
+import junit.framework.Assert;
+
+public class PostMessageTest extends ActivityInstrumentationTestCase2<WebViewCtsActivity> {
+ public static final long TIMEOUT = 20000L;
+
+ private WebView mWebView;
+ private WebViewOnUiThread mOnUiThread;
+
+ private static final String WEBVIEW_MESSAGE = "from_webview";
+ private static final String BASE_URI = "http://www.example.com";
+
+ public PostMessageTest() {
+ super("com.android.cts.webkit", WebViewCtsActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ final WebViewCtsActivity activity = getActivity();
+ mWebView = activity.getWebView();
+ if (mWebView != null) {
+ mOnUiThread = new WebViewOnUiThread(this, mWebView);
+ mOnUiThread.getSettings().setJavaScriptEnabled(true);
+ }
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ if (mOnUiThread != null) {
+ mOnUiThread.cleanUp();
+ }
+ super.tearDown();
+ }
+
+ private static final String TITLE_FROM_POST_MESSAGE =
+ "<!DOCTYPE html><html><body>"
+ + " <script>"
+ + " var received = '';"
+ + " onmessage = function (e) {"
+ + " received += e.data;"
+ + " document.title = received; };"
+ + " </script>"
+ + "</body></html>";
+
+ // Acks each received message from the message channel with a seq number.
+ private static final String CHANNEL_MESSAGE =
+ "<!DOCTYPE html><html><body>"
+ + " <script>"
+ + " var counter = 0;"
+ + " onmessage = function (e) {"
+ + " var myPort = e.ports[0];"
+ + " myPort.onmessage = function (f) {"
+ + " myPort.postMessage(f.data + counter++);"
+ + " }"
+ + " }"
+ + " </script>"
+ + "</body></html>";
+
+ private void loadPage(String data) {
+ mOnUiThread.loadDataWithBaseURLAndWaitForCompletion(BASE_URI, data,
+ "text/html", "UTF-8", null);
+ }
+
+ private void waitForTitle(final String title) {
+ new PollingCheck(TIMEOUT) {
+ @Override
+ protected boolean check() {
+ return mOnUiThread.getTitle().equals(title);
+ }
+ }.run();
+ }
+
+ // Post a string message to main frame and make sure it is received.
+ public void testSimpleMessageToMainFrame() throws Throwable {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
+ loadPage(TITLE_FROM_POST_MESSAGE);
+ WebMessage message = new WebMessage(WEBVIEW_MESSAGE);
+ mOnUiThread.postMessageToMainFrame(message, Uri.parse(BASE_URI));
+ waitForTitle(WEBVIEW_MESSAGE);
+ }
+
+ // Post multiple messages to main frame and make sure they are received in
+ // correct order.
+ public void testMultipleMessagesToMainFrame() throws Throwable {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
+ loadPage(TITLE_FROM_POST_MESSAGE);
+ for (int i = 0; i < 10; i++) {
+ mOnUiThread.postMessageToMainFrame(new WebMessage(Integer.toString(i)),
+ Uri.parse(BASE_URI));
+ }
+ waitForTitle("0123456789");
+ }
+
+ // Create a message channel and make sure it can be used for data transfer to/from js.
+ public void testMessageChannel() throws Throwable {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
+ loadPage(CHANNEL_MESSAGE);
+ final WebMessagePort[] channel = mOnUiThread.createWebMessageChannel();
+ WebMessage message = new WebMessage(WEBVIEW_MESSAGE, new WebMessagePort[]{channel[1]});
+ mOnUiThread.postMessageToMainFrame(message, Uri.parse(BASE_URI));
+ final int messageCount = 3;
+ final CountDownLatch latch = new CountDownLatch(messageCount);
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ for (int i = 0; i < messageCount; i++) {
+ channel[0].postMessage(new WebMessage(WEBVIEW_MESSAGE + i));
+ }
+ channel[0].setWebMessageCallback(new WebMessagePort.WebMessageCallback() {
+ @Override
+ public void onMessage(WebMessagePort port, WebMessage message) {
+ int i = messageCount - (int)latch.getCount();
+ assertEquals(WEBVIEW_MESSAGE + i + i, message.getData());
+ latch.countDown();
+ }
+ });
+ }
+ });
+ // Wait for all the responses to arrive.
+ boolean ignore = latch.await(TIMEOUT, java.util.concurrent.TimeUnit.MILLISECONDS);
+ }
+
+ // Test that a message port that is closed cannot used to send a message
+ public void testClose() throws Throwable {
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
+ loadPage(CHANNEL_MESSAGE);
+ final WebMessagePort[] channel = mOnUiThread.createWebMessageChannel();
+ WebMessage message = new WebMessage(WEBVIEW_MESSAGE, new WebMessagePort[]{channel[1]});
+ mOnUiThread.postMessageToMainFrame(message, Uri.parse(BASE_URI));
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ channel[0].close();
+ channel[0].postMessage(new WebMessage(WEBVIEW_MESSAGE));
+ } catch (IllegalStateException ex) {
+ // expect to receive an exception
+ return;
+ }
+ Assert.fail("A closed port cannot be used to transfer messages");
+ }
+ });
+ }
+
+ // Sends a new message channel from JS to Java.
+ private static final String CHANNEL_FROM_JS =
+ "<!DOCTYPE html><html><body>"
+ + " <script>"
+ + " var counter = 0;"
+ + " var mc = new MessageChannel();"
+ + " var received = '';"
+ + " mc.port1.onmessage = function (e) {"
+ + " received = e.data;"
+ + " document.title = e.data;"
+ + " };"
+ + " onmessage = function (e) {"
+ + " var myPort = e.ports[0];"
+ + " myPort.postMessage('', [mc.port2]);"
+ + " };"
+ + " </script>"
+ + "</body></html>";
+
+ // Test a message port created in JS can be received and used for message transfer.
+ public void testReceiveMessagePort() throws Throwable {
+ final String hello = "HELLO";
+ if (!NullWebViewUtils.isWebViewAvailable()) {
+ return;
+ }
+ loadPage(CHANNEL_FROM_JS);
+ final WebMessagePort[] channel = mOnUiThread.createWebMessageChannel();
+ WebMessage message = new WebMessage(WEBVIEW_MESSAGE, new WebMessagePort[]{channel[1]});
+ mOnUiThread.postMessageToMainFrame(message, Uri.parse(BASE_URI));
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ channel[0].setWebMessageCallback(new WebMessagePort.WebMessageCallback() {
+ @Override
+ public void onMessage(WebMessagePort port, WebMessage message) {
+ message.getPorts()[0].postMessage(new WebMessage(hello));
+ }
+ });
+ }
+ });
+ waitForTitle(hello);
+ }
+}