Skip to content

Commit 70169dc

Browse files
committed
More tests and general code cleanup
1 parent 4fcbc7c commit 70169dc

8 files changed

Lines changed: 200 additions & 47 deletions

File tree

.idea/runConfigurations/Run_Android_Tests.xml

Lines changed: 27 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/runConfigurations/Run_JUnit_Tests.xml

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/runConfigurations/Run_Sample_App.xml

Lines changed: 26 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

library/src/main/java/uk/co/alt236/bluetoothlelib/device/mfdata/IBeaconManufacturerData.java

Lines changed: 20 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice;
66
import uk.co.alt236.bluetoothlelib.device.adrecord.AdRecord;
77
import uk.co.alt236.bluetoothlelib.util.ByteUtils;
8+
import uk.co.alt236.bluetoothlelib.util.IBeaconUtils;
89

910
/**
1011
* Parses the Manufactured Data field of an iBeacon
@@ -52,29 +53,41 @@ public final class IBeaconManufacturerData {
5253
private final int mMinor;
5354
private final String mUUID;
5455

56+
/**
57+
* Instantiates a new iBeacon manufacturer data object.
58+
*
59+
* @param device a {@link BluetoothLeDevice}
60+
* @throws IllegalArgumentException if the data is not from an iBeacon.
61+
*/
5562
public IBeaconManufacturerData(final BluetoothLeDevice device) {
5663
this(device.getAdRecordStore().getRecord(AdRecord.TYPE_MANUFACTURER_SPECIFIC_DATA).getData());
5764
}
5865

