incubator-callback-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From agri...@apache.org
Subject [4/6] android commit: Refactor Native->JS messaging logic into its own class.
Date Wed, 22 Aug 2012 13:57:11 GMT
Refactor Native->JS messaging logic into its own class.

This will make it easy to add more modes.
This also adds logic to set the move via a prompt() from JS.


Project: http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/commit/5e3e9ddb
Tree: http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/tree/5e3e9ddb
Diff: http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/diff/5e3e9ddb

Branch: refs/heads/master
Commit: 5e3e9ddb8e8aadbb4b864b9b6946a8fea9b50144
Parents: a9a5284
Author: Andrew Grieve <agrieve@chromium.org>
Authored: Fri Aug 10 12:55:29 2012 -0400
Committer: Andrew Grieve <agrieve@chromium.org>
Committed: Wed Aug 22 09:46:30 2012 -0400

----------------------------------------------------------------------
 .../src/org/apache/cordova/CallbackServer.java     |   82 ++------
 .../org/apache/cordova/CordovaChromeClient.java    |   12 +-
 .../src/org/apache/cordova/CordovaWebView.java     |   12 +-
 .../org/apache/cordova/CordovaWebViewClient.java   |   10 +-
 framework/src/org/apache/cordova/DroidGap.java     |    4 +-
 .../org/apache/cordova/NativeToJsMessageQueue.java |  163 +++++++++++++++
 6 files changed, 201 insertions(+), 82 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/blob/5e3e9ddb/framework/src/org/apache/cordova/CallbackServer.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/CallbackServer.java b/framework/src/org/apache/cordova/CallbackServer.java
