Exemplo n.º 1
0
  private void sendBeaconChangeMessage(Beacon beacon) {
    String uuid = beacon.getId1().toString();
    // Payload
    SaneJSONObject payload = new SaneJSONObject();
    payload.putOrIgnore("platform", "android");
    payload.putDoubleOrIgnore("version", VERSION);

    // Beacon
    SaneJSONObject beaconJSON = new SaneJSONObject();
    beaconJSON.putOrIgnore("uuid", uuid);
    payload.putJSONOrIgnore("beacon", beaconJSON);

    // Proximity
    payload.putJSONOrIgnore("proximity", getProximity(beacon));

    // Message
    SaneJSONObject message = new SaneJSONObject();
    JSONArray devices = new JSONArray();
    devices.put("*");
    message.putArrayOrIgnore("devices", devices);
    message.putJSONOrIgnore("payload", payload);
    message.putOrIgnore("topic", "location_update");

    // Send
    BeaconInfo beaconInfo = getBeaconInfo(this.beaconInfo, uuid);
    Double distance = beacon.getDistance();
    if (beaconInfo.hasChangedDistance(distance)) {
      meshblu.message(message);
      emitter.emit(EVENTS.LOCATION_UPDATE, payload, beaconInfo);
    }
    beaconInfo.setLastDistance(distance);
  }
 /**
  * Estimate the distance to the beacon using the DistanceCalculator set on this class. If no
  * DistanceCalculator has been set, return -1 as the distance.
  *
  * @see org.altbeacon.beacon.distance.DistanceCalculator
  * @param txPower
  * @param bestRssiAvailable
  * @return
  */
 protected static Double calculateDistance(int txPower, double bestRssiAvailable) {
   if (Beacon.getDistanceCalculator() != null) {
     return Beacon.getDistanceCalculator().calculateDistance(txPower, bestRssiAvailable);
   } else {
     LogManager.e(TAG, "Distance calculator not set.  Distance will bet set to -1");
     return -1.0;
   }
 }