5966
/**
6067
* Instantiates a new iBeacon manufacturer data object.
6168
*
62-
* @param data the {@link uk.co.alt236.bluetoothlelib.device.adrecord.AdRecord#TYPE_MANUFACTURER_SPECIFIC_DATA} data array
63-
* @throws IndexOutOfBoundsException if the data array is shorter than expected
69+
* @param manufacturerData the {@link AdRecord#TYPE_MANUFACTURER_SPECIFIC_DATA} data array
70+
* @throws IllegalArgumentException if the data is not from an iBeacon.
6471
*/
65-
public IBeaconManufacturerData(final byte[] data) {
66-
mData = data;
72+
public IBeaconManufacturerData(final byte[] manufacturerData) {
73+
mData = manufacturerData;
74+
75+
if (!IBeaconUtils.isThisAnIBeacon(manufacturerData)) {
76+
throw new IllegalArgumentException(
77+
"Manufacturer record '"
78+
+ Arrays.toString(manufacturerData)
79+
+ "' is not from an iBeacon.");
80+
}
6781

6882
final byte[] intArray = Arrays.copyOfRange(mData, 0, 2);
6983
ByteUtils.invertArray(intArray);
7084

7185
mCompanyIdentidier = ByteUtils.getIntFrom2ByteArray(intArray);
72-
7386
mIBeaconAdvertisment = ByteUtils.getIntFrom2ByteArray(Arrays.copyOfRange(mData, 2, 4));
74-
mUUID = calculateUUIDString(Arrays.copyOfRange(mData, 4, 20));
87+
mUUID = IBeaconUtils.calculateUuidString(Arrays.copyOfRange(mData, 4, 20));
7588
mMajor = ByteUtils.getIntFrom2ByteArray(Arrays.copyOfRange(mData, 20, 22));
7689
mMinor = ByteUtils.getIntFrom2ByteArray(Arrays.copyOfRange(mData, 22, 24));
77-
mCalibratedTxPower = data[24];
90+
mCalibratedTxPower = mData[24];
7891
}
7992

8093
/**
@@ -125,29 +138,4 @@ public int getMinor() {
125138
public String getUUID() {
126139
return mUUID;
127140
}
128-
129-
private static String calculateUUIDString(final byte[] uuid) {
130-
final StringBuilder sb = new StringBuilder();
131-
132-
for (int i = 0; i < uuid.length; i++) {
133-
if (i == 4) {
134-
sb.append('-');
135-
}
136-
if (i == 6) {
137-
sb.append('-');
138-
}
139-
if (i == 8) {
140-
sb.append('-');
141-
}
142-
if (i == 10) {
143-
sb.append('-');
144-
}
145-
146-
sb.append(
147-
Integer.toHexString(ByteUtils.getIntFromByte(uuid[i])));
148-
}
149-
150-
151-
return sb.toString();
152-
}
153141
}

library/src/main/java/uk/co/alt236/bluetoothlelib/util/AdRecordUtils.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@
1212

1313
import uk.co.alt236.bluetoothlelib.device.adrecord.AdRecord;
1414

15-
public class AdRecordUtils {
15+
public final class AdRecordUtils {
16+
17+
private AdRecordUtils(){
18+
// TO AVOID INSTANTIATION
19+
}
1620

1721
public static String getRecordDataAsString(final AdRecord nameRecord) {
1822
if (nameRecord == null) {

library/src/main/java/uk/co/alt236/bluetoothlelib/util/ByteUtils.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ public class ByteUtils {
99
*/
1010
private static final String HEXES = "0123456789ABCDEF";
1111

12+
private ByteUtils(){
13+
// TO AVOID INSTANTIATION
14+
}
15+
1216
/**
1317
* Gets a pretty representation of a Byte Array as a HEX String.
1418
* <p/>

library/src/main/java/uk/co/alt236/bluetoothlelib/util/IBeaconUtils.java

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public class IBeaconUtils {
1313
/**
1414
* Calculates the accuracy of an RSSI reading.
1515
* <p/>
16-
* The code was taken from {@linktourl http://stackoverflow.com/questions/20416218/understanding-ibeacon-distancing}
16+
* The code was taken from <a href="http://stackoverflow.com/questions/20416218/understanding-ibeacon-distancing" /a>
1717
*
1818
* @param txPower the calibrated TX power of an iBeacon
1919
* @param rssi the RSSI value of the iBeacon
@@ -28,11 +28,35 @@ public static double calculateAccuracy(final int txPower, final double rssi) {
2828
if (ratio < 1.0) {
2929
return Math.pow(ratio, 10);
3030
} else {
31-
final double accuracy = (0.89976) * Math.pow(ratio, 7.7095) + 0.111;
32-
return accuracy;
31+
return (0.89976) * Math.pow(ratio, 7.7095) + 0.111;
3332
}
3433
}
3534

35+
public static String calculateUuidString(final byte[] uuid) {
36+
final StringBuilder sb = new StringBuilder();
37+
38+
for (int i = 0; i < uuid.length; i++) {
39+
if (i == 4) {
40+
sb.append('-');
41+
}
42+
if (i == 6) {
43+
sb.append('-');
44+
}
45+
if (i == 8) {
46+
sb.append('-');
47+
}
48+
if (i == 10) {
49+
sb.append('-');
50+
}
51+
52+
final int intFromByte = ByteUtils.getIntFromByte(uuid[i]);
53+
sb.append(Integer.toHexString(intFromByte));
54+
}
55+
56+
57+
return sb.toString();
58+
}
59+
3660
public static IBeaconDistanceDescriptor getDistanceDescriptor(final double accuracy) {
3761
if (accuracy < DISTANCE_THRESHOLD_WTF) {
3862
return IBeaconDistanceDescriptor.UNKNOWN;
@@ -49,17 +73,6 @@ public static IBeaconDistanceDescriptor getDistanceDescriptor(final double accur
4973
return IBeaconDistanceDescriptor.FAR;
5074
}
5175

52-
/**
53-
* Ascertains whether a {@link uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice} is an iBeacon;
54-
*
55-
* @param device a {@link uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice} device.
56-
* @return true if the device is an iBeacon, false otherwise
57-
*/
58-
public static boolean isThisAnIBeacon(final BluetoothLeDevice device) {
59-
return isThisAnIBeacon(
60-
device.getAdRecordStore().getRecordDataAsString(AdRecord.TYPE_MANUFACTURER_SPECIFIC_DATA).getBytes());
61-
}
62-
6376
/**
6477
* Ascertains whether a Manufacturer Data byte array belongs to an iBeacon;
6578
*
@@ -83,4 +96,14 @@ public static boolean isThisAnIBeacon(final byte[] manufacturerData) {
8396
return false;
8497
}
8598

99+
/**
100+
* Ascertains whether a {@link uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice} is an iBeacon;
101+
*
102+
* @param device a {@link uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice} device.
103+
* @return true if the device is an iBeacon, false otherwise
104+
*/
105+
public static boolean isThisAnIBeacon(final BluetoothLeDevice device) {
106+
return isThisAnIBeacon(
107+
device.getAdRecordStore().getRecordDataAsString(AdRecord.TYPE_MANUFACTURER_SPECIFIC_DATA).getBytes());
108+
}
86109
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package uk.co.alt236.bluetoothlelib.util;
2+
3+
import junit.framework.TestCase;
4+
5+
import java.util.List;
6+
import java.util.Map;
7+
8+
import uk.co.alt236.bluetoothlelib.device.adrecord.AdRecord;
9+
10+
/**
11+
*
12+
*/
13+
public class AdRecordUtilsTest extends TestCase {
14+
private static final byte[] NON_IBEACON =
15+
{2, 1, 26, 11, -1, 76, 0, 9, 6, 3, -32, -64, -88,
16+
1, 98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
17+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
18+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
19+
20+
public void testParseScanRecordAsList() throws Exception {
21+
final List<AdRecord> adRecords = AdRecordUtils.parseScanRecordAsList(NON_IBEACON);
22+
assertNotNull(adRecords);
23+
assertEquals(2, adRecords.size());
24+
25+
int type = AdRecord.TYPE_FLAGS;
26+
assertEquals(type, adRecords.get(0).getType());
27+
assertEquals(2, adRecords.get(0).getLength());
28+
29+
type = AdRecord.TYPE_MANUFACTURER_SPECIFIC_DATA;
30+
assertEquals(type, adRecords.get(1).getType());
31+
assertEquals(11, adRecords.get(1).getLength());
32+
}
33+
34+
public void testParseScanRecordAsMap() throws Exception {
35+
final Map<Integer, AdRecord> adRecords = AdRecordUtils.parseScanRecordAsMap(NON_IBEACON);
36+
assertNotNull(adRecords);
37+
assertEquals(2, adRecords.size());
38+
39+
int type = AdRecord.TYPE_FLAGS;
40+
assertEquals(type, adRecords.get(type).getType());
41+
assertEquals(2, adRecords.get(type).getLength());
42+
43+
type = AdRecord.TYPE_MANUFACTURER_SPECIFIC_DATA;
44+
assertEquals(type, adRecords.get(type).getType());
45+
assertEquals(11, adRecords.get(type).getLength());
46+
}
47+
48+
public void testParseScanRecordAsSparseArray() throws Exception {
49+
//
50+
// Cannot be tested here as it relies on Android code...
51+
//
52+
// final SparseArray<AdRecord> adRecords = AdRecordUtils.parseScanRecordAsSparseArray(NON_IBEACON);
53+
// assertNotNull(adRecords);
54+
// assertEquals(2, adRecords.size());
55+
// assertEquals(AdRecord.TYPE_FLAGS, adRecords.get(AdRecord.TYPE_FLAGS).getType());
56+
// assertEquals(AdRecord.TYPE_MANUFACTURER_SPECIFIC_DATA, adRecords.get(AdRecord.TYPE_MANUFACTURER_SPECIFIC_DATA).getType());
57+
}
58+
}

0 commit comments

Comments
 (0)