diff --git a/.idea/runConfigurations/Run_Android_Tests.xml b/.idea/runConfigurations/Run_Android_Tests.xml
new file mode 100644
index 0000000..1f32fb7
--- /dev/null
+++ b/.idea/runConfigurations/Run_Android_Tests.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations/Run_JUnit_Tests.xml b/.idea/runConfigurations/Run_JUnit_Tests.xml
new file mode 100644
index 0000000..09ab733
--- /dev/null
+++ b/.idea/runConfigurations/Run_JUnit_Tests.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations/Run_Sample_App.xml b/.idea/runConfigurations/Run_Sample_App.xml
new file mode 100644
index 0000000..8873b95
--- /dev/null
+++ b/.idea/runConfigurations/Run_Sample_App.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/library/src/main/java/uk/co/alt236/bluetoothlelib/device/mfdata/IBeaconManufacturerData.java b/library/src/main/java/uk/co/alt236/bluetoothlelib/device/mfdata/IBeaconManufacturerData.java
index fe338cd..ea7adbf 100644
--- a/library/src/main/java/uk/co/alt236/bluetoothlelib/device/mfdata/IBeaconManufacturerData.java
+++ b/library/src/main/java/uk/co/alt236/bluetoothlelib/device/mfdata/IBeaconManufacturerData.java
@@ -5,6 +5,7 @@ import java.util.Arrays;
import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice;
import uk.co.alt236.bluetoothlelib.device.adrecord.AdRecord;
import uk.co.alt236.bluetoothlelib.util.ByteUtils;
+import uk.co.alt236.bluetoothlelib.util.IBeaconUtils;
/**
* Parses the Manufactured Data field of an iBeacon
@@ -52,6 +53,12 @@ public final class IBeaconManufacturerData {
private final int mMinor;
private final String mUUID;
+ /**
+ * Instantiates a new iBeacon manufacturer data object.
+ *
+ * @param device a {@link BluetoothLeDevice}
+ * @throws IllegalArgumentException if the data is not from an iBeacon.
+ */
public IBeaconManufacturerData(final BluetoothLeDevice device) {
this(device.getAdRecordStore().getRecord(AdRecord.TYPE_MANUFACTURER_SPECIFIC_DATA).getData());
}
@@ -59,22 +66,28 @@ public final class IBeaconManufacturerData {
/**
* Instantiates a new iBeacon manufacturer data object.
*
- * @param data the {@link uk.co.alt236.bluetoothlelib.device.adrecord.AdRecord#TYPE_MANUFACTURER_SPECIFIC_DATA} data array
- * @throws IndexOutOfBoundsException if the data array is shorter than expected
+ * @param manufacturerData the {@link AdRecord#TYPE_MANUFACTURER_SPECIFIC_DATA} data array
+ * @throws IllegalArgumentException if the data is not from an iBeacon.
*/
- public IBeaconManufacturerData(final byte[] data) {
- mData = data;
+ public IBeaconManufacturerData(final byte[] manufacturerData) {
+ mData = manufacturerData;
+
+ if (!IBeaconUtils.isThisAnIBeacon(manufacturerData)) {
+ throw new IllegalArgumentException(
+ "Manufacturer record '"
+ + Arrays.toString(manufacturerData)
+ + "' is not from an iBeacon.");
+ }
final byte[] intArray = Arrays.copyOfRange(mData, 0, 2);
ByteUtils.invertArray(intArray);
mCompanyIdentidier = ByteUtils.getIntFrom2ByteArray(intArray);
-
mIBeaconAdvertisment = ByteUtils.getIntFrom2ByteArray(Arrays.copyOfRange(mData, 2, 4));
- mUUID = calculateUUIDString(Arrays.copyOfRange(mData, 4, 20));
+ mUUID = IBeaconUtils.calculateUuidString(Arrays.copyOfRange(mData, 4, 20));
mMajor = ByteUtils.getIntFrom2ByteArray(Arrays.copyOfRange(mData, 20, 22));
mMinor = ByteUtils.getIntFrom2ByteArray(Arrays.copyOfRange(mData, 22, 24));
- mCalibratedTxPower = data[24];
+ mCalibratedTxPower = mData[24];
}
/**
@@ -125,29 +138,4 @@ public final class IBeaconManufacturerData {
public String getUUID() {
return mUUID;
}
-
- private static String calculateUUIDString(final byte[] uuid) {
- final StringBuilder sb = new StringBuilder();
-
- for (int i = 0; i < uuid.length; i++) {
- if (i == 4) {
- sb.append('-');
- }
- if (i == 6) {
- sb.append('-');
- }
- if (i == 8) {
- sb.append('-');
- }
- if (i == 10) {
- sb.append('-');
- }
-
- sb.append(
- Integer.toHexString(ByteUtils.getIntFromByte(uuid[i])));
- }
-
-
- return sb.toString();
- }
}
diff --git a/library/src/main/java/uk/co/alt236/bluetoothlelib/util/AdRecordUtils.java b/library/src/main/java/uk/co/alt236/bluetoothlelib/util/AdRecordUtils.java
index cc87d8a..c872f82 100644
--- a/library/src/main/java/uk/co/alt236/bluetoothlelib/util/AdRecordUtils.java
+++ b/library/src/main/java/uk/co/alt236/bluetoothlelib/util/AdRecordUtils.java
@@ -12,7 +12,11 @@ import java.util.Map;
import uk.co.alt236.bluetoothlelib.device.adrecord.AdRecord;
-public class AdRecordUtils {
+public final class AdRecordUtils {
+
+ private AdRecordUtils(){
+ // TO AVOID INSTANTIATION
+ }
public static String getRecordDataAsString(final AdRecord nameRecord) {
if (nameRecord == null) {
diff --git a/library/src/main/java/uk/co/alt236/bluetoothlelib/util/ByteUtils.java b/library/src/main/java/uk/co/alt236/bluetoothlelib/util/ByteUtils.java
index 5d4aed0..53f009f 100644
--- a/library/src/main/java/uk/co/alt236/bluetoothlelib/util/ByteUtils.java
+++ b/library/src/main/java/uk/co/alt236/bluetoothlelib/util/ByteUtils.java
@@ -9,6 +9,10 @@ public class ByteUtils {
*/
private static final String HEXES = "0123456789ABCDEF";
+ private ByteUtils(){
+ // TO AVOID INSTANTIATION
+ }
+
/**
* Gets a pretty representation of a Byte Array as a HEX String.
*
diff --git a/library/src/main/java/uk/co/alt236/bluetoothlelib/util/IBeaconUtils.java b/library/src/main/java/uk/co/alt236/bluetoothlelib/util/IBeaconUtils.java
index b992e4a..084f15a 100644
--- a/library/src/main/java/uk/co/alt236/bluetoothlelib/util/IBeaconUtils.java
+++ b/library/src/main/java/uk/co/alt236/bluetoothlelib/util/IBeaconUtils.java
@@ -13,7 +13,7 @@ public class IBeaconUtils {
/**
* Calculates the accuracy of an RSSI reading.
*
- * The code was taken from {@linktourl http://stackoverflow.com/questions/20416218/understanding-ibeacon-distancing}
+ * The code was taken from
*
* @param txPower the calibrated TX power of an iBeacon
* @param rssi the RSSI value of the iBeacon
@@ -28,11 +28,35 @@ public class IBeaconUtils {
if (ratio < 1.0) {
return Math.pow(ratio, 10);
} else {
- final double accuracy = (0.89976) * Math.pow(ratio, 7.7095) + 0.111;
- return accuracy;
+ return (0.89976) * Math.pow(ratio, 7.7095) + 0.111;
}
}
+ public static String calculateUuidString(final byte[] uuid) {
+ final StringBuilder sb = new StringBuilder();
+
+ for (int i = 0; i < uuid.length; i++) {
+ if (i == 4) {
+ sb.append('-');
+ }
+ if (i == 6) {
+ sb.append('-');
+ }
+ if (i == 8) {
+ sb.append('-');
+ }
+ if (i == 10) {
+ sb.append('-');
+ }
+
+ final int intFromByte = ByteUtils.getIntFromByte(uuid[i]);
+ sb.append(Integer.toHexString(intFromByte));
+ }
+
+
+ return sb.toString();
+ }
+
public static IBeaconDistanceDescriptor getDistanceDescriptor(final double accuracy) {
if (accuracy < DISTANCE_THRESHOLD_WTF) {
return IBeaconDistanceDescriptor.UNKNOWN;
@@ -49,17 +73,6 @@ public class IBeaconUtils {
return IBeaconDistanceDescriptor.FAR;
}
- /**
- * 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) {
- return isThisAnIBeacon(
- device.getAdRecordStore().getRecordDataAsString(AdRecord.TYPE_MANUFACTURER_SPECIFIC_DATA).getBytes());
- }
-
/**
* Ascertains whether a Manufacturer Data byte array belongs to an iBeacon;
*
@@ -83,4 +96,14 @@ public class IBeaconUtils {
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) {
+ return isThisAnIBeacon(
+ device.getAdRecordStore().getRecordDataAsString(AdRecord.TYPE_MANUFACTURER_SPECIFIC_DATA).getBytes());
+ }
}
diff --git a/library/src/test/java/uk/co/alt236/bluetoothlelib/util/AdRecordUtilsTest.java b/library/src/test/java/uk/co/alt236/bluetoothlelib/util/AdRecordUtilsTest.java
new file mode 100644
index 0000000..455bb6e
--- /dev/null
+++ b/library/src/test/java/uk/co/alt236/bluetoothlelib/util/AdRecordUtilsTest.java
@@ -0,0 +1,58 @@
+package uk.co.alt236.bluetoothlelib.util;
+
+import junit.framework.TestCase;
+
+import java.util.List;
+import java.util.Map;
+
+import uk.co.alt236.bluetoothlelib.device.adrecord.AdRecord;
+
+/**
+ *
+ */
+public class AdRecordUtilsTest extends TestCase {
+ private static final byte[] NON_IBEACON =
+ {2, 1, 26, 11, -1, 76, 0, 9, 6, 3, -32, -64, -88,
+ 1, 98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+ public void testParseScanRecordAsList() throws Exception {
+ final List adRecords = AdRecordUtils.parseScanRecordAsList(NON_IBEACON);
+ assertNotNull(adRecords);
+ assertEquals(2, adRecords.size());
+
+ int type = AdRecord.TYPE_FLAGS;
+ assertEquals(type, adRecords.get(0).getType());
+ assertEquals(2, adRecords.get(0).getLength());
+
+ type = AdRecord.TYPE_MANUFACTURER_SPECIFIC_DATA;
+ assertEquals(type, adRecords.get(1).getType());
+ assertEquals(11, adRecords.get(1).getLength());
+ }
+
+ public void testParseScanRecordAsMap() throws Exception {
+ final Map adRecords = AdRecordUtils.parseScanRecordAsMap(NON_IBEACON);
+ assertNotNull(adRecords);
+ assertEquals(2, adRecords.size());
+
+ int type = AdRecord.TYPE_FLAGS;
+ assertEquals(type, adRecords.get(type).getType());
+ assertEquals(2, adRecords.get(type).getLength());
+
+ type = AdRecord.TYPE_MANUFACTURER_SPECIFIC_DATA;
+ assertEquals(type, adRecords.get(type).getType());
+ assertEquals(11, adRecords.get(type).getLength());
+ }
+
+ public void testParseScanRecordAsSparseArray() throws Exception {
+ //
+ // Cannot be tested here as it relies on Android code...
+ //
+// final SparseArray adRecords = AdRecordUtils.parseScanRecordAsSparseArray(NON_IBEACON);
+// assertNotNull(adRecords);
+// assertEquals(2, adRecords.size());
+// assertEquals(AdRecord.TYPE_FLAGS, adRecords.get(AdRecord.TYPE_FLAGS).getType());
+// assertEquals(AdRecord.TYPE_MANUFACTURER_SPECIFIC_DATA, adRecords.get(AdRecord.TYPE_MANUFACTURER_SPECIFIC_DATA).getType());
+ }
+}
\ No newline at end of file