-Formatting source files prior to additional changes.

Change-Id: I9d653eb70163dba83d21f0dc74f6459c3bb391b2
diff --git a/Common/src/com/googlecode/android_scripting/facade/EventFacade.java b/Common/src/com/googlecode/android_scripting/facade/EventFacade.java
index 4b65c99..3680f61 100644
--- a/Common/src/com/googlecode/android_scripting/facade/EventFacade.java
+++ b/Common/src/com/googlecode/android_scripting/facade/EventFacade.java
@@ -1,422 +1,455 @@
-/*

- * Copyright (C) 2010 Google Inc.

- *

- * 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 com.googlecode.android_scripting.facade;

-

-import android.content.Context;

-import android.content.Intent;

-import android.content.IntentFilter;

-import android.os.Bundle;

-

-import com.google.common.collect.ArrayListMultimap;

-import com.google.common.collect.Lists;

-import com.google.common.collect.Multimap;

-import com.google.common.collect.Multimaps;

-import com.googlecode.android_scripting.Log;

-import com.googlecode.android_scripting.event.Event;

-import com.googlecode.android_scripting.future.FutureResult;

-import com.googlecode.android_scripting.jsonrpc.JsonBuilder;

-import com.googlecode.android_scripting.jsonrpc.RpcReceiver;

-import com.googlecode.android_scripting.rpc.Rpc;

-import com.googlecode.android_scripting.rpc.RpcDefault;

-import com.googlecode.android_scripting.rpc.RpcDeprecated;

-import com.googlecode.android_scripting.rpc.RpcName;

-import com.googlecode.android_scripting.rpc.RpcOptional;

-import com.googlecode.android_scripting.rpc.RpcParameter;

-

-import java.util.HashMap;

-import java.util.List;

-import java.util.Queue;

-import java.util.Set;

-import java.util.concurrent.ConcurrentLinkedQueue;

-import java.util.concurrent.CopyOnWriteArrayList;

-import java.util.concurrent.TimeUnit;

-

-import org.json.JSONException;

-

-/**

- * Manage the event queue. <br>

- * <br>

- * <b>Usage Notes:</b><br>

- * EventFacade APIs interact with the Event Queue (a data buffer containing up to 1024 event

- * entries).<br>

- * Events are automatically entered into the Event Queue following API calls such as startSensing()

- * and startLocating().<br>

- * The Event Facade provides control over how events are entered into (and removed from) the Event

- * Queue.<br>

- * The Event Queue provides a useful means of recording background events (such as sensor data) when

- * the phone is busy with foreground activities.

- * 

- * @author Felix Arends (felix.arends@gmail.com)

- * 

- */