index b8075b5..d0296a3 100755
--- a/framework/src/org/apache/cordova/CallbackServer.java
+++ b/framework/src/org/apache/cordova/CallbackServer.java
@@ -59,8 +59,9 @@ public class CallbackServer implements Runnable {
     private ServerSocket waitSocket;
     /**
      * The list of JavaScript statements to be sent to JavaScript.
+     * This can be null when there are no messages available.
      */
-    private LinkedList<String> javascript;
+    private NativeToJsMessageQueue jsMessageQueue;
 
     /**
      * The port to listen on.
@@ -77,10 +78,6 @@ public class CallbackServer implements Runnable {
      */
     private boolean active;
 
-    /**
-     * Indicates that the JavaScript statements list is empty
-     */
-    private boolean empty;
 
     /**
      * Indicates that polling should be used instead of XHR.
@@ -98,9 +95,7 @@ public class CallbackServer implements Runnable {
     public CallbackServer() {
         //Log.d(LOG_TAG, "CallbackServer()");
         this.active = false;
-        this.empty = true;
         this.port = 0;
-        this.javascript = new LinkedList<String>();
     }
 
     /**
@@ -113,10 +108,8 @@ public class CallbackServer implements Runnable {
      */
     public void init(String url) {
         //System.out.println("CallbackServer.start("+url+")");
-        this.active = false;
-        this.empty = true;
+        this.stopServer();
         this.port = 0;
-        this.javascript = new LinkedList<String>();
 
         // Determine if XHR or polling is to be used
         if ((url != null) && !url.startsWith("file://")) {
@@ -134,16 +127,6 @@ public class CallbackServer implements Runnable {
     }
 
     /**
-     * Re-init when loading a new HTML page into webview.
-     *
-     * @param url           The URL of the Cordova app being loaded
-     */
-    public void reinit(String url) {
-        this.stopServer();
-        this.init(url);
-    }
-
-    /**
      * Return if polling is being used instead of XHR.
      * @return
      */
@@ -224,11 +207,19 @@ public class CallbackServer implements Runnable {
                         // Must have security token
                         if ((requestParts.length == 3) && (requestParts[1].substring(1).equals(this.token)))
{
                             //Log.d(LOG_TAG, "CallbackServer -- Processing GET request");
+                        	String js = null;
 
                             // Wait until there is some data to send, or send empty data
every 10 sec 
                             // to prevent XHR timeout on the client 
                             synchronized (this) {
-                                while (this.empty) {
+                                while (this.active) {
+                                	if (jsMessageQueue != null) {
+                                		// TODO(agrieve): Should this use popAll() instead?
+                                		js = jsMessageQueue.pop();
+                                	    if (js != null) {
+                                	    	break;
+                                	    }
+                                	}
                                     try {
                                         this.wait(10000); // prevent timeout from happening
                                         //Log.d(LOG_TAG, "CallbackServer>>> break
<<<");
@@ -242,17 +233,14 @@ public class CallbackServer implements Runnable {
                             if (this.active) {
 
                                 // If no data, then send 404 back to client before it times
out
-                                if (this.empty) {
+                                if (js == null) {
                                     //Log.d(LOG_TAG, "CallbackServer -- sending data 0");
                                     response = "HTTP/1.1 404 NO DATA\r\n\r\n "; // need to
send content otherwise some Android devices fail, so send space
                                 }
                                 else {
                                     //Log.d(LOG_TAG, "CallbackServer -- sending item");
                                     response = "HTTP/1.1 200 OK\r\n\r\n";
-                                    String js = this.getJavascript();
-                                    if (js != null) {
-                                        response += encode(js, "UTF-8");
-                                    }
+                                    response += encode(js, "UTF-8");
                                 }
                             }
                             else {
@@ -305,46 +293,10 @@ public class CallbackServer implements Runnable {
     public void destroy() {
         this.stopServer();
     }
-
-    /**
-     * Get the number of JavaScript statements.
-     * 
-     * @return int
-     */
-    public int getSize() {
-        synchronized (this) {
-            int size = this.javascript.size();
-            return size;
-        }
-    }
-
-    /**
-     * Get the next JavaScript statement and remove from list.
-     *  
-     * @return String
-     */
-    public String getJavascript() {
-        synchronized (this) {
-            if (this.javascript.size() == 0) {
-                return null;
-            }
-            String statement = this.javascript.remove(0);
-            if (this.javascript.size() == 0) {
-                this.empty = true;
-            }
-            return statement;
-        }
-    }
-
-    /**
-     * Add a JavaScript statement to the list.
-     * 
-     * @param statement
-     */
-    public void sendJavascript(String statement) {
+    
+	public void onNativeToJsMessageAvailable(NativeToJsMessageQueue queue) {
         synchronized (this) {
-            this.javascript.add(statement);
-            this.empty = false;
+        	this.jsMessageQueue = queue;
             this.notify();
         }
     }

http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/blob/5e3e9ddb/framework/src/org/apache/cordova/CordovaChromeClient.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/CordovaChromeClient.java b/framework/src/org/apache/cordova/CordovaChromeClient.java
index cdfc9d1..7feee19 100755
--- a/framework/src/org/apache/cordova/CordovaChromeClient.java
+++ b/framework/src/org/apache/cordova/CordovaChromeClient.java
@@ -23,12 +23,9 @@ import org.apache.cordova.api.LOG;
 import org.json.JSONArray;
 import org.json.JSONException;
 
-//import android.app.Activity;
 import android.app.AlertDialog;
-//import android.content.Context;
 import android.content.DialogInterface;
 import android.view.KeyEvent;
-//import android.view.View;
 import android.webkit.ConsoleMessage;
 import android.webkit.JsPromptResult;
 import android.webkit.JsResult;
@@ -211,9 +208,16 @@ public class CordovaChromeClient extends WebChromeClient {
             }
         }
 
+        // Sets the native->JS bridge mode. 
+        else if (reqOk && defaultValue != null && defaultValue.equals("gap_bridge_mode:"))
{
+            this.appView.jsMessageQueue.setBridgeMode(Integer.parseInt(message));
+            result.confirm("");
+        }
+
         // Polling for JavaScript messages 
         else if (reqOk && defaultValue != null && defaultValue.equals("gap_poll:"))
{
-            String r = this.appView.callbackServer.getJavascript();
+        	// TODO(agrieve): Use popAll() here.
+            String r = this.appView.jsMessageQueue.pop();
             result.confirm(r);
         }
 

http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/blob/5e3e9ddb/framework/src/org/apache/cordova/CordovaWebView.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/CordovaWebView.java b/framework/src/org/apache/cordova/CordovaWebView.java
index 85c3cd8..131f754 100755
--- a/framework/src/org/apache/cordova/CordovaWebView.java
+++ b/framework/src/org/apache/cordova/CordovaWebView.java
@@ -88,6 +88,8 @@ public class CordovaWebView extends WebView {
 
     private boolean handleButton = false;
 
+	NativeToJsMessageQueue jsMessageQueue;
+
     /**
      * Constructor.
      *
@@ -190,14 +192,14 @@ public class CordovaWebView extends WebView {
         }
     }
 
-    
     /**
      * Initialize webview.
      */
     @SuppressWarnings("deprecation")
     @SuppressLint("NewApi")
     private void setup() {
-
+    	jsMessageQueue = new NativeToJsMessageQueue(this);
+    	
         this.setInitialScale(0);
         this.setVerticalScrollBarEnabled(false);
         this.requestFocusFromTouch();
@@ -456,7 +458,7 @@ public class CordovaWebView extends WebView {
      *
      * @param url
      */
-    private void loadUrlNow(String url) {
+    void loadUrlNow(String url) {
         LOG.d(TAG, ">>> loadUrlNow()");
         super.loadUrl(url);
     }
@@ -495,9 +497,7 @@ public class CordovaWebView extends WebView {
      * @param message
      */
     public void sendJavascript(String statement) {
-        if (this.callbackServer != null) {
-            this.callbackServer.sendJavascript(statement);
-        }
+        this.jsMessageQueue.add(statement);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/blob/5e3e9ddb/framework/src/org/apache/cordova/CordovaWebViewClient.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/CordovaWebViewClient.java b/framework/src/org/apache/cordova/CordovaWebViewClient.java
index 6e4ff7f..037f200 100755
--- a/framework/src/org/apache/cordova/CordovaWebViewClient.java
+++ b/framework/src/org/apache/cordova/CordovaWebViewClient.java
@@ -230,14 +230,14 @@ public class CordovaWebViewClient extends WebViewClient {
             this.doClearHistory = true;
         }
 
-        // Create callback server and plugin manager
+        // Flush stale messages.
+        this.appView.jsMessageQueue.reset();
+
+        // Create callback server
         if (this.appView.callbackServer == null) {
             this.appView.callbackServer = new CallbackServer();
-            this.appView.callbackServer.init(url);
-        }
-        else {
-            this.appView.callbackServer.reinit(url);
         }
+        this.appView.callbackServer.init(url);
 
         // Broadcast message that page has loaded
         this.appView.postMessage("onPageStarted", url);

http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/blob/5e3e9ddb/framework/src/org/apache/cordova/DroidGap.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/DroidGap.java b/framework/src/org/apache/cordova/DroidGap.java
index 68dbe08..03ca2ad 100755
--- a/framework/src/org/apache/cordova/DroidGap.java
+++ b/framework/src/org/apache/cordova/DroidGap.java
@@ -714,8 +714,8 @@ public class DroidGap extends Activity implements CordovaInterface {
      * @param message
      */
     public void sendJavascript(String statement) {
-        if (this.appView != null && this.appView.callbackServer != null) {
-            this.appView.callbackServer.sendJavascript(statement);
+        if (this.appView != null) {
+            this.appView.jsMessageQueue.add(statement);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/blob/5e3e9ddb/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/NativeToJsMessageQueue.java b/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
new file mode 100755
index 0000000..037cc9c
--- /dev/null
+++ b/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
@@ -0,0 +1,163 @@
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you 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 org.apache.cordova;
+
+import java.util.LinkedList;
+
+import android.util.Log;
+
+/**
+ * Holds the list of messages to be sent to the WebView.
+ */
+public class NativeToJsMessageQueue {
+    private static final String LOG_TAG = "JsMessageQueue";
+
+    // This must match the default value in incubator-cordova-js/lib/android/exec.js
+    private static final int DEFAULT_BRIDGE_MODE = 1;
+    
+    /**
+     * The list of JavaScript statements to be sent to JavaScript.
+     */
+    private LinkedList<String> queue = new LinkedList<String>();
+
+    /**
+     * The index into registeredListeners to treat as active. 
+     */
+    private int activeListenerIndex;
+    
+    /**
+     * The array of listeners that can be used to send messages to JS.
+     */
+    private BridgeMode[] registeredListeners;    
+        
+    public NativeToJsMessageQueue(CordovaWebView webView) {
+    	registeredListeners = new BridgeMode[2];
+    	registeredListeners[0] = null;
+    	registeredListeners[1] = new CallbackBridgeMode(webView);
+    	reset();
+//        POLLING: 0,
+//        HANGING_GET: 1,
+//        LOAD_URL: 2,
+//        ONLINE_EVENT: 3,
+//        PRIVATE_API: 4
+    }
+    
+    /**
+     * Changes the bridge mode.
+     */
+    public void setBridgeMode(int value) {
+    	if (value < 0 || value >= registeredListeners.length) {
+    		Log.d(LOG_TAG, "Invalid NativeToJsBridgeMode: " + value);
+    	} else {
+    		if (value != activeListenerIndex) {
+    			Log.d(LOG_TAG, "Set native->JS mode to " + value);
+    			synchronized (this) {
+    			    activeListenerIndex = value;
+    			    BridgeMode activeListener = registeredListeners[value];
+    			    if (!queue.isEmpty() && activeListener != null) {
+    			    	activeListener.onNativeToJsMessageAvailable(this);
+    			    }
+    			}
+    		}
+    	}
+    }
+    
+	/**
+	 * Clears all messages and resets to the default bridge mode.
+     */
+    public void reset() {
+    	synchronized (this) {
+    		queue.clear();
+    		setBridgeMode(DEFAULT_BRIDGE_MODE);
+    	}
+    }
+
+    /**
+     * Removes and returns the last statement in the queue.
+     * Returns null if the queue is empty.
+     */
+    public String pop() {
+        synchronized (this) {
+            if (queue.isEmpty()) {
+                return null;
+            }
+            return queue.remove(0);
+        }
+    }
+
+    /**
+     * Combines and returns all statements. Clears the queue.
+     * Returns null if the queue is empty.
+     */
+    public String popAll() {
+        synchronized (this) {
+            int length = queue.size();
+            if (length == 0) {
+                return null;
+            }
+            StringBuffer sb = new StringBuffer();
+            // Wrap each statement in a try/finally so that if one throws it does 
+            // not affect the next.
+            int i = 0;
+			for (String message : queue) {
+            	if (++i == length) {
+            		sb.append(message);
+            	} else {
+	            	sb.append("try{")
+	            	  .append(message)
+	            	  .append("}finally{");
+            	}
+            }
+            for ( i = 1; i < length; ++i) {
+            	sb.append('}');
+            }
+            queue.clear();
+            return sb.toString();
+        }
+    }    
+
+    /**
+     * Add a JavaScript statement to the list.
+     */
+    public void add(String statement) {
+        synchronized (this) {
+            queue.add(statement);
+            if (registeredListeners[activeListenerIndex] != null) {
+            	registeredListeners[activeListenerIndex].onNativeToJsMessageAvailable(this);
+            }
+        }
+    }
+
+    private interface BridgeMode {
+		void onNativeToJsMessageAvailable(NativeToJsMessageQueue queue);
+	}
+	
+    private static class CallbackBridgeMode implements BridgeMode {
+    	private CordovaWebView webView;
+		public CallbackBridgeMode(CordovaWebView webView) {
+    		this.webView = webView;
+    	}
+    	public void onNativeToJsMessageAvailable(NativeToJsMessageQueue queue) {
+    		if (webView.callbackServer != null) {
+    			webView.callbackServer.onNativeToJsMessageAvailable(queue);
+    		}
+        }
+    }
+
+}


Mime
View raw message