Exemplo n.º 3
0
 /**
  * 每个扫描周期结束,根据20秒内各beacon的RSSI平均值计算它的距离,该回调获取这些beacon的距离值 Called once per second (实际上是每扫描周期)
  * to give an estimate of the mDistance to visible beacons
  */
 @Override
 public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
   LogManager.d(TAG, "didRangeBeaconsInRegion(),beacons=" + beacons.size());
   for (Beacon beacon : beacons) {
     LogManager.d(TAG, beacon.getId2() + ":" + beacon.getId3() + "," + beacon.getDistance());
   }
   Beacon beacon = mNearestBeacon.getNearestBeacon(mGetBeaconType, beacons);
   mOnNearestBeaconListener.getNearestBeacon(mGetBeaconType, beacon);
 }
 /**
  * @param beacon the beacon whose fields we should copy to this beacon builder
  * @return
  */
 public Builder copyBeaconFields(Beacon beacon) {
   setIdentifiers(beacon.getIdentifiers());
   setBeaconTypeCode(beacon.getBeaconTypeCode());
   setDataFields(beacon.getDataFields());
   setBluetoothAddress(beacon.getBluetoothAddress());
   setBluetoothName(beacon.getBluetoothName());
   setExtraDataFields(beacon.getExtraDataFields());
   setManufacturer(beacon.getManufacturer());
   setTxPower(beacon.getTxPower());
   setRssi(beacon.getRssi());
   setServiceUuid(beacon.getServiceUuid());
   return this;
 }
 @Test
 public void gattBeaconExtraDataAreNotOverwritten() {
   Beacon beacon = getGattBeacon();
   Beacon extraDataBeacon = getGattBeaconExtraData();
   GattBeaconTracker tracker = new GattBeaconTracker();
   tracker.track(beacon);
   tracker.track(extraDataBeacon);
   Beacon trackedBeacon = tracker.track(beacon);
   assertEquals(
       "extra data should not be overwritten",
       extraDataBeacon.getDataFields(),
       trackedBeacon.getExtraDataFields());
 }
 public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
   if (beacons.size() > 0) {
     EditText editText = (EditText) RangingActivity.this.findViewById(R.id.rangingText);
     for (Beacon beacon : beacons) {
       logToDisplay(
           "Beacon "
               + beacon.toString()
               + " is about "
               + beacon.getDistance()
               + " meters away, with Rssi: "
               + beacon.getRssi());
     }
   }
 }
        @Override
        public void getBeacons(Collection<Beacon> beacons) {
          // 防止停止收集beacons前,再次收到此回调,导致重复记录,在开始和结束监控(查找)beacons时设置。
          if (isRecorded) return; // 已经记录了

          // 日志记录和屏幕显示Beacon信息
          // 有可能到达采样周期时,没有找到所有beacons,甚至是0个beacons,因此,应重复记录,一直到采样周期结束。当然是最后更新的有效。
          String str = "beacons=" + beacons.size();
          LogManager.d(TAG, str);
          logToDisplay(str);
          String rssi;
          for (Beacon beacon : beacons) {
            // becaon的两个id(major,minor),rssi及其平均值
            str =
                beacon.getId2()
                    + ":"
                    + beacon.getId3()
                    + "="
                    + beacon.getRssi()
                    + ","
                    + String.format("%.2f", beacon.getRunningAverageRssi());
            LogManager.d(TAG, str);
            logToDisplay(str);

            // 记录至mBeaconsRssi
            rssi =
                beacon.getId2()
                    + "_"
                    + beacon.getId3()
                    + ":"
                    + String.format("%.2f", beacon.getRunningAverageRssi());
            mBeaconsRssi.put(beacon, rssi);
          }

          // 记录参考点的各个beacon的id和rssi平均值
          if ((System.currentTimeMillis() - startSample) >= SamplePeroid) {
            // 将目前定位参考点测量的各个beacons的rssi平均值计入数据库。
            SaveRssiToDb();

            str =
                "记录完毕,定位参考点[" + reference_pointPerf + reference_pointNum + "]" + "各个beacon的rssi平均值";
            LogManager.d(TAG, str);
            logToDisplay(str);
            // 以下必须在UI现成中执行,否则,程序将异常终止。
            runOnUiThread(
                new Runnable() {
                  public void run() {
                    String str = "记录完毕,定位参考点[" + reference_pointPerf + reference_pointNum + "]";
                    Toast.makeText(trainingActivity.this, str, Toast.LENGTH_LONG).show();
                    // 下一个参考点默认名称
                    reference_pointNum++;
                    reference_point_edit.setText(reference_pointPerf + reference_pointNum);

                    // 停止查找beacons
                    onMonitoringStop(null);
                  }
                });
          }
        }
 @Test
 public void gattBeaconExtraDataGetUpdated() {
   Beacon beacon = getGattBeacon();
   Beacon extraDataBeacon = getGattBeaconExtraData();
   Beacon extraDataBeacon2 = getGattBeaconExtraData2();
   GattBeaconTracker tracker = new GattBeaconTracker();
   tracker.track(beacon);
   tracker.track(extraDataBeacon);
   tracker.track(extraDataBeacon2);
   Beacon trackedBeacon = tracker.track(beacon);
   assertEquals(
       "extra data is updated",
       extraDataBeacon2.getDataFields(),
       trackedBeacon.getExtraDataFields());
 }
 /**
  * @see Beacon#mIdentifiers
  * @param identifiers identifiers to set
  * @return builder
  */
 public Builder setIdentifiers(List<Identifier> identifiers) {
   mId1 = null;
   mId2 = null;
   mId3 = null;
   mBeacon.mIdentifiers = identifiers;
   return this;
 }
