Started making the library less bound to ibeacons
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
package uk.co.alt236.bluetoothlelib.device.beacon;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public enum BeaconType {
|
||||
NOT_A_BEACON,
|
||||
IBEACON
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package uk.co.alt236.bluetoothlelib.device.beacon;
|
||||
|
||||
import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice;
|
||||
import uk.co.alt236.bluetoothlelib.device.adrecord.AdRecord;
|
||||
import uk.co.alt236.bluetoothlelib.device.beacon.ibeacon.IBeaconConstants;
|
||||
import uk.co.alt236.bluetoothlelib.util.ByteUtils;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public final class BeaconUtils {
|
||||
|
||||
private BeaconUtils(){
|
||||
// TO AVOID INSTANTIATION
|
||||
}
|
||||
|
||||
/**
|
||||
* Ascertains whether a Manufacturer Data byte array belongs to a known Beacon type;
|
||||
*
|
||||
* @param manufacturerData a Bluetooth LE device's raw manufacturerData.
|
||||
* @return the {@link BeaconType}
|
||||
*/
|
||||
public static BeaconType getBeaconType(final byte[] manufacturerData) {
|
||||
if (manufacturerData == null) {
|
||||
return BeaconType.NOT_A_BEACON;
|
||||
}
|
||||
|
||||
if(isIBeacon(manufacturerData)){
|
||||
return BeaconType.IBEACON;
|
||||
} else {
|
||||
return BeaconType.NOT_A_BEACON;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ascertains whether a {@link uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice} is an iBeacon;
|
||||
*
|
||||
* @param device a {@link uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice} device.
|
||||
* @return the {@link BeaconType}
|
||||
*/
|
||||
public static BeaconType getBeaconType(final BluetoothLeDevice device) {
|
||||
final int key = AdRecord.TYPE_MANUFACTURER_SPECIFIC_DATA;
|
||||
return getBeaconType(device.getAdRecordStore().getRecordDataAsString(key).getBytes());
|
||||
}
|
||||
|
||||
private static boolean isIBeacon(final byte[] manufacturerData){
|
||||
// An iBeacon record must be at least 25 chars long
|
||||
if (!(manufacturerData.length >= 25)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ByteUtils.doesArrayBeginWith(manufacturerData, IBeaconConstants.MANUFACTURER_DATA_IBEACON_PREFIX)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package uk.co.alt236.bluetoothlelib.device.beacon.ibeacon;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class IBeaconConstants {
|
||||
public static final byte[] MANUFACTURER_DATA_IBEACON_PREFIX = {0x4C, 0x00, 0x02, 0x15};
|
||||
|
||||
}
|
||||
+5
-5
@@ -1,11 +1,11 @@
|
||||
package uk.co.alt236.bluetoothlelib.device;
|
||||
package uk.co.alt236.bluetoothlelib.device.beacon.ibeacon;
|
||||
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.os.Parcel;
|
||||
|
||||
import uk.co.alt236.bluetoothlelib.device.mfdata.IBeaconManufacturerData;
|
||||
import uk.co.alt236.bluetoothlelib.util.IBeaconDistanceDescriptor;
|
||||
import uk.co.alt236.bluetoothlelib.util.IBeaconUtils;
|
||||
import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice;
|
||||
import uk.co.alt236.bluetoothlelib.device.beacon.BeaconType;
|
||||
import uk.co.alt236.bluetoothlelib.device.beacon.BeaconUtils;
|
||||
|
||||
public class IBeaconDevice extends BluetoothLeDevice {
|
||||
|
||||
@@ -139,7 +139,7 @@ public class IBeaconDevice extends BluetoothLeDevice {
|
||||
}
|
||||
|
||||
private void validate() {
|
||||
if (!IBeaconUtils.isThisAnIBeacon(this)) {
|
||||
if (BeaconUtils.getBeaconType(this) != BeaconType.IBEACON) {
|
||||
throw new IllegalArgumentException("Device " + getDevice() + " is not an iBeacon.");
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package uk.co.alt236.bluetoothlelib.util;
|
||||
package uk.co.alt236.bluetoothlelib.device.beacon.ibeacon;
|
||||
|
||||
public enum IBeaconDistanceDescriptor {
|
||||
IMMEDIATE,
|
||||
+4
-3
@@ -1,11 +1,12 @@
|
||||
package uk.co.alt236.bluetoothlelib.device.mfdata;
|
||||
package uk.co.alt236.bluetoothlelib.device.beacon.ibeacon;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice;
|
||||
import uk.co.alt236.bluetoothlelib.device.adrecord.AdRecord;
|
||||
import uk.co.alt236.bluetoothlelib.device.beacon.BeaconType;
|
||||
import uk.co.alt236.bluetoothlelib.device.beacon.BeaconUtils;
|
||||
import uk.co.alt236.bluetoothlelib.util.ByteUtils;
|
||||
import uk.co.alt236.bluetoothlelib.util.IBeaconUtils;
|
||||
|
||||
/**
|
||||
* Parses the Manufactured Data field of an iBeacon
|
||||
@@ -72,7 +73,7 @@ public final class IBeaconManufacturerData {
|
||||
public IBeaconManufacturerData(final byte[] manufacturerData) {
|
||||
mData = manufacturerData;
|
||||
|
||||
if (!IBeaconUtils.isThisAnIBeacon(manufacturerData)) {
|
||||
if (BeaconUtils.getBeaconType(mData) != BeaconType.IBEACON) {
|
||||
throw new IllegalArgumentException(
|
||||
"Manufacturer record '"
|
||||
+ Arrays.toString(manufacturerData)
|
||||
+6
-39
@@ -1,14 +1,15 @@
|
||||
package uk.co.alt236.bluetoothlelib.util;
|
||||
package uk.co.alt236.bluetoothlelib.device.beacon.ibeacon;
|
||||
|
||||
import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice;
|
||||
import uk.co.alt236.bluetoothlelib.device.adrecord.AdRecord;
|
||||
import uk.co.alt236.bluetoothlelib.util.ByteUtils;
|
||||
|
||||
public class IBeaconUtils {
|
||||
final class IBeaconUtils {
|
||||
private static final double DISTANCE_THRESHOLD_WTF = 0.0;
|
||||
private static final double DISTANCE_THRESHOLD_IMMEDIATE = 0.5;
|
||||
private static final double DISTANCE_THRESHOLD_NEAR = 3.0;
|
||||
|
||||
private static final byte[] MANUFACTURER_DATA_IBEACON_PREFIX = {0x4C, 0x00, 0x02, 0x15};
|
||||
private IBeaconUtils(){
|
||||
// TO AVOID INSTANTIATION
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the accuracy of an RSSI reading.
|
||||
@@ -75,38 +76,4 @@ public class IBeaconUtils {
|
||||
|
||||
return IBeaconDistanceDescriptor.FAR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ascertains whether a Manufacturer Data byte array belongs to an iBeacon;
|
||||
*
|
||||
* @param manufacturerData a Bluetooth LE device's raw manufacturerData.
|
||||
* @return true if the manufacturer data belong to an iBeacon
|
||||
*/
|
||||
public static boolean isThisAnIBeacon(final byte[] manufacturerData) {
|
||||
if (manufacturerData == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// An iBeacon record must be at least 25 chars long
|
||||
if (!(manufacturerData.length >= 25)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ByteUtils.doesArrayBeginWith(manufacturerData, MANUFACTURER_DATA_IBEACON_PREFIX)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ascertains whether a {@link uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice} is an iBeacon;
|
||||
*
|
||||
* @param device a {@link uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice} device.
|
||||
* @return true if the device is an iBeacon, false otherwise
|
||||
*/
|
||||
public static boolean isThisAnIBeacon(final BluetoothLeDevice device) {
|
||||
final int key = AdRecord.TYPE_MANUFACTURER_SPECIFIC_DATA;
|
||||
return isThisAnIBeacon(device.getAdRecordStore().getRecordDataAsString(key).getBytes());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package uk.co.alt236.bluetoothlelib.device.beacon;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class BeaconUtilsTest extends TestCase {
|
||||
|
||||
public void testGetBeaconTypeInvalid() throws Exception {
|
||||
assertEquals(BeaconType.NOT_A_BEACON, BeaconUtils.getBeaconType((byte[]) null));
|
||||
assertEquals(BeaconType.NOT_A_BEACON, BeaconUtils.getBeaconType(new byte[0]));
|
||||
assertEquals(BeaconType.NOT_A_BEACON, BeaconUtils.getBeaconType(new byte[25]));
|
||||
}
|
||||
|
||||
public void testGetBeaconTypeIBeacon() throws Exception {
|
||||
assertEquals(BeaconType.IBEACON, BeaconUtils.getBeaconType(new byte[]{
|
||||
0x4C, 0x00, 0x02, 0x15, 0x00, // <- Magic iBeacon header
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00
|
||||
}));
|
||||
}
|
||||
}
|
||||
+1
-15
@@ -1,4 +1,4 @@
|
||||
package uk.co.alt236.bluetoothlelib.util;
|
||||
package uk.co.alt236.bluetoothlelib.device.beacon.ibeacon;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
@@ -7,20 +7,6 @@ import junit.framework.TestCase;
|
||||
*/
|
||||
public class IBeaconUtilsTest extends TestCase {
|
||||
|
||||
public void testIsThisAnIBeacon() throws Exception {
|
||||
assertFalse(IBeaconUtils.isThisAnIBeacon((byte[]) null));
|
||||
assertFalse(IBeaconUtils.isThisAnIBeacon(new byte[0]));
|
||||
assertFalse(IBeaconUtils.isThisAnIBeacon(new byte[25]));
|
||||
|
||||
assertTrue(IBeaconUtils.isThisAnIBeacon(new byte[]{
|
||||
0x4C, 0x00, 0x02, 0x15, 0x00, // <- Magic iBeacon header
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00
|
||||
}));
|
||||
}
|
||||
|
||||
public void testGetDistanceDescriptor() throws Exception {
|
||||
assertEquals(IBeaconDistanceDescriptor.UNKNOWN, IBeaconUtils.getDistanceDescriptor(-1));
|
||||
|
||||
Reference in New Issue
Block a user