@Override
 public void subscribe(int appId, String nodeName) throws RemoteException {
   Log.d(TAG, "subscribe for " + nodeName);
   mApplicationMap.get(appId).addSubscribedNodeNames(nodeName);
   mGraphConfig.subscribe(mApplicationMap.get(appId), nodeName);
   mNotification.showNotificationNow("Subscribed " + nodeName);
 }
 @Override
 public void unregister(int appId) throws RemoteException {
   synchronized (mApplicationMap) {
     Application removedApp = mApplicationMap.remove(appId);
     mGraphConfig.removeApplication(removedApp);
     mNotification.showNotificationNow("Unregistering application ID " + appId);
   }
 }
  @Override
  public void onCreate() {
    super.onCreate();
    DebugHelper.logi(TAG, "Service creating..");

    INSTANCE = this;

    mNotification =
        new NotificationHelper(this, TAG, this.getClass().getName(), R.drawable.ic_launcher);
    mNotification.showNotificationNow("FlowEngine starting..");

    DebugHelper.startTrace();
  }
 private void showNotification(int sensor, String name) {
   Timer timer = mCancelTimerMap.get(sensor);
   if (timer == null) {
     mNotification.showNotificationNowOngoing(sensor, "Receiving " + name + "..");
     timer = new Timer();
     timer.schedule(new CancelNotificationTimerTask(sensor), 5000);
     mCancelTimerMap.put(sensor, timer);
   } else {
     timer.cancel();
     timer = new Timer();
     timer.schedule(new CancelNotificationTimerTask(sensor), 5000);
     mCancelTimerMap.put(sensor, timer);
   }
 }
        @Override
        public int addDevice(DeviceAPI deviceAPI) throws RemoteException {
          synchronized (mDeviceMap) {
            Device device = new Device(deviceAPI);
            int deviceID = mNextDeviceID;
            mNextDeviceID += 1;
            mDeviceMap.put(deviceID, device);

            mNotification.showNotificationNow("Added device ID " + deviceID);
            DebugHelper.log(TAG, "Added device ID: " + deviceID);

            return deviceID;
          }
        }
        @Override
        public int register(ApplicationInterface appInterface) throws RemoteException {
          synchronized (mApplicationMap) {
            Application app = new Application(appInterface);
            int appID = mNextApplicationID;
            mNextApplicationID += 1;
            mApplicationMap.put(appID, app);

            DebugHelper.log(TAG, "Registered application ID " + appID);
            mNotification.showNotificationNow("Registered application ID: " + appID);

            return appID;
          }
        }
  @Override
  public void onDestroy() {
    DebugHelper.logi(TAG, "Service destroying..");
    DebugHelper.stopTrace();

    mNotification.showNotificationNow("FlowEngine destryong..");

    for (Map.Entry<Integer, Device> entry : mDeviceMap.entrySet()) {
      try {
        entry.getValue().getInterface().kill();
      } catch (RemoteException e) {
        e.printStackTrace();
      }
    }

    super.onDestroy();
  }
        @Override
        public void removeDevice(int deviceID) throws RemoteException {
          synchronized (mDeviceMap) {
            synchronized (mSeedNodeMap) {
              Device removedDevice = mDeviceMap.remove(deviceID);
              if (removedDevice != null) {
                Sensor[] sensors = removedDevice.getSensorList();
                for (Sensor sensor : sensors) {
                  SeedNode seed = mSeedNodeMap.get(sensor.getSensorID());
                  if (seed.isConnected()) {
                    seed.detachDevice();
                  } else {
                    mSeedNodeMap.remove(sensor.getSensorID());
                    mNodeNameMap.remove("|" + SensorType.getSensorName(sensor.getSensorID()));
                  }
                }
                DebugHelper.log(TAG, "Removed device ID: " + deviceID);
                mNotification.showNotificationNow("Removed device ID " + deviceID);
              }
            }
          }
          // print seed map
          DebugHelper.log(TAG, "Printing mSeedNodeMap..");
          for (Map.Entry<Integer, SeedNode> entry : mSeedNodeMap.entrySet()) {
            int sensor = entry.getKey();
            SeedNode node1 = entry.getValue();
            DebugHelper.log(
                TAG,
                node1.getClass().getName()
                    + ": "
                    + sensor
                    + " device: "
                    + node1.getAttachedDevice());
          }
          DebugHelper.log(TAG, "Done.");

          // print node name map
          DebugHelper.log(TAG, "Printing mNodeNameMap..");
          for (Map.Entry<String, DataFlowNode> entry : mNodeNameMap.entrySet()) {
            String nodeName = entry.getKey();
            DataFlowNode node2 = entry.getValue();
            DebugHelper.log(TAG, nodeName + ": " + node2.getClass().getName());
          }
          DebugHelper.log(TAG, "Done.");
        }