Exemplo n.º 10
0
 private void beaconRangeChange(Collection<Beacon> beacons, Region region) {
   for (Beacon beacon : beacons) {
     String uuid = beacon.getId1().toString();
     DecimalFormat df = new DecimalFormat("#.000");
     String distance = df.format(beacon.getDistance());
     Log.d(TAG, "Beacon (" + uuid.substring(0, 8) + ") is about " + distance + " meters away.");
     Boolean enabled = isBeaconEnabled(uuid);
     if (enabled != null) {
       if (enabled) {
         sendBeaconChangeMessage(beacon);
       }
     } else {
       emitter.emit(EVENTS.DISCOVERED_BEACON, beacon);
     }
   }
 }
Exemplo n.º 11
0
 /**
  * Two detected beacons are considered equal if they share the same three identifiers, regardless
  * of their mDistance or RSSI.
  */
 @Override
 public boolean equals(Object that) {
   if (!(that instanceof Beacon)) {
     return false;
   }
   Beacon thatBeacon = (Beacon) that;
   if (this.mIdentifiers.size() != thatBeacon.mIdentifiers.size()) {
     return false;
   }
   // all identifiers must match
   for (int i = 0; i < this.mIdentifiers.size(); i++) {
     if (!this.mIdentifiers.get(i).equals(thatBeacon.mIdentifiers.get(i))) {
       return false;
     }
   }
   return sHardwareEqualityEnforced
       ? this.getBluetoothAddress().equals(thatBeacon.getBluetoothAddress())
       : true;
 }
Exemplo n.º 12
0
 private SaneJSONObject getProximity(Beacon beacon) {
   Double distance = beacon.getDistance();
   String proximity = "Unknown";
   Integer code = 0;
   if (distance < 2) {
     code = 1;
     proximity = "Immediate";
   } else if (distance >= 2 && distance < 5) {
     code = 2;
     proximity = "Near";
   } else if (distance >= 5) {
     code = 3;
     proximity = "Far";
   }
   SaneJSONObject proximityJSON = new SaneJSONObject();
   proximityJSON.putOrIgnore("message", proximity);
   proximityJSON.putIntOrIgnore("code", code);
   proximityJSON.putDoubleOrIgnore("distance", distance);
   proximityJSON.putIntOrIgnore("rssi", beacon.getRssi());
   Long time = new Date().getTime();
   proximityJSON.putOrIgnore("timestamp", new Timestamp(time).toString());
   return proximityJSON;
 }
Exemplo n.º 13
0
 /**
  * Copy constructor
  *
  * @param otherBeacon
  */
 protected Beacon(Beacon otherBeacon) {
   super();
   mIdentifiers = new ArrayList<Identifier>(otherBeacon.mIdentifiers.size());
   mDataFields = new ArrayList<Long>(otherBeacon.mDataFields.size());
   mExtraDataFields = new ArrayList<Long>(otherBeacon.mExtraDataFields.size());
   for (int i = 0; i < otherBeacon.mIdentifiers.size(); i++) {
     mIdentifiers.add(otherBeacon.mIdentifiers.get(i));
   }
   for (int i = 0; i < otherBeacon.mDataFields.size(); i++) {
     mDataFields.add(otherBeacon.mDataFields.get(i));
   }
   for (int i = 0; i < otherBeacon.mExtraDataFields.size(); i++) {
     mExtraDataFields.add(otherBeacon.mExtraDataFields.get(i));
   }
   this.mDistance = otherBeacon.mDistance;
   this.mRunningAverageRssi = otherBeacon.mRunningAverageRssi;
   this.mRssi = otherBeacon.mRssi;
   this.mTxPower = otherBeacon.mTxPower;
   this.mBluetoothAddress = otherBeacon.mBluetoothAddress;
   this.mBeaconTypeCode = otherBeacon.getBeaconTypeCode();
   this.mServiceUuid = otherBeacon.getServiceUuid();
   this.mBluetoothName = otherBeacon.mBluetoothName;
 }
 @Test
 public void gattBeaconFieldsGetUpdated() {
   Beacon beacon = getGattBeacon();
   Beacon beaconUpdate = getGattBeaconUpdate();
   Beacon extraDataBeacon = getGattBeaconExtraData();
   GattBeaconTracker tracker = new GattBeaconTracker();
   tracker.track(beacon);
   Beacon trackedBeacon = tracker.track(beaconUpdate);
   assertEquals("rssi should be updated", beaconUpdate.getRssi(), trackedBeacon.getRssi());
   assertEquals(
       "data fields should be updated",
       beaconUpdate.getDataFields(),
       trackedBeacon.getDataFields());
 }