-public class EventFacade extends RpcReceiver {

-  /**

-   * The maximum length of the event queue. Old events will be discarded when this limit is

-   * exceeded.

-   */

-  private static final int MAX_QUEUE_SIZE = 1024;

-  private final Queue<Event> mEventQueue = new ConcurrentLinkedQueue<Event>();

-  private final CopyOnWriteArrayList<EventObserver> mGlobalEventObservers =

-      new CopyOnWriteArrayList<EventObserver>();

-  private final Multimap<String, EventObserver> mNamedEventObservers = Multimaps

-      .synchronizedListMultimap(ArrayListMultimap.<String, EventObserver> create());

-  private EventServer mEventServer = null;

-  private final HashMap<String, BroadcastListener> mBroadcastListeners =

-      new HashMap<String, BroadcastListener>();

-  private final Context mContext;

-  private boolean bEventServerRunning;

-

-  public EventFacade(FacadeManager manager) {

-    super(manager);

-    mContext = manager.getService().getApplicationContext();

-    Log.v("Creating new EventFacade Instance()");

-    bEventServerRunning = false;

-  }

-

-  /**

-   * Example (python): droid.eventClearBuffer()

-   */

-  @Rpc(description = "Clears all events from the event buffer.")

-  public void eventClearBuffer() {

-    mEventQueue.clear();

-  }

-

-  /**

-   * Registers a listener for a new broadcast signal

-   */

-  @Rpc(description = "Registers a listener for a new broadcast signal")

-  public boolean eventRegisterForBroadcast(

-      @RpcParameter(name = "category") String category,

-      @RpcParameter(name = "enqueue", description = "Should this events be added to the event queue or only dispatched") @RpcDefault(value = "true") Boolean enqueue) {

-    if (mBroadcastListeners.containsKey(category)) {

-      return false;

-    }

-

-    BroadcastListener b = new BroadcastListener(this, enqueue.booleanValue());

-    IntentFilter c = new IntentFilter(category);

-    mContext.registerReceiver(b, c);

-    mBroadcastListeners.put(category, b);

-

-    return true;

-  }

-

-  @Rpc(description = "Stop listening for a broadcast signal")

-  public void eventUnregisterForBroadcast(@RpcParameter(name = "category") String category) {

-    if (!mBroadcastListeners.containsKey(category)) {

-      return;

-    }

-

-    mContext.unregisterReceiver(mBroadcastListeners.get(category));

-    mBroadcastListeners.remove(category);

-  }

-

-  @Rpc(description = "Lists all the broadcast signals we are listening for")

-  public Set<String> eventGetBrodcastCategories() {

-    return mBroadcastListeners.keySet();

-  }

-

-  /**

-   * Actual data returned in the map will depend on the type of event.

-   * 

-   * <pre>

-   * Example (python):

-   *     import android, time

-   *     droid = android.Android()

-   *     droid.startSensing()

-   *     time.sleep(1)

-   *     droid.eventClearBuffer()

-   *     time.sleep(1)

-   *     e = eventPoll(1).result

-   *     event_entry_number = 0

-   *     x = e[event_entry_ number]['data']['xforce']

-   * </pre>

-   * 

-   * e has the format:<br>

-   * [{u'data': {u'accuracy': 0, u'pitch': -0.48766891956329345, u'xmag': -5.6875, u'azimuth':

-   * 0.3312483489513397, u'zforce': 8.3492730000000002, u'yforce': 4.5628165999999997, u'time':

-   * 1297072704.813, u'ymag': -11.125, u'zmag': -42.375, u'roll': -0.059393649548292161, u'xforce':

-   * 0.42223078000000003}, u'name': u'sensors', u'time': 1297072704813000L}]<br>

-   * x has the string value of the x force data (0.42223078000000003) at the time of the event

-   * entry. </pre>

-   */

-

-  @Rpc(description = "Returns and removes the oldest n events (i.e. location or sensor update, etc.) from the event buffer.", returns = "A List of Maps of event properties.")

-  public List<Event> eventPoll(

-      @RpcParameter(name = "number_of_events") @RpcDefault("1") Integer number_of_events) {

-    List<Event> events = Lists.newArrayList();

-    for (int i = 0; i < number_of_events; i++) {

-      Event event = mEventQueue.poll();

-      if (event == null) {

-        break;

-      }

-      events.add(event);

-    }

-    return events;

-  }

-

-  @Rpc(description = "Blocks until an event with the supplied name occurs. Event is removed from the buffer if removeEvent is True.",

-      returns = "Map of event properties.")

-  public Event eventWaitFor(

-      @RpcParameter(name = "eventName") final String eventName,

-      @RpcParameter(name = "removeEvent") final Boolean removeEvent,

-      @RpcParameter(name = "timeout", description = "the maximum time to wait (in ms)") @RpcOptional Integer timeout)

-      throws InterruptedException {

-    Event result = null;

-    final FutureResult<Event> futureEvent;

-    synchronized (mEventQueue) { // First check to make sure it isn't already there

-      for (Event event : mEventQueue) {

-        if (event.getName().equals(eventName)) {

-          result = event;

-          if(removeEvent)

-            mEventQueue.remove(event);

-          return result;

-        }

-      }

-      futureEvent = new FutureResult<Event>();

-      addNamedEventObserver(eventName, new EventObserver() {

-        @Override

-        public void onEventReceived(Event event) {

-          if (event.getName().equals(eventName)) {

-            synchronized (futureEvent) {

-              if (!futureEvent.isDone()) {

-                futureEvent.set(event);

-                //TODO(navtej) Remove log.

-                Log.v(String.format("Removeing observer (%s) got event  (%s)",this, event));

-                removeEventObserver(this);

-              }

-              if(removeEvent)

-                mEventQueue.remove(event);

-            }

-          }

-        }

-      });

-    }

-    if (futureEvent != null) {

-      if (timeout != null) {

-        result = futureEvent.get(timeout, TimeUnit.MILLISECONDS);

-      } else {

-        result = futureEvent.get();

-      }

-    }

-    return result;

-  }

-

-  @Rpc(description = "Blocks until an event occurs. The returned event is removed from the buffer.", returns = "Map of event properties.")

-  public Event eventWait(

-      @RpcParameter(name = "timeout", description = "the maximum time to wait") @RpcOptional Integer timeout)

-      throws InterruptedException {

-    Event result = null;

-    final FutureResult<Event> futureEvent = new FutureResult<Event>();

-    EventObserver observer;

-    synchronized (mEventQueue) { // Anything in queue?

-      if (mEventQueue.size() > 0) {

-         return mEventQueue.poll(); // return it.

-      }

-      observer = new EventObserver() {

-        @Override

-        public void onEventReceived(Event event) { // set up observer for any events.

-          synchronized (futureEvent) {

-            if (!futureEvent.isDone()) {

-              futureEvent.set(event);

-              //TODO(navtej) Remove log.

-              Log.v(String.format("onEventReceived for event (%s)", event));

-            }

-            mEventQueue.remove(event);

-          }

-        }

-      };

-      addGlobalEventObserver(observer);

-    }

-    if (timeout != null) {

-        result = futureEvent.get(timeout, TimeUnit.MILLISECONDS);

-        if(result == null){

-          result = new Event( "eventTimeout", null);

-        }

-    } else {

-        result = futureEvent.get();

-    }

-    //TODO(navtej) Remove log.

-    Log.v(String.format("Removeing observer (%s) got event  (%s)", observer, result ));

-    if (observer != null) {

-      removeEventObserver(observer); // Make quite sure this goes away.

-    }

-    return result;

-  }

-

-  /**

-   * <pre>

-   * Example:

-   *   import android

-   *   from datetime import datetime

-   *   droid = android.Android()

-   *   t = datetime.now()

-   *   droid.eventPost('Some Event', t)

-   * </pre>

-   */

-  @Rpc(description = "Post an event to the event queue.")

-  public void eventPost(

-      @RpcParameter(name = "name", description = "Name of event") String name,

-      @RpcParameter(name = "data", description = "Data contained in event.") String data,

-      @RpcParameter(name = "enqueue", description = "Set to False if you don't want your events to be added to the event queue, just dispatched.") @RpcOptional @RpcDefault("false") Boolean enqueue) {

-    postEvent(name, data, enqueue.booleanValue());

-  }

-

-  /**

-   * Post an event and queue it

-   */

-  public void postEvent(String name, Object data) {

-    postEvent(name, data, true);

-  }

-

-  /**

-   * Posts an event with to the event queue.

-   */

-  public void postEvent(String name, Object data, boolean enqueue) {

-    Event event = new Event(name, data);

-    if (enqueue != false) {

-      synchronized (mEventQueue) {

-        while (mEventQueue.size() >= MAX_QUEUE_SIZE) {

-          mEventQueue.remove();

-        }

-        mEventQueue.add(event);

-      }

-      Log.v(String.format("postEvent(%s)", name));

-    }

-    synchronized (mNamedEventObservers) {

-      for (EventObserver observer : mNamedEventObservers.get(name)) {

-        observer.onEventReceived(event);

-      }

-    }

-    synchronized (mGlobalEventObservers) {

-      //TODO(navtej) Remove log.

-      Log.v(String.format("mGlobalEventObservers size (%s)", mGlobalEventObservers.size()));

-      for (EventObserver observer : mGlobalEventObservers) {

-        observer.onEventReceived(event);

-      }

-    }

-  }

-

-  @RpcDeprecated(value = "eventPost", release = "r4")

-  @Rpc(description = "Post an event to the event queue.")

-  @RpcName(name = "postEvent")

-  public void rpcPostEvent(@RpcParameter(name = "name") String name,

-      @RpcParameter(name = "data") String data) {

-    postEvent(name, data);

-  }

-

-  @RpcDeprecated(value = "eventPoll", release = "r4")

-  @Rpc(description = "Returns and removes the oldest event (i.e. location or sensor update, etc.) from the event buffer.", returns = "Map of event properties.")

-  public Event receiveEvent() {

-    return mEventQueue.poll();

-  }

-

-  @RpcDeprecated(value = "eventWaitFor", release = "r4")

-  @Rpc(description = "Blocks until an event with the supplied name occurs. Event is removed from the buffer if removeEvent is True.",

-   returns = "Map of event properties.")

-  public Event waitForEvent(

-      @RpcParameter(name = "eventName") final String eventName,

-      @RpcOptional final Boolean removeEvent,

-      @RpcParameter(name = "timeout", description = "the maximum time to wait") @RpcOptional Integer timeout)

-      throws InterruptedException {

-    return eventWaitFor(eventName, removeEvent, timeout);

-  }

-

-  @Rpc(description = "Opens up a socket where you can read for events posted")

-  public int startEventDispatcher(

-      @RpcParameter(name = "port", description = "Port to use") @RpcDefault("0") @RpcOptional() Integer port) {

-    if (mEventServer == null) {

-      if (port == null) {

-        port = 0;

-      }

-      mEventServer = new EventServer(port);

-      addGlobalEventObserver(mEventServer);

-      bEventServerRunning = true;

-    }

-    return mEventServer.getAddress().getPort();

-  }

-

-  @Rpc(description = "Stops the event server, you can't read in the port anymore")

-  public void stopEventDispatcher() throws RuntimeException {

-    if (bEventServerRunning == true) {

-      if (mEventServer == null) {

-        throw new RuntimeException("Not running");

-      }

-      bEventServerRunning = false;

-      mEventServer.shutdown();

-      Log.v(String.format("stopEventDispatcher   (%s)", mEventServer ));

-      removeEventObserver(mEventServer);

-      mEventServer = null;

-    }

-    return;

-  }

-

-  @Override

-  public void shutdown() {

-

-    try {

-      stopEventDispatcher();

-    } catch (Exception e) {

-      Log.e("Exception tearing down event dispatcher", e);

-    }

-    mGlobalEventObservers.clear();

-    mEventQueue.clear();

-  }

-

-  public void addNamedEventObserver(String eventName, EventObserver observer) {

-    mNamedEventObservers.put(eventName, observer);

-  }

-

-  public void addGlobalEventObserver(EventObserver observer) {

-    mGlobalEventObservers.add(observer);

-  }

-

-  public void removeEventObserver(EventObserver observer) {

-    mNamedEventObservers.removeAll(observer);

-    mGlobalEventObservers.remove(observer);

-  }

-

-  public interface EventObserver {

-    public void onEventReceived(Event event);

-  }

-

-  public class BroadcastListener extends android.content.BroadcastReceiver {

-    private EventFacade mParent;

-    private boolean mEnQueue;

-

-    public BroadcastListener(EventFacade parent, boolean enqueue) {

-      mParent = parent;

-      mEnQueue = enqueue;

-    }

-

-    @Override

-    public void onReceive(Context context, Intent intent) {

-      Bundle data;

-      if (intent.getExtras() != null) {

-        data = (Bundle) intent.getExtras().clone();

-      } else {

-        data = new Bundle();

-      }

-      data.putString("action", intent.getAction());

-      try {

-        mParent.eventPost("sl4a", JsonBuilder.build(data).toString(), mEnQueue);

-      } catch (JSONException e) {

-        e.printStackTrace();

-      }

-    }

-

-  }

-}

