From fcae1c9785ae3136dc89f97bccf4e8b81184c51b Mon Sep 17 00:00:00 2001
From: Dan Ambrosio <dan.ambrosio@stratom.com>
Date: Fri, 3 Mar 2017 11:46:49 -0800
Subject: [PATCH] This closes rosjava/rosjava_core#233. Adds fix for shutting
 down DefaultNodeMainExecutor ListenerGroup to prevent leak in android when
 activities are destroyed. Added ability to remove listener from ListenerGroup
 to fix android_core issue #254.

---
 .../org/ros/concurrent/EventDispatcher.java   |  5 +++++
 .../org/ros/concurrent/ListenerGroup.java     | 20 +++++++++++++++++++
 .../org/ros/internal/node/DefaultNode.java    |  5 +++++
 .../org/ros/node/DefaultNodeMainExecutor.java |  1 +
 rosjava/src/main/java/org/ros/node/Node.java  |  6 ++++++
 5 files changed, 37 insertions(+)

diff --git a/rosjava/src/main/java/org/ros/concurrent/EventDispatcher.java b/rosjava/src/main/java/org/ros/concurrent/EventDispatcher.java
index 428d9256..83985f6f 100644
--- a/rosjava/src/main/java/org/ros/concurrent/EventDispatcher.java
+++ b/rosjava/src/main/java/org/ros/concurrent/EventDispatcher.java
@@ -42,4 +42,9 @@ public class EventDispatcher<T> extends CancellableLoop {
     SignalRunnable<T> signalRunnable = events.takeFirst();
     signalRunnable.run(listener);
   }
+
+  public T getListener()
+  {
+    return listener;
+  }
 }
\ No newline at end of file
diff --git a/rosjava/src/main/java/org/ros/concurrent/ListenerGroup.java b/rosjava/src/main/java/org/ros/concurrent/ListenerGroup.java
index ae7deb38..29a8ccb2 100644
--- a/rosjava/src/main/java/org/ros/concurrent/ListenerGroup.java
+++ b/rosjava/src/main/java/org/ros/concurrent/ListenerGroup.java
@@ -101,6 +101,25 @@ public class ListenerGroup<T> {
     return addAll(listeners, DEFAULT_QUEUE_CAPACITY);
   }
 
+  /**
+   * Removes and cancels the {@EventDispatcher} specified by the listener
+   * from the {@link ListenerGroup}.
+   * @param listener the listener to remove
+   * @return flag indicating successful removal
+     */
+  public boolean remove(T listener)
+  {
+    for (EventDispatcher<T> eventDispatcher : eventDispatchers) {
+      if(listener.equals(eventDispatcher.getListener()))
+      {
+        eventDispatcher.cancel();
+        eventDispatchers.remove(eventDispatcher);
+        return true;
+      }
+    }
+    return false;
+  }
+
   /**
    * @return the number of listeners in the group
    */
@@ -151,5 +170,6 @@ public class ListenerGroup<T> {
     for (EventDispatcher<T> eventDispatcher : eventDispatchers) {
       eventDispatcher.cancel();
     }
+    eventDispatchers.clear();
   }
 }
diff --git a/rosjava/src/main/java/org/ros/internal/node/DefaultNode.java b/rosjava/src/main/java/org/ros/internal/node/DefaultNode.java
index ec363955..81386ceb 100644
--- a/rosjava/src/main/java/org/ros/internal/node/DefaultNode.java
+++ b/rosjava/src/main/java/org/ros/internal/node/DefaultNode.java
@@ -493,6 +493,11 @@ public class DefaultNode implements ConnectedNode {
     });
   }
 
+  @Override
+  public void removeListeners() {
+    nodeListeners.shutdown();
+  }
+
   /**
    * SignalRunnable all {@link NodeListener}s that the {@link Node} has started.
    * <p>
diff --git a/rosjava/src/main/java/org/ros/node/DefaultNodeMainExecutor.java b/rosjava/src/main/java/org/ros/node/DefaultNodeMainExecutor.java
index 96d75754..7ae60746 100644
--- a/rosjava/src/main/java/org/ros/node/DefaultNodeMainExecutor.java
+++ b/rosjava/src/main/java/org/ros/node/DefaultNodeMainExecutor.java
@@ -213,6 +213,7 @@ public class DefaultNodeMainExecutor implements NodeMainExecutor {
    *          the {@link Node} to unregister
    */
   private void unregisterNode(Node node) {
+    node.removeListeners();
     connectedNodes.get(node.getName()).remove(node);
     nodeMains.remove(node);
   }
diff --git a/rosjava/src/main/java/org/ros/node/Node.java b/rosjava/src/main/java/org/ros/node/Node.java
index ea88d768..9e47943c 100644
--- a/rosjava/src/main/java/org/ros/node/Node.java
+++ b/rosjava/src/main/java/org/ros/node/Node.java
@@ -126,4 +126,10 @@ public interface Node {
    * Shut the node down.
    */
   void shutdown();
+
+  /**
+   * Stops and Clears node listeners.
+   */
+
+  void removeListeners();
 }
-- 
GitLab