Exemplo n.º 15
0
 /**
  * @see Beacon#mTxPower
  * @param txPower
  * @return builder
  */
 public Builder setTxPower(int txPower) {
   mBeacon.mTxPower = txPower;
   return this;
 }
Exemplo n.º 16
0
 /**
  * @see Beacon#mBluetoothName
  * @param name
  * @return builder
  */
 public Builder setBluetoothName(String name) {
   mBeacon.mBluetoothName = name;
   return this;
 }
Exemplo n.º 17
0
 /**
  * @see Beacon#mManufacturer
  * @param manufacturer
  * @return builder
  */
 public Builder setManufacturer(int manufacturer) {
   mBeacon.mManufacturer = manufacturer;
   return this;
 }
Exemplo n.º 18
0
 /**
  * @see Beacon#mDataFields
  * @param extraDataFields
  * @return builder
  */
 public Builder setExtraDataFields(List<Long> extraDataFields) {
   mBeacon.mExtraDataFields = extraDataFields;
   return this;
 }
Exemplo n.º 19
0
 /**
  * @see Beacon#mDataFields
  * @param dataFields
  * @return builder
  */
 public Builder setDataFields(List<Long> dataFields) {
   mBeacon.mDataFields = dataFields;
   return this;
 }
Exemplo n.º 20
0
 /**
  * @see Beacon#mBluetoothAddress
  * @param bluetoothAddress
  * @return builder
  */
 public Builder setBluetoothAddress(String bluetoothAddress) {
   mBeacon.mBluetoothAddress = bluetoothAddress;
   return this;
 }
Exemplo n.º 21
0
 /**
  * @see Beacon#mServiceUuid
  * @param serviceUuid
  * @return builder
  */
 public Builder setServiceUuid(int serviceUuid) {
   mBeacon.mServiceUuid = serviceUuid;
   return this;
 }
Exemplo n.º 22
0
 /**
  * @see Beacon#mBeaconTypeCode
  * @param beaconTypeCode
  * @return builder
  */
 public Builder setBeaconTypeCode(int beaconTypeCode) {
   mBeacon.mBeaconTypeCode = beaconTypeCode;
   return this;
 }
