@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()); }
/** * @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()); }
@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()); }
/** * 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; }