@Override
    protected Void doInBackground(ScanData... params) {
      ScanData scanData = params[0];

      IBeacon iBeacon = IBeacon.fromScanData(scanData.scanRecord, scanData.rssi);
      if (iBeacon != null) {
        lastIBeaconDetectionTime = new Date();
        trackedBeacons.add(iBeacon);
        Log.d(
            TAG,
            "iBeacon detected :"
                + iBeacon.getProximityUuid()
                + " "
                + iBeacon.getMajor()
                + " "
                + iBeacon.getMinor()
                + " accuracy: "
                + iBeacon.getAccuracy()
                + " proximity: "
                + iBeacon.getProximity());

        List<Region> matchedRegions = matchingRegions(iBeacon, monitoredRegionState.keySet());
        Iterator<Region> matchedRegionIterator = matchedRegions.iterator();
        while (matchedRegionIterator.hasNext()) {
          Region region = matchedRegionIterator.next();
          MonitorState state = monitoredRegionState.get(region);
          if (state.markInside()) {
            state
                .getCallback()
                .call(
                    IBeaconService.this,
                    "monitoringData",
                    new MonitoringData(state.isInside(), region));
          }
        }

        Log.d(TAG, "looking for ranging region matches for this ibeacon");
        matchedRegions = matchingRegions(iBeacon, rangedRegionState.keySet());
        matchedRegionIterator = matchedRegions.iterator();
        while (matchedRegionIterator.hasNext()) {
          Region region = matchedRegionIterator.next();
          Log.d(TAG, "matches ranging region: " + region);
          RangeState rangeState = rangedRegionState.get(region);
          rangeState.addIBeacon(iBeacon);
        }
      }
      // I see a device: 00:02:72:C5:EC:33 with scan data: 02 01 1A 1A FF 4C 00 02 15 84 2A F9 C4 08
      // F5 11 E3 92 82 F2 3C 91 AE C0 5E D0 00 00 69 C5
      // 0000000000000000000000000000000000000000000000000000000000000000
      //
      // 9: proximityUuid (16 bytes) 84 2A F9 C4 08 F5 11 E3 92 82 F2 3C 91 AE C0 5E
      // 25: major (2 bytes unsigned int)
      // 27: minor (2 bytes unsigned int)
      // 29: tx power (1 byte signed int)
      return null;
    }
  @Override
  public void didRangeBeaconsInRegion(Collection<IBeacon> iBeacons, Region region) {
    for (IBeacon iBeacon : iBeacons) {
      iBeacon.requestData(this);

      String displayString =
          iBeacon.getProximityUuid() + " " + iBeacon.getMajor() + " " + iBeacon.getMinor() + "\n";

      Log.d(TAG, displayString);
    }

    myBeacons.clear();
    myBeacons.addAll(iBeacons);
  }
 @Override
 public void iBeaconDataUpdate(IBeacon iBeacon, IBeaconData iBeaconData, DataProviderException e) {
   if (e != null) {
     Log.d(TAG, "data fetch error:" + e);
   }
   if (iBeaconData != null) {
     String displayString =
         iBeacon.getProximityUuid()
             + " "
             + iBeacon.getMajor()
             + " "
             + iBeacon.getMinor()
             + "\n"
             + "Welcome message:"
             + iBeaconData.get("welcomeMessage");
     Log.d(TAG, displayString);
   }
 }
  private void processIBeaconFromScan(IBeacon iBeacon) {
    lastIBeaconDetectionTime = new Date();
    trackedBeacons.add(iBeacon);
    Log.d(
        TAG,
        "iBeacon detected :"
            + iBeacon.getProximityUuid()
            + " "
            + iBeacon.getMajor()
            + " "
            + iBeacon.getMinor()
            + " accuracy: "
            + iBeacon.getAccuracy()
            + " proximity: "
            + iBeacon.getProximity());

    List<Region> matchedRegions = matchingRegions(iBeacon, monitoredRegionState.keySet());
    Iterator<Region> matchedRegionIterator = matchedRegions.iterator();
    while (matchedRegionIterator.hasNext()) {
      Region region = matchedRegionIterator.next();
      MonitorState state = monitoredRegionState.get(region);
      if (state.markInside()) {
        state
            .getCallback()
            .call(
                IBeaconService.this,
                "monitoringData",
                new MonitoringData(state.isInside(), region));
      }
    }

    Log.d(TAG, "looking for ranging region matches for this ibeacon");
    matchedRegions = matchingRegions(iBeacon, rangedRegionState.keySet());
    matchedRegionIterator = matchedRegions.iterator();
    while (matchedRegionIterator.hasNext()) {
      Region region = matchedRegionIterator.next();
      Log.d(TAG, "matches ranging region: " + region);
      RangeState rangeState = rangedRegionState.get(region);
      rangeState.addIBeacon(iBeacon);
    }
  }
  private JSONObject mapOfBeacon(IBeacon region) throws JSONException {
    JSONObject dict = new JSONObject();

    // beacon id
    dict.put("uuid", region.getProximityUuid());
    dict.put("major", region.getMajor());
    dict.put("minor", region.getMinor());

    // proximity
    dict.put("proximity", nameOfProximity(region.getProximity()));

    // signal strength and transmission power
    dict.put("rssi", region.getRssi());
    dict.put("tx", region.getTxPower());

    // accuracy = rough distance estimate limited to two decimal places (in metres)
    // NO NOT ASSUME THIS IS ACCURATE - it is effected by radio interference and obstacles
    dict.put("accuracy", Math.round(region.getAccuracy() * 100.0) / 100.0);

    return dict;
  }
  private void processIBeaconFromScan(IBeacon iBeacon) {
    lastIBeaconDetectionTime = new Date();
    trackedBeaconsPacketCount++;
    if (trackedBeacons.contains(iBeacon)) {
      if (IBeaconManager.LOG_DEBUG)
        Log.d(
            TAG,
            "iBeacon detected multiple times in scan cycle :"
                + iBeacon.getProximityUuid()
                + " "
                + iBeacon.getMajor()
                + " "
                + iBeacon.getMinor()
                + " accuracy: "
                + iBeacon.getAccuracy()
                + " proximity: "
                + iBeacon.getProximity());
    }
    trackedBeacons.add(iBeacon);
    if (IBeaconManager.LOG_DEBUG)
      Log.d(
          TAG,
          "iBeacon detected :"
              + iBeacon.getProximityUuid()
              + " "
              + iBeacon.getMajor()
              + " "
              + iBeacon.getMinor()
              + " accuracy: "
              + iBeacon.getAccuracy()
              + " proximity: "
              + iBeacon.getProximity());

    List<Region> matchedRegions = null;
    synchronized (monitoredRegionState) {
      matchedRegions = matchingRegions(iBeacon, monitoredRegionState.keySet());
    }
    Iterator<Region> matchedRegionIterator = matchedRegions.iterator();
    while (matchedRegionIterator.hasNext()) {
      Region region = matchedRegionIterator.next();
      MonitorState state = monitoredRegionState.get(region);
      if (state.markInside()) {
        state
            .getCallback()
            .call(
                IBeaconService.this,
                "monitoringData",
                new MonitoringData(state.isInside(), region));
      }
    }

    if (IBeaconManager.LOG_DEBUG) Log.d(TAG, "looking for ranging region matches for this ibeacon");
    synchronized (rangedRegionState) {
      matchedRegions = matchingRegions(iBeacon, rangedRegionState.keySet());
    }
    matchedRegionIterator = matchedRegions.iterator();
    while (matchedRegionIterator.hasNext()) {
      Region region = matchedRegionIterator.next();
      if (IBeaconManager.LOG_DEBUG) Log.d(TAG, "matches ranging region: " + region);
      RangeState rangeState = rangedRegionState.get(region);
      rangeState.addIBeacon(iBeacon);
    }
  }