Index: android_webview/java/src/org/chromium/android_webview/PostMessageSender.java |
diff --git a/android_webview/java/src/org/chromium/android_webview/PostMessageSender.java b/android_webview/java/src/org/chromium/android_webview/PostMessageSender.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..1159c1bb6e3a2c86ad72a5397ee4d97350c58d5a |
--- /dev/null |
+++ b/android_webview/java/src/org/chromium/android_webview/PostMessageSender.java |
@@ -0,0 +1,149 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+package org.chromium.android_webview; |
+ |
+import java.util.ArrayDeque; |
hush (inactive)
2015/02/13 03:25:08
please add a new line after this.
sgurun-gerrit only
2015/02/13 05:11:59
Done.
|
+/** |
+ * Sanity checks and sends post messages to web. Queues messages if necessary. |
+ */ |
+public class PostMessageSender implements AwMessagePortService.MessageChannelObserver { |
+ |
+ /** |
+ * The interface for message handler. |
+ */ |
+ public static interface PostMessageSenderDelegate { |
+ void postMessageToWeb(String frameName, String message, String sourceOrigin, |
+ String targetOrigin, int[] sentPorts); |
+ }; |
+ |
+ // A struct to store Message parameters that are sent from App to Web. |
+ private static class PostMessageParams { |
+ public String frameName; |
+ public String message; |
+ public String sourceOrigin; |
+ public String targetOrigin; |
+ public MessagePort[] sentPorts; |
+ |
+ public PostMessageParams(String frameName, String message, String sourceOrigin, |
+ String targetOrigin, MessagePort[] sentPorts) { |
+ this.frameName = frameName; |
+ this.message = message; |
+ this.sourceOrigin = sourceOrigin; |
+ this.targetOrigin = targetOrigin; |
+ this.sentPorts = sentPorts; |
+ } |
+ } |
+ |
+ private PostMessageSenderDelegate mDelegate; |
+ private AwMessagePortService mService; |
+ |
+ // If a message that is sent from android webview to web has a pending port (a port that |
+ // is not internally created yet), this message, and any following messages will be |
+ // queued until the transferred port becomes ready. This is necessary to prevent any |
+ // reordering. |
+ private boolean mShouldQueue = false; |
+ private ArrayDeque<PostMessageParams> mMessageQueue = new ArrayDeque<PostMessageParams>(); |
+ |
+ public PostMessageSender(PostMessageSenderDelegate delegate, AwMessagePortService service) { |
+ mDelegate = delegate; |
+ mService = service; |
+ } |
+ |
+ // Return true if any sent port is pending. |
+ private boolean anySentPortIsPending(MessagePort[] sentPorts) { |
+ if (sentPorts != null) { |
+ for (MessagePort port : sentPorts) { |
+ if (!port.isReady()) { |
+ return true; |
+ } |
+ } |
+ } |
+ return false; |
+ } |
+ |
+ // By default the sender is always ready. |
+ protected boolean senderIsReady() { |
+ return true; |
+ } |
+ |
+ // A message to a frame is queued if: |
+ // 1. Sender is not ready to post. When posting messages to frames, sender is always |
+ // ready. However, when posting messages using message channels, sender may be in |
+ // a pending state. |
+ // 2. The mShouldQueue mode is already on. Having mShouldQueue mode true means |
+ // there is a already a message with a pending port in queue. |
+ // 3. The message includes a port that is not ready yet. |
+ private boolean shouldQueueMessage(MessagePort[] sentPorts) { |
+ // if messages to frames are already in queue mode, simply queue it, no need to |
+ // check ports. |
+ if (mShouldQueue || !senderIsReady()) { |
+ return true; |
+ } |
+ if (anySentPortIsPending(sentPorts)) { |
+ mShouldQueue = true; |
hush (inactive)
2015/02/13 03:25:08
I feel it is weird that a method that looks like i
sgurun-gerrit only
2015/02/13 05:11:59
this is a private method so I did not worry too mu
|
+ return true; |
+ } |
+ return false; |
+ } |
+ |
+ private void postMessageToWeb(String frameName, String message, String sourceOrigin, |
+ String targetOrigin, MessagePort[] sentPorts) { |
+ int[] portIds = null; |
+ if (sentPorts != null) { |
+ portIds = new int[sentPorts.length]; |
+ for (int i = 0; i < sentPorts.length; i++) { |
+ portIds[i] = sentPorts[i].portId(); |
+ } |
+ mService.removeSentPorts(portIds); |
+ } |
+ mDelegate.postMessageToWeb(frameName, message, sourceOrigin, targetOrigin, portIds); |
+ } |
+ |
+ /* |
+ * Sanity checks the message and queues it if necessary. Posts the message to delegate |
+ * when message can be sent. |
+ */ |
+ public void postMessage(String frameName, String message, String sourceOrigin, |
hush (inactive)
2015/02/13 03:25:08
name it postMessageIfPossible?
sgurun-gerrit only
2015/02/13 05:11:59
I think the name is compatible with HTML5 MessageP
|
+ String targetOrigin, MessagePort[] sentPorts) throws IllegalStateException { |
+ // Sanity check all the ports that are being transferred. |
+ if (sentPorts != null) { |
+ for (MessagePort p : sentPorts) { |
+ if (p.isClosed() || p.isTransferred()) { |
+ throw new IllegalStateException("Port cannot be transferred"); |
+ } |
+ p.setTransferred(); |
+ } |
+ } |
+ if (shouldQueueMessage(sentPorts)) { |
+ mMessageQueue.add(new PostMessageParams(frameName, message, sourceOrigin, |
+ targetOrigin, sentPorts)); |
+ } else { |
+ postMessageToWeb(frameName, message, sourceOrigin, targetOrigin, sentPorts); |
+ } |
+ } |
+ |
+ /* |
+ * Starts posting any messages that are queued. |
+ */ |
+ public void onMessageChannelCreated() { |
+ PostMessageParams msg; |
+ |
+ if (!senderIsReady()) { |
+ return; |
+ } |
+ |
+ while ((msg = mMessageQueue.peek()) != null) { |
+ // If there are still pending ports, message cannot be posted. |
+ if (anySentPortIsPending(msg.sentPorts)) { |
+ return; |
+ } |
+ mMessageQueue.remove(); |
+ postMessageToWeb(msg.frameName, msg.message, msg.sourceOrigin, msg.targetOrigin, |
+ msg.sentPorts); |
+ } |
+ // No more messages in the queue. |
+ mShouldQueue = false; |
+ } |
+} |