+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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 com.googlecode.android_scripting.facade;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
+import com.googlecode.android_scripting.Log;
+import com.googlecode.android_scripting.event.Event;
+import com.googlecode.android_scripting.future.FutureResult;
+import com.googlecode.android_scripting.jsonrpc.JsonBuilder;
+import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
+import com.googlecode.android_scripting.rpc.Rpc;
+import com.googlecode.android_scripting.rpc.RpcDefault;
+import com.googlecode.android_scripting.rpc.RpcDeprecated;
+import com.googlecode.android_scripting.rpc.RpcName;
+import com.googlecode.android_scripting.rpc.RpcOptional;
+import com.googlecode.android_scripting.rpc.RpcParameter;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Queue;
+import java.util.Set;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.TimeUnit;
+
+import org.json.JSONException;
+
+/**
+ * Manage the event queue. <br>
+ * <br>
+ * <b>Usage Notes:</b><br>
+ * EventFacade APIs interact with the Event Queue (a data buffer containing up to 1024 event
+ * entries).<br>
+ * Events are automatically entered into the Event Queue following API calls such as startSensing()
+ * and startLocating().<br>
+ * The Event Facade provides control over how events are entered into (and removed from) the Event
+ * Queue.<br>
+ * The Event Queue provides a useful means of recording background events (such as sensor data) when
+ * the phone is busy with foreground activities.
+ *
+ * @author Felix Arends (felix.arends@gmail.com)
+ */
+public class EventFacade extends RpcReceiver {
+    /**
+     * The maximum length of the event queue. Old events will be discarded when this limit is
+     * exceeded.
+     */
+    private static final int MAX_QUEUE_SIZE = 1024;
+    private final Queue<Event> mEventQueue = new ConcurrentLinkedQueue<Event>();
+    private final CopyOnWriteArrayList<EventObserver> mGlobalEventObservers =
+            new CopyOnWriteArrayList<EventObserver>();
+    private final Multimap<String, EventObserver> mNamedEventObservers = Multimaps
+            .synchronizedListMultimap(ArrayListMultimap.<String, EventObserver> create());
+    private EventServer mEventServer = null;
+    private final HashMap<String, BroadcastListener> mBroadcastListeners =
+            new HashMap<String, BroadcastListener>();
+    private final Context mContext;
+    private boolean bEventServerRunning;
+
+    public EventFacade(FacadeManager manager) {
+        super(manager);
+        mContext = manager.getService().getApplicationContext();
+        Log.v("Creating new EventFacade Instance()");
+        bEventServerRunning = false;
+    }
+
+    /**
+     * Example (python): droid.eventClearBuffer()
+     */
+    @Rpc(description = "Clears all events from the event buffer.")
+    public void eventClearBuffer() {
+        mEventQueue.clear();
+    }
+
+    /**
+     * Registers a listener for a new broadcast signal
+     */
+    @Rpc(description = "Registers a listener for a new broadcast signal")
+    public boolean eventRegisterForBroadcast(
+                        @RpcParameter(name = "category")
+            String category,
+            @RpcParameter(name = "enqueue",
+                    description = "Should this events be added to the event queue or only dispatched")
+            @RpcDefault(value = "true")
+            Boolean enqueue) {
+        if (mBroadcastListeners.containsKey(category)) {
+            return false;
+        }
+
+        BroadcastListener b = new BroadcastListener(this, enqueue.booleanValue());
+        IntentFilter c = new IntentFilter(category);
+        mContext.registerReceiver(b, c);
+        mBroadcastListeners.put(category, b);
+
+        return true;
+    }
+
+    @Rpc(description = "Stop listening for a broadcast signal")
+    public void eventUnregisterForBroadcast(
+            @RpcParameter(name = "category")
+    String category) {
+        if (!mBroadcastListeners.containsKey(category)) {
+            return;
+        }
+
+        mContext.unregisterReceiver(mBroadcastListeners.get(category));
+        mBroadcastListeners.remove(category);
+    }
+
+    @Rpc(description = "Lists all the broadcast signals we are listening for")
+    public Set<String> eventGetBrodcastCategories() {
+        return mBroadcastListeners.keySet();
+    }
+
+    /**
+     * Actual data returned in the map will depend on the type of event.
+     *
+     * <pre>
+     * Example (python):
+     *     import android, time
+     *     droid = android.Android()
+     *     droid.startSensing()
+     *     time.sleep(1)
+     *     droid.eventClearBuffer()
+     *     time.sleep(1)
+     *     e = eventPoll(1).result
+     *     event_entry_number = 0
+     *     x = e[event_entry_ number]['data']['xforce']
+     * </pre>
+     *
+     * e has the format:<br>
+     * [{u'data': {u'accuracy': 0, u'pitch': -0.48766891956329345, u'xmag': -5.6875, u'azimuth':
+     * 0.3312483489513397, u'zforce': 8.3492730000000002, u'yforce': 4.5628165999999997, u'time':
+     * 1297072704.813, u'ymag': -11.125, u'zmag': -42.375, u'roll': -0.059393649548292161,
+     * u'xforce': 0.42223078000000003}, u'name': u'sensors', u'time': 1297072704813000L}]<br>
+     * x has the string value of the x force data (0.42223078000000003) at the time of the event
+     * entry. </pre>
+     */
+
+    @Rpc(description = "Returns and removes the oldest n events (i.e. location or sensor update, etc.) from the event buffer.",
+            returns = "A List of Maps of event properties.")
+    public List<Event> eventPoll(
+            @RpcParameter(name = "number_of_events")
+            @RpcDefault("1")
+            Integer number_of_events) {
+        List<Event> events = Lists.newArrayList();
+        for (int i = 0; i < number_of_events; i++) {
+            Event event = mEventQueue.poll();
+            if (event == null) {
+                break;
+            }
+            events.add(event);
+        }
+        return events;
+    }
+
+    @Rpc(description = "Blocks until an event with the supplied name occurs. Event is removed from the buffer if removeEvent is True.",
+            returns = "Map of event properties.")
+    public Event eventWaitFor(
+                        @RpcParameter(name = "eventName")
+            final String eventName,
+                        @RpcParameter(name = "removeEvent")
+            final Boolean removeEvent,
+            @RpcParameter(name = "timeout", description = "the maximum time to wait (in ms)")
+            @RpcOptional
+            Integer timeout)
+            throws InterruptedException {
+        Event result = null;
+        final FutureResult<Event> futureEvent;
+        synchronized (mEventQueue) { // First check to make sure it isn't already there
+            for (Event event : mEventQueue) {
+                if (event.getName().equals(eventName)) {
+                    result = event;
+                    if (removeEvent)
+                        mEventQueue.remove(event);
+                    return result;
+                }
+            }
+            futureEvent = new FutureResult<Event>();
+            addNamedEventObserver(eventName, new EventObserver() {
+                    @Override
+                public void onEventReceived(Event event) {
+                    if (event.getName().equals(eventName)) {
+                        synchronized (futureEvent) {
+                            if (!futureEvent.isDone()) {
+                                futureEvent.set(event);
+                                // TODO(navtej) Remove log.
+                                Log.v(String.format("Removeing observer (%s) got event  (%s)", this,
+                                        event));
+                                removeEventObserver(this);
+                            }
+                            if (removeEvent)
+                                mEventQueue.remove(event);
+                        }
+                    }
+                }
+            });
+        }
+        if (futureEvent != null) {
+            if (timeout != null) {
+                result = futureEvent.get(timeout, TimeUnit.MILLISECONDS);
+            } else {
+                result = futureEvent.get();
+            }
+        }
+        return result;
+    }
+
+    @Rpc(description = "Blocks until an event occurs. The returned event is removed from the buffer.",
+            returns = "Map of event properties.")
+    public Event eventWait(
+            @RpcParameter(name = "timeout", description = "the maximum time to wait")
+            @RpcOptional
+            Integer timeout)
+            throws InterruptedException {
+        Event result = null;
+        final FutureResult<Event> futureEvent = new FutureResult<Event>();
+        EventObserver observer;
+        synchronized (mEventQueue) { // Anything in queue?
+            if (mEventQueue.size() > 0) {
+                return mEventQueue.poll(); // return it.
+            }
+            observer = new EventObserver() {
+                    @Override
+                public void onEventReceived(Event event) { // set up observer for any events.
+                    synchronized (futureEvent) {
+                        if (!futureEvent.isDone()) {
+                            futureEvent.set(event);
+                            // TODO(navtej) Remove log.
+                            Log.v(String.format("onEventReceived for event (%s)", event));
+                        }
+                        mEventQueue.remove(event);
+                    }
+                }
+            };
+            addGlobalEventObserver(observer);
+        }
+        if (timeout != null) {
+            result = futureEvent.get(timeout, TimeUnit.MILLISECONDS);
+            if (result == null) {
+                result = new Event("eventTimeout", null);
+            }
+        } else {
+            result = futureEvent.get();
+        }
+        // TODO(navtej) Remove log.
+        Log.v(String.format("Removeing observer (%s) got event  (%s)", observer, result));
+        if (observer != null) {
+            removeEventObserver(observer); // Make quite sure this goes away.
+        }
+        return result;
+    }
+
+    /**
+     * <pre>
+     * Example:
+     *   import android
+     *   from datetime import datetime
+     *   droid = android.Android()
+     *   t = datetime.now()
+     *   droid.eventPost('Some Event', t)
+     * </pre>
+     */
+    @Rpc(description = "Post an event to the event queue.")
+    public void eventPost(
+                        @RpcParameter(name = "name", description = "Name of event")
+            String name,
+                        @RpcParameter(name = "data", description = "Data contained in event.")
+            String data,
+            @RpcParameter(name = "enqueue",
+                    description = "Set to False if you don't want your events to be added to the event queue, just dispatched.")
+            @RpcOptional
+            @RpcDefault("false")
+            Boolean enqueue) {
+        postEvent(name, data, enqueue.booleanValue());
+    }
+
+    /**
+     * Post an event and queue it
+     */
+    public void postEvent(String name, Object data) {
+        postEvent(name, data, true);
+    }
+
+    /**
+     * Posts an event with to the event queue.
+     */
+    public void postEvent(String name, Object data, boolean enqueue) {
+        Event event = new Event(name, data);
+        if (enqueue != false) {
+            synchronized (mEventQueue) {
+                while (mEventQueue.size() >= MAX_QUEUE_SIZE) {
+                    mEventQueue.remove();
+                }
+                mEventQueue.add(event);
+            }
+            Log.v(String.format("postEvent(%s)", name));
+        }
+        synchronized (mNamedEventObservers) {
+            for (EventObserver observer : mNamedEventObservers.get(name)) {
+                observer.onEventReceived(event);
+            }
+        }
+        synchronized (mGlobalEventObservers) {
+            // TODO(navtej) Remove log.
+            Log.v(String.format("mGlobalEventObservers size (%s)", mGlobalEventObservers.size()));
+            for (EventObserver observer : mGlobalEventObservers) {
+                observer.onEventReceived(event);
+            }
+        }
+    }
+
+    @RpcDeprecated(value = "eventPost", release = "r4")
+    @Rpc(description = "Post an event to the event queue.")
+    @RpcName(name = "postEvent")
+    public void rpcPostEvent(
+            @RpcParameter(name = "name")
+    String name,
+                        @RpcParameter(name = "data")
+            String data) {
+        postEvent(name, data);
+    }
+
+    @RpcDeprecated(value = "eventPoll", release = "r4")
+    @Rpc(description = "Returns and removes the oldest event (i.e. location or sensor update, etc.) from the event buffer.",
+            returns = "Map of event properties.")
+    public Event receiveEvent() {
+        return mEventQueue.poll();
+    }
+
+    @RpcDeprecated(value = "eventWaitFor", release = "r4")
+    @Rpc(description = "Blocks until an event with the supplied name occurs. Event is removed from the buffer if removeEvent is True.",
+            returns = "Map of event properties.")
+    public Event waitForEvent(
+                        @RpcParameter(name = "eventName")
+            final String eventName,
+                        @RpcOptional
+            final Boolean removeEvent,
+            @RpcParameter(name = "timeout", description = "the maximum time to wait")
+            @RpcOptional
+            Integer timeout)
+            throws InterruptedException {
+        return eventWaitFor(eventName, removeEvent, timeout);
+    }
+
+    @Rpc(description = "Opens up a socket where you can read for events posted")
+    public int startEventDispatcher(
+            @RpcParameter(name = "port", description = "Port to use")
+            @RpcDefault("0")
+            @RpcOptional()
+            Integer port) {
+        if (mEventServer == null) {
+            if (port == null) {
+                port = 0;
+            }
+            mEventServer = new EventServer(port);
+            addGlobalEventObserver(mEventServer);
+            bEventServerRunning = true;
+        }
+        return mEventServer.getAddress().getPort();
+    }
+
+    @Rpc(description = "Stops the event server, you can't read in the port anymore")
+    public void stopEventDispatcher() throws RuntimeException {
+        if (bEventServerRunning == true) {
+            if (mEventServer == null) {
+                throw new RuntimeException("Not running");
+            }
+            bEventServerRunning = false;
+            mEventServer.shutdown();
+            Log.v(String.format("stopEventDispatcher   (%s)", mEventServer));
+            removeEventObserver(mEventServer);
+            mEventServer = null;
+        }
+        return;
+    }
+
+    @Override
+    public void shutdown() {
+
+        try {
+            stopEventDispatcher();
+        } catch (Exception e) {
+            Log.e("Exception tearing down event dispatcher", e);
+        }
+        mGlobalEventObservers.clear();
+        mEventQueue.clear();
+    }
+
+    public void addNamedEventObserver(String eventName, EventObserver observer) {
+        mNamedEventObservers.put(eventName, observer);
+    }
+
+    public void addGlobalEventObserver(EventObserver observer) {
+        mGlobalEventObservers.add(observer);
+    }
+
+    public void removeEventObserver(EventObserver observer) {
+        mNamedEventObservers.removeAll(observer);
+        mGlobalEventObservers.remove(observer);
+    }
+
+    public interface EventObserver {
+        public void onEventReceived(Event event);
+    }
+
+    public class BroadcastListener extends android.content.BroadcastReceiver {
+        private EventFacade mParent;
+        private boolean mEnQueue;
+
+        public BroadcastListener(EventFacade parent, boolean enqueue) {
+            mParent = parent;
+            mEnQueue = enqueue;
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            Bundle data;
+            if (intent.getExtras() != null) {
+                data = (Bundle) intent.getExtras().clone();
+            } else {
+                data = new Bundle();
+            }
+            data.putString("action", intent.getAction());
+            try {
+                mParent.eventPost("sl4a", JsonBuilder.build(data).toString(), mEnQueue);
+            } catch (JSONException e) {
+                e.printStackTrace();
+            }
+        }
+
+    }
+}
diff --git a/Utils/src/com/googlecode/android_scripting/future/FutureResult.java b/Utils/src/com/googlecode/android_scripting/future/FutureResult.java
index 78a63b0..bdf9cb8 100644
--- a/Utils/src/com/googlecode/android_scripting/future/FutureResult.java
+++ b/Utils/src/com/googlecode/android_scripting/future/FutureResult.java
@@ -27,39 +27,39 @@
  */
 public class FutureResult<T> implements Future<T> {
 
-  private final CountDownLatch mLatch = new CountDownLatch(1);
-  private volatile T mResult = null;
+    private final CountDownLatch mLatch = new CountDownLatch(1);
+    private volatile T mResult = null;
 
-  public void set(T result) {
-    mResult = result;
-    mLatch.countDown();
-  }
+    public void set(T result) {
+        mResult = result;
+        mLatch.countDown();
+    }
 
-  @Override
-  public boolean cancel(boolean mayInterruptIfRunning) {
-    return false;
-  }
+    @Override
+    public boolean cancel(boolean mayInterruptIfRunning) {
+        return false;
+    }
 
-  @Override
-  public T get() throws InterruptedException {
-    mLatch.await();
-    return mResult;
-  }
+    @Override
+    public T get() throws InterruptedException {
+        mLatch.await();
+        return mResult;
+    }
 
-  @Override
-  public T get(long timeout, TimeUnit unit) throws InterruptedException {
-    mLatch.await(timeout, unit);
-    return mResult;
-  }
+    @Override
+    public T get(long timeout, TimeUnit unit) throws InterruptedException {
+        mLatch.await(timeout, unit);
+        return mResult;
+    }
 
-  @Override
-  public boolean isCancelled() {
-    return false;
-  }
+    @Override
+    public boolean isCancelled() {
+        return false;
+    }
 
-  @Override
-  public boolean isDone() {
-    return mResult != null;
-  }
+    @Override
+    public boolean isDone() {
+        return mResult != null;
+    }
 
 }