Skip to content

Commit

Permalink
Merge pull request #631 from AltBeacon/minor-refactor
Browse files Browse the repository at this point in the history
Minor refactor and annotation updates
  • Loading branch information
davidgyoung authored Dec 16, 2017
2 parents f221213 + 9b628e2 commit c6e34c5
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 50 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package org.altbeacon.beacon.service;

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;

import org.altbeacon.beacon.Beacon;

import java.io.Serializable;
Expand All @@ -12,11 +15,17 @@
*/
public class ExtraDataBeaconTracker implements Serializable {
private static final String TAG = "BeaconTracker";
// This is a lookup table to find tracked beacons by the calculated beacon key
private HashMap<String,HashMap<Integer,Beacon>> mBeaconsByKey = new HashMap<String,HashMap<Integer,Beacon>>();

private boolean matchBeaconsByServiceUUID = true;
/**
* This is a lookup table to find tracked beacons by the calculated beacon key
*/
@NonNull
private final HashMap<String,HashMap<Integer,Beacon>> mBeaconsByKey = new HashMap<>();

private final boolean matchBeaconsByServiceUUID;

public ExtraDataBeaconTracker() {
this(true);
}

public ExtraDataBeaconTracker(boolean matchBeaconsByServiceUUID) {
Expand All @@ -25,12 +34,10 @@ public ExtraDataBeaconTracker(boolean matchBeaconsByServiceUUID) {

/**
* Tracks a beacon. For Gatt-based beacons, returns a merged copy of fields from multiple
* frames. Returns null when passed a Gatt-based beacon that has is only extra beacon data.
*
* @param beacon
* @return
* frames. Returns null when passed a Gatt-based beacon that has is only extra beacon data.
*/
public synchronized Beacon track(Beacon beacon) {
@Nullable
public synchronized Beacon track(@NonNull Beacon beacon) {
Beacon trackedBeacon = null;
if (beacon.isMultiFrameBeacon() || beacon.getServiceUuid() != -1) {
trackedBeacon = trackGattBeacon(beacon);
Expand All @@ -41,42 +48,42 @@ public synchronized Beacon track(Beacon beacon) {
return trackedBeacon;
}

// The following code is for dealing with merging data fields in beacons
private Beacon trackGattBeacon(Beacon beacon) {
Beacon trackedBeacon = null;
HashMap<Integer,Beacon> matchingTrackedBeacons = mBeaconsByKey.get(getBeaconKey(beacon));
if (matchingTrackedBeacons != null) {
for (Beacon matchingTrackedBeacon: matchingTrackedBeacons.values()) {
if (beacon.isExtraBeaconData()) {
matchingTrackedBeacon.setRssi(beacon.getRssi());
matchingTrackedBeacon.setExtraDataFields(beacon.getDataFields());
}
else {
beacon.setExtraDataFields(matchingTrackedBeacon.getExtraDataFields());
// replace the tracked beacon instance with this one so it has updated values
trackedBeacon = beacon;
}
}
}
if (!beacon.isExtraBeaconData()) {
updateTrackingHashes(beacon, matchingTrackedBeacons);
/**
* The following code is for dealing with merging data fields in beacons
*/
@Nullable
private Beacon trackGattBeacon(@NonNull Beacon beacon) {
if (beacon.isExtraBeaconData()) {
updateTrackedBeacons(beacon);
return null;
}

if (trackedBeacon == null && !beacon.isExtraBeaconData()) {
trackedBeacon = beacon;
String key = getBeaconKey(beacon);
HashMap<Integer,Beacon> matchingTrackedBeacons = mBeaconsByKey.get(key);
if (null == matchingTrackedBeacons) {
matchingTrackedBeacons = new HashMap<>();
}
return trackedBeacon;
else {
Beacon trackedBeacon = matchingTrackedBeacons.values().iterator().next();
beacon.setExtraDataFields(trackedBeacon.getExtraDataFields());
}
matchingTrackedBeacons.put(beacon.hashCode(), beacon);
mBeaconsByKey.put(key, matchingTrackedBeacons);

return beacon;
}

private void updateTrackingHashes(Beacon trackedBeacon, HashMap<Integer,Beacon> matchingTrackedBeacons) {
if (matchingTrackedBeacons == null) {
matchingTrackedBeacons = new HashMap<Integer,Beacon>();
private void updateTrackedBeacons(@NonNull Beacon beacon) {
HashMap<Integer,Beacon> matchingTrackedBeacons = mBeaconsByKey.get(getBeaconKey(beacon));
if (null != matchingTrackedBeacons) {
for (Beacon matchingTrackedBeacon : matchingTrackedBeacons.values()) {
matchingTrackedBeacon.setRssi(beacon.getRssi());
matchingTrackedBeacon.setExtraDataFields(beacon.getDataFields());
}
}
matchingTrackedBeacons.put(trackedBeacon.hashCode(), trackedBeacon);
mBeaconsByKey.put(getBeaconKey(trackedBeacon), matchingTrackedBeacons);
}

private String getBeaconKey(Beacon beacon) {
private String getBeaconKey(@NonNull Beacon beacon) {
if (matchBeaconsByServiceUUID) {
return beacon.getBluetoothAddress() + beacon.getServiceUuid();
} else {
Expand Down
7 changes: 5 additions & 2 deletions src/main/java/org/altbeacon/beacon/service/ScanHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,10 @@ class ScanHelper {
private MonitoringStatus mMonitoringStatus;
private final Map<Region, RangeState> mRangedRegionState = new HashMap<>();
private DistinctPacketDetector mDistinctPacketDetector = new DistinctPacketDetector();
private ExtraDataBeaconTracker mExtraDataBeaconTracker;

@NonNull
private ExtraDataBeaconTracker mExtraDataBeaconTracker = new ExtraDataBeaconTracker();

private Set<BeaconParser> mBeaconParsers = new HashSet<>();
private List<Beacon> mSimulatedScanData = null;
private Context mContext;
Expand Down Expand Up @@ -99,7 +102,7 @@ void setRangedRegionState(Map<Region, RangeState> rangedRegionState) {
}
}

void setExtraDataBeaconTracker(ExtraDataBeaconTracker extraDataBeaconTracker) {
void setExtraDataBeaconTracker(@NonNull ExtraDataBeaconTracker extraDataBeaconTracker) {
mExtraDataBeaconTracker = extraDataBeaconTracker;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,9 @@
import java.util.ArrayList;
import java.util.List;

import dalvik.annotation.TestTargetClass;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;

@RunWith(RobolectricTestRunner.class)
@Config(sdk = 18)
Expand Down Expand Up @@ -59,6 +57,7 @@ Beacon getGattBeaconExtraData() {
return new Beacon.Builder()
.setBluetoothAddress("01:02:03:04:05:06")
.setServiceUuid(1234)
.setRssi(-25)
.setDataFields(getDataFields())
.build();
}
Expand All @@ -67,6 +66,7 @@ Beacon getGattBeaconExtraData2() {
return new Beacon.Builder()
.setBluetoothAddress("01:02:03:04:05:06")
.setServiceUuid(1234)
.setRssi(-50)
.setDataFields(getDataFields2())
.build();
}
Expand Down Expand Up @@ -119,32 +119,44 @@ public void gattBeaconExtraDataGetUpdated() {
ExtraDataBeaconTracker tracker = new ExtraDataBeaconTracker();
tracker.track(beacon);
tracker.track(extraDataBeacon);
tracker.track(extraDataBeacon2);
Beacon trackedBeacon = tracker.track(beacon);
assertEquals("rssi should be updated", extraDataBeacon.getRssi(), trackedBeacon.getRssi());
assertEquals("extra data is updated", extraDataBeacon.getDataFields(), trackedBeacon.getExtraDataFields());

tracker.track(extraDataBeacon2);
trackedBeacon = tracker.track(beacon);
assertEquals("rssi should be updated", extraDataBeacon2.getRssi(), trackedBeacon.getRssi());
assertEquals("extra data is updated", extraDataBeacon2.getDataFields(), trackedBeacon.getExtraDataFields());
}

@Test
public void gattBeaconExtraDataAreNotOverwritten() {
public void gattBeaconFieldsAreNotUpdated() {
Beacon beacon = getGattBeacon();
Beacon extraDataBeacon = getGattBeaconExtraData();
final int originalRssi = beacon.getRssi();
final List<Long> originalData = beacon.getDataFields();
final List<Long> originalExtra = beacon.getExtraDataFields();
Beacon beaconUpdate = getGattBeaconUpdate();
ExtraDataBeaconTracker tracker = new ExtraDataBeaconTracker();
tracker.track(beacon);
tracker.track(extraDataBeacon);
tracker.track(beaconUpdate);
Beacon trackedBeacon = tracker.track(beacon);
assertEquals("extra data should not be overwritten", extraDataBeacon.getDataFields(), trackedBeacon.getExtraDataFields());
assertEquals("rssi should NOT be updated", originalRssi, trackedBeacon.getRssi());
assertEquals("data should NOT be updated", originalData, trackedBeacon.getDataFields());
assertEquals("extra data should NOT be updated", originalExtra, trackedBeacon.getExtraDataFields());
}

@Test
public void gattBeaconFieldsGetUpdated() {
Beacon beacon = getGattBeacon();
Beacon beaconUpdate = getGattBeaconUpdate();
Beacon extraDataBeacon = getGattBeaconExtraData();
Beacon repeatBeacon = getGattBeacon();
repeatBeacon.setRssi(-100);
ExtraDataBeaconTracker tracker = new ExtraDataBeaconTracker();
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());
tracker.track(extraDataBeacon);
Beacon trackedBeacon = tracker.track(repeatBeacon);
assertEquals("rssi should NOT be updated", -100, trackedBeacon.getRssi());
assertEquals("extra data fields should be updated", extraDataBeacon.getDataFields(), trackedBeacon.getExtraDataFields());
}

@Test
Expand Down

0 comments on commit c6e34c5

Please sign in to comment.