Exemplo n.º 23
0
  /**
   * Get BLE advertisement bytes for a Beacon
   *
   * @param beacon the beacon containing the data to be transmitted
   * @return the byte array of the advertisement
   */
  @TargetApi(Build.VERSION_CODES.GINGERBREAD)
  public byte[] getBeaconAdvertisementData(Beacon beacon) {
    byte[] advertisingBytes;

    if (beacon.getIdentifiers().size() != getIdentifierCount()) {
      throw new IllegalArgumentException(
          "Beacon has "
              + beacon.getIdentifiers().size()
              + " identifiers but format requires "
              + getIdentifierCount());
    }

    int lastIndex = -1;
    if (mMatchingBeaconTypeCodeEndOffset != null && mMatchingBeaconTypeCodeEndOffset > lastIndex) {
      lastIndex = mMatchingBeaconTypeCodeEndOffset;
    }
    if (mPowerEndOffset != null && mPowerEndOffset > lastIndex) {
      lastIndex = mPowerEndOffset;
    }
    for (int identifierNum = 0;
        identifierNum < this.mIdentifierEndOffsets.size();
        identifierNum++) {
      if (this.mIdentifierEndOffsets.get(identifierNum) != null
          && this.mIdentifierEndOffsets.get(identifierNum) > lastIndex) {
        lastIndex = this.mIdentifierEndOffsets.get(identifierNum);
      }
    }
    for (int identifierNum = 0; identifierNum < this.mDataEndOffsets.size(); identifierNum++) {
      if (this.mDataEndOffsets.get(identifierNum) != null
          && this.mDataEndOffsets.get(identifierNum) > lastIndex) {
        lastIndex = this.mDataEndOffsets.get(identifierNum);
      }
    }

    // we must adjust the lastIndex to account for variable length identifiers, if there are any.
    int adjustedIdentifiersLength = 0;
    for (int identifierNum = 0;
        identifierNum < this.mIdentifierStartOffsets.size();
        identifierNum++) {
      if (mIdentifierVariableLengthFlags.get(identifierNum)) {
        int declaredIdentifierLength =
            (this.mIdentifierEndOffsets.get(identifierNum)
                - this.mIdentifierStartOffsets.get(identifierNum)
                + 1);
        int actualIdentifierLength = beacon.getIdentifier(identifierNum).getByteCount();
        adjustedIdentifiersLength += actualIdentifierLength;
        adjustedIdentifiersLength -= declaredIdentifierLength;
      }
    }
    lastIndex += adjustedIdentifiersLength;

    advertisingBytes = new byte[lastIndex + 1 - 2];
    long beaconTypeCode = this.getMatchingBeaconTypeCode();

    // set type code
    for (int index = this.mMatchingBeaconTypeCodeStartOffset;
        index <= this.mMatchingBeaconTypeCodeEndOffset;
        index++) {
      byte value =
          (byte)
              (this.getMatchingBeaconTypeCode()
                      >> (8 * (this.mMatchingBeaconTypeCodeEndOffset - index))
                  & 0xff);
      advertisingBytes[index - 2] = value;
    }

    // set identifiers
    for (int identifierNum = 0;
        identifierNum < this.mIdentifierStartOffsets.size();
        identifierNum++) {
      byte[] identifierBytes =
          beacon
              .getIdentifier(identifierNum)
              .toByteArrayOfSpecifiedEndianness(
                  !this.mIdentifierLittleEndianFlags.get(identifierNum));

      // If the identifier we are trying to stuff into the space is different than the space
      // available
      // adjust it
      if (identifierBytes.length < getIdentifierByteCount(identifierNum)) {
        if (!mIdentifierVariableLengthFlags.get(identifierNum)) {
          // Pad it, but only if this is not a variable length identifier
          if (mIdentifierLittleEndianFlags.get(identifierNum)) {
            // this is little endian.  Pad at the end of the array
            identifierBytes = Arrays.copyOf(identifierBytes, getIdentifierByteCount(identifierNum));
          } else {
            // this is big endian.  Pad at the beginning of the array
            byte[] newIdentifierBytes = new byte[getIdentifierByteCount(identifierNum)];
            System.arraycopy(
                identifierBytes,
                0,
                newIdentifierBytes,
                getIdentifierByteCount(identifierNum) - identifierBytes.length,
                identifierBytes.length);
            identifierBytes = newIdentifierBytes;
          }
        }
        LogManager.d(
            TAG,
            "Expanded identifier because it is too short.  It is now: "
                + byteArrayToString(identifierBytes));
      } else if (identifierBytes.length > getIdentifierByteCount(identifierNum)) {
        if (mIdentifierLittleEndianFlags.get(identifierNum)) {
          // Truncate it at the beginning for big endian
          identifierBytes =
              Arrays.copyOfRange(
                  identifierBytes,
                  getIdentifierByteCount(identifierNum) - identifierBytes.length,
                  getIdentifierByteCount(identifierNum));
        } else {
          // Truncate it at the end for little endian
          identifierBytes = Arrays.copyOf(identifierBytes, getIdentifierByteCount(identifierNum));
        }
        LogManager.d(
            TAG,
            "Truncated identifier because it is too long.  It is now: "
                + byteArrayToString(identifierBytes));
      } else {
        LogManager.d(TAG, "Identifier size is just right: " + byteArrayToString(identifierBytes));
      }
      for (int index = this.mIdentifierStartOffsets.get(identifierNum);
          index <= this.mIdentifierStartOffsets.get(identifierNum) + identifierBytes.length - 1;
          index++) {
        advertisingBytes[index - 2] =
            (byte) identifierBytes[index - this.mIdentifierStartOffsets.get(identifierNum)];
      }
    }

    // set power
    for (int index = this.mPowerStartOffset; index <= this.mPowerEndOffset; index++) {
      advertisingBytes[index - 2] =
          (byte) (beacon.getTxPower() >> (8 * (index - this.mPowerStartOffset)) & 0xff);
    }

    // set data fields
    for (int dataFieldNum = 0; dataFieldNum < this.mDataStartOffsets.size(); dataFieldNum++) {
      long dataField = beacon.getDataFields().get(dataFieldNum);

      for (int index = this.mDataStartOffsets.get(dataFieldNum);
          index <= this.mDataEndOffsets.get(dataFieldNum);
          index++) {
        int endianCorrectedIndex = index;
        if (this.mDataLittleEndianFlags.get(dataFieldNum)) {
          endianCorrectedIndex = this.mDataEndOffsets.get(dataFieldNum) - index;
        }
        advertisingBytes[endianCorrectedIndex - 2] =
            (byte) (dataField >> (8 * (index - this.mDataStartOffsets.get(dataFieldNum))) & 0xff);
      }
    }
    return advertisingBytes;
  }
