package org.altbeacon.beacon.service;
import org.altbeacon.beacon.Beacon;
import java.util.HashMap;
/**
* Keeps track of beacons that have ever been seen and
* merges them together depending on configured beacon parsers
* Created by dyoung on 5/5/15.
*/
public class ExtraDataBeaconTracker {
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;
public ExtraDataBeaconTracker() {
}
public ExtraDataBeaconTracker(boolean matchBeaconsByServiceUUID) {
this.matchBeaconsByServiceUUID = 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
*/
public synchronized Beacon track(Beacon beacon) {
Beacon trackedBeacon = null;
if (beacon.isMultiFrameBeacon() || beacon.getServiceUuid() != -1) {
trackedBeacon = trackGattBeacon(beacon);
}
else {
trackedBeacon = 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);
}
if (trackedBeacon == null && !beacon.isExtraBeaconData()) {
trackedBeacon = beacon;
}
return trackedBeacon;
}
private void updateTrackingHashes(Beacon trackedBeacon, HashMap<Integer,Beacon> matchingTrackedBeacons) {
if (matchingTrackedBeacons == null) {
matchingTrackedBeacons = new HashMap<Integer,Beacon>();
}
matchingTrackedBeacons.put(trackedBeacon.hashCode(), trackedBeacon);
mBeaconsByKey.put(getBeaconKey(trackedBeacon), matchingTrackedBeacons);
}
private String getBeaconKey(Beacon beacon) {
if (matchBeaconsByServiceUUID) {
return beacon.getBluetoothAddress() + beacon.getServiceUuid();
} else {
return beacon.getBluetoothAddress();
}
}
}