Exemplo n.º 24
0
 /**
  * @see Beacon#mRssi
  * @param rssi
  * @return builder
  */
 public Builder setRssi(int rssi) {
   mBeacon.mRssi = rssi;
   return this;
 }
Exemplo n.º 25
0
  @TargetApi(5)
  protected Beacon fromScanData(
      byte[] bytesToProcess, int rssi, BluetoothDevice device, Beacon beacon) {
    BleAdvertisement advert = new BleAdvertisement(bytesToProcess);
    boolean parseFailed = false;
    Pdu pduToParse = null;
    int startByte = 0;
    ArrayList<Identifier> identifiers = new ArrayList<Identifier>();
    ArrayList<Long> dataFields = new ArrayList<Long>();

    for (Pdu pdu : advert.getPdus()) {
      if (pdu.getType() == Pdu.GATT_SERVICE_UUID_PDU_TYPE
          || pdu.getType() == Pdu.MANUFACTURER_DATA_PDU_TYPE) {
        pduToParse = pdu;
        if (LogManager.isVerboseLoggingEnabled()) {
          LogManager.d(
              TAG,
              "Processing pdu type %02X: %s with startIndex: %d, endIndex: %d",
              pdu.getType(),
              bytesToHex(bytesToProcess),
              pdu.getStartIndex(),
              pdu.getEndIndex());
        }
        break;
      } else {
        if (LogManager.isVerboseLoggingEnabled()) {
          LogManager.d(TAG, "Ignoring pdu type %02X", pdu.getType());
        }
      }
    }
    if (pduToParse == null) {
      if (LogManager.isVerboseLoggingEnabled()) {
        LogManager.d(TAG, "No PDUs to process in this packet.");
      }
      parseFailed = true;
    } else {
      byte[] serviceUuidBytes = null;
      byte[] typeCodeBytes =
          longToByteArray(
              getMatchingBeaconTypeCode(),
              mMatchingBeaconTypeCodeEndOffset - mMatchingBeaconTypeCodeStartOffset + 1);
      if (getServiceUuid() != null) {
        serviceUuidBytes =
            longToByteArray(
                getServiceUuid(), mServiceUuidEndOffset - mServiceUuidStartOffset + 1, false);
      }
      startByte = pduToParse.getStartIndex();
      boolean patternFound = false;

      if (getServiceUuid() == null) {
        if (byteArraysMatch(
            bytesToProcess, startByte + mMatchingBeaconTypeCodeStartOffset, typeCodeBytes, 0)) {
          patternFound = true;
        }
      } else {
        if (byteArraysMatch(
                bytesToProcess, startByte + mServiceUuidStartOffset, serviceUuidBytes, 0)
            && byteArraysMatch(
                bytesToProcess, startByte + mMatchingBeaconTypeCodeStartOffset, typeCodeBytes, 0)) {
          patternFound = true;
        }
      }

      if (patternFound == false) {
        // This is not a beacon
        if (getServiceUuid() == null) {
          if (LogManager.isVerboseLoggingEnabled()) {
            LogManager.d(
                TAG,
                "This is not a matching Beacon advertisement. (Was expecting %s.  "
                    + "The bytes I see are: %s",
                byteArrayToString(typeCodeBytes),
                bytesToHex(bytesToProcess));
          }
        } else {
          if (LogManager.isVerboseLoggingEnabled()) {
            LogManager.d(
                TAG,
                "This is not a matching Beacon advertisement. Was expecting %s at offset %d and %s at offset %d.  "
                    + "The bytes I see are: %s",
                byteArrayToString(serviceUuidBytes),
                startByte + mServiceUuidStartOffset,
                byteArrayToString(typeCodeBytes),
                startByte + mMatchingBeaconTypeCodeStartOffset,
                bytesToHex(bytesToProcess));
          }
        }
        parseFailed = true;
        beacon = null;
      } else {
        if (LogManager.isVerboseLoggingEnabled()) {
          LogManager.d(
              TAG,
              "This is a recognized beacon advertisement -- %s seen",
              byteArrayToString(typeCodeBytes));
        }
      }

      if (patternFound) {
        if (bytesToProcess.length <= startByte + mLayoutSize && mAllowPduOverflow) {
          // If the layout size is bigger than this PDU, and we allow overflow.  Make sure
          // the byte buffer is big enough by zero padding the end so we don't try to read
          // outside the byte array of the advertisement
          if (LogManager.isVerboseLoggingEnabled()) {
            LogManager.d(
                TAG,
                "Expanding buffer because it is too short to parse: "
                    + bytesToProcess.length
                    + ", needed: "
                    + (startByte + mLayoutSize));
          }
          bytesToProcess = ensureMaxSize(bytesToProcess, startByte + mLayoutSize);
        }
        for (int i = 0; i < mIdentifierEndOffsets.size(); i++) {
          int endIndex = mIdentifierEndOffsets.get(i) + startByte;

          if (endIndex > pduToParse.getEndIndex() && mIdentifierVariableLengthFlags.get(i)) {
            if (LogManager.isVerboseLoggingEnabled()) {
              LogManager.d(
                  TAG, "Need to truncate identifier by " + (endIndex - pduToParse.getEndIndex()));
            }
            // If this is a variable length identifier, we truncate it to the size that
            // is available in the packet
            Identifier identifier =
                Identifier.fromBytes(
                    bytesToProcess,
                    mIdentifierStartOffsets.get(i) + startByte,
                    pduToParse.getEndIndex() + 1,
                    mIdentifierLittleEndianFlags.get(i));
            identifiers.add(identifier);
          } else if (endIndex > pduToParse.getEndIndex() && !mAllowPduOverflow) {
            parseFailed = true;
            if (LogManager.isVerboseLoggingEnabled()) {
              LogManager.d(
                  TAG,
                  "Cannot parse identifier "
                      + i
                      + " because PDU is too short.  endIndex: "
                      + endIndex
                      + " PDU endIndex: "
                      + pduToParse.getEndIndex());
            }
          } else {
            Identifier identifier =
                Identifier.fromBytes(
                    bytesToProcess,
                    mIdentifierStartOffsets.get(i) + startByte,
                    endIndex + 1,
                    mIdentifierLittleEndianFlags.get(i));
            identifiers.add(identifier);
          }
        }
        for (int i = 0; i < mDataEndOffsets.size(); i++) {
          int endIndex = mDataEndOffsets.get(i) + startByte;
          if (endIndex > pduToParse.getEndIndex() && !mAllowPduOverflow) {
            if (LogManager.isVerboseLoggingEnabled()) {
              LogManager.d(
                  TAG,
                  "Cannot parse data field "
                      + i
                      + " because PDU is too short.  endIndex: "
                      + endIndex
                      + " PDU endIndex: "
                      + pduToParse.getEndIndex()
                      + ".  Setting value to 0");
            }
            dataFields.add(new Long(0l));
          } else {
            String dataString =
                byteArrayToFormattedString(
                    bytesToProcess,
                    mDataStartOffsets.get(i) + startByte,
                    endIndex,
                    mDataLittleEndianFlags.get(i));
            dataFields.add(Long.parseLong(dataString));
          }
        }

        if (mPowerStartOffset != null) {
          int endIndex = mPowerEndOffset + startByte;
          int txPower = 0;
          try {
            if (endIndex > pduToParse.getEndIndex() && !mAllowPduOverflow) {
              parseFailed = true;
              if (LogManager.isVerboseLoggingEnabled()) {
                LogManager.d(
                    TAG,
                    "Cannot parse power field because PDU is too short.  endIndex: "
                        + endIndex
                        + " PDU endIndex: "
                        + pduToParse.getEndIndex());
              }
            } else {
              String powerString =
                  byteArrayToFormattedString(
                      bytesToProcess,
                      mPowerStartOffset + startByte,
                      mPowerEndOffset + startByte,
                      false);
              txPower = Integer.parseInt(powerString) + mDBmCorrection;
              // make sure it is a signed integer
              if (txPower > 127) {
                txPower -= 256;
              }
              beacon.mTxPower = txPower;
            }
          } catch (NumberFormatException e1) {
            // keep default value
          } catch (NullPointerException e2) {
            // keep default value
          }
        }
      }
    }

    if (parseFailed) {
      beacon = null;
    } else {
      int beaconTypeCode = 0;
      String beaconTypeString =
          byteArrayToFormattedString(
              bytesToProcess,
              mMatchingBeaconTypeCodeStartOffset + startByte,
              mMatchingBeaconTypeCodeEndOffset + startByte,
              false);
      beaconTypeCode = Integer.parseInt(beaconTypeString);
      // TODO: error handling needed on the parse

      int manufacturer = 0;
      String manufacturerString =
          byteArrayToFormattedString(bytesToProcess, startByte, startByte + 1, true);
      manufacturer = Integer.parseInt(manufacturerString);

      String macAddress = null;
      String name = null;
      if (device != null) {
        macAddress = device.getAddress();
        name = device.getName();
      }

      beacon.mIdentifiers = identifiers;
      beacon.mDataFields = dataFields;
      beacon.mRssi = rssi;
      beacon.mBeaconTypeCode = beaconTypeCode;
      if (mServiceUuid != null) {
        beacon.mServiceUuid = (int) mServiceUuid.longValue();
      } else {
        beacon.mServiceUuid = -1;
      }

      beacon.mBluetoothAddress = macAddress;
      beacon.mBluetoothName = name;
      beacon.mManufacturer = manufacturer;
      beacon.mParserIdentifier = mIdentifier;
    }
    return beacon;
  }