diff --git a/README.md b/README.md index e0411c6..e8fdbfc 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ In the `onLeScan()` method of your `BluetoothAdapter.LeScanCallback()` create a For example: -
+```
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
@@ -51,7 +51,7 @@ For example:
});
}
};
-
+```
### Device Properties
@@ -83,7 +83,17 @@ Once you've created a BluetoothLe device, you can access the AdRecord store via
They are also declared as constants in `AdRecord.java`.
### Fun with iBeacons
-You can check if a device is an iBeacon by using `IBeaconUtils.isThisAnIBeacon(BluetootLeDevice device)`. Once you have confirmed that it is, you can create a new IBeaconDevice via the IBeaconDevice constructor.
+You can check if a device is an iBeacon by using `BeaconUtils.getBeaconType(BluetootLeDevice device)`. Once you have confirmed that it is, you can create a new IBeaconDevice via the IBeaconDevice constructor.
+
+Example Flow:
+```
+ final BluetoothLeDevice device = ... // A generic BLE device
+
+ if (BeaconUtils.getBeaconType(device) == BeaconType.IBEACON) {
+ final IBeaconDevice iBeacon = new IBeaconDevice(device);
+ // DO STUFF
+ }
+```
An IBeaconDevice extends BluetoothLeDevice, so you still have access to the same methods as before. In addition you can do the following:
@@ -114,6 +124,7 @@ You can also lookup values and convert them to human friendly strings:
* Added some Estimote UUIDs
* v1.0.0:
* Migrated project to Android Studio/ gradle
+ * We now use the more generic `BeaconUtils.getBeaconType()` method instead of `IBeaconUtils.isThisAnIBeacon()`
* Fix for [issue 5](https://github.com/alt236/Bluetooth-LE-Library---Android/issues/5)
* Fix for [issue 9](https://github.com/alt236/Bluetooth-LE-Library---Android/issues/9)
diff --git a/library/src/main/java/uk/co/alt236/bluetoothlelib/device/beacon/BeaconType.java b/library/src/main/java/uk/co/alt236/bluetoothlelib/device/beacon/BeaconType.java
new file mode 100644
index 0000000..d843150
--- /dev/null
+++ b/library/src/main/java/uk/co/alt236/bluetoothlelib/device/beacon/BeaconType.java
@@ -0,0 +1,9 @@
+package uk.co.alt236.bluetoothlelib.device.beacon;
+
+/**
+ *
+ */
+public enum BeaconType {
+ NOT_A_BEACON,
+ IBEACON
+}
diff --git a/library/src/main/java/uk/co/alt236/bluetoothlelib/device/beacon/BeaconUtils.java b/library/src/main/java/uk/co/alt236/bluetoothlelib/device/beacon/BeaconUtils.java
new file mode 100644
index 0000000..9bafee9
--- /dev/null
+++ b/library/src/main/java/uk/co/alt236/bluetoothlelib/device/beacon/BeaconUtils.java
@@ -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;
+ }
+}
diff --git a/library/src/main/java/uk/co/alt236/bluetoothlelib/device/beacon/ibeacon/IBeaconConstants.java b/library/src/main/java/uk/co/alt236/bluetoothlelib/device/beacon/ibeacon/IBeaconConstants.java
new file mode 100644
index 0000000..6c1914f
--- /dev/null
+++ b/library/src/main/java/uk/co/alt236/bluetoothlelib/device/beacon/ibeacon/IBeaconConstants.java
@@ -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};
+
+}
diff --git a/library/src/main/java/uk/co/alt236/bluetoothlelib/device/IBeaconDevice.java b/library/src/main/java/uk/co/alt236/bluetoothlelib/device/beacon/ibeacon/IBeaconDevice.java
similarity index 92%
rename from library/src/main/java/uk/co/alt236/bluetoothlelib/device/IBeaconDevice.java
rename to library/src/main/java/uk/co/alt236/bluetoothlelib/device/beacon/ibeacon/IBeaconDevice.java
index d6dbdd5..abb2c96 100644
--- a/library/src/main/java/uk/co/alt236/bluetoothlelib/device/IBeaconDevice.java
+++ b/library/src/main/java/uk/co/alt236/bluetoothlelib/device/beacon/ibeacon/IBeaconDevice.java
@@ -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.");
}
}
diff --git a/library/src/main/java/uk/co/alt236/bluetoothlelib/util/IBeaconDistanceDescriptor.java b/library/src/main/java/uk/co/alt236/bluetoothlelib/device/beacon/ibeacon/IBeaconDistanceDescriptor.java
similarity index 60%
rename from library/src/main/java/uk/co/alt236/bluetoothlelib/util/IBeaconDistanceDescriptor.java
rename to library/src/main/java/uk/co/alt236/bluetoothlelib/device/beacon/ibeacon/IBeaconDistanceDescriptor.java
index 10d4a40..413e63e 100644
--- a/library/src/main/java/uk/co/alt236/bluetoothlelib/util/IBeaconDistanceDescriptor.java
+++ b/library/src/main/java/uk/co/alt236/bluetoothlelib/device/beacon/ibeacon/IBeaconDistanceDescriptor.java
@@ -1,4 +1,4 @@
-package uk.co.alt236.bluetoothlelib.util;
+package uk.co.alt236.bluetoothlelib.device.beacon.ibeacon;
public enum IBeaconDistanceDescriptor {
IMMEDIATE,
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/beacon/ibeacon/IBeaconManufacturerData.java
similarity index 93%
rename from library/src/main/java/uk/co/alt236/bluetoothlelib/device/mfdata/IBeaconManufacturerData.java
rename to library/src/main/java/uk/co/alt236/bluetoothlelib/device/beacon/ibeacon/IBeaconManufacturerData.java
index ea7adbf..25b14ce 100644
--- a/library/src/main/java/uk/co/alt236/bluetoothlelib/device/mfdata/IBeaconManufacturerData.java
+++ b/library/src/main/java/uk/co/alt236/bluetoothlelib/device/beacon/ibeacon/IBeaconManufacturerData.java
@@ -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)
diff --git a/library/src/main/java/uk/co/alt236/bluetoothlelib/util/IBeaconUtils.java b/library/src/main/java/uk/co/alt236/bluetoothlelib/device/beacon/ibeacon/IBeaconUtils.java
similarity index 59%
rename from library/src/main/java/uk/co/alt236/bluetoothlelib/util/IBeaconUtils.java
rename to library/src/main/java/uk/co/alt236/bluetoothlelib/device/beacon/ibeacon/IBeaconUtils.java
index f38b995..1d8d552 100644
--- a/library/src/main/java/uk/co/alt236/bluetoothlelib/util/IBeaconUtils.java
+++ b/library/src/main/java/uk/co/alt236/bluetoothlelib/device/beacon/ibeacon/IBeaconUtils.java
@@ -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());
- }
}
diff --git a/library/src/test/java/uk/co/alt236/bluetoothlelib/device/beacon/BeaconUtilsTest.java b/library/src/test/java/uk/co/alt236/bluetoothlelib/device/beacon/BeaconUtilsTest.java
new file mode 100644
index 0000000..840215f
--- /dev/null
+++ b/library/src/test/java/uk/co/alt236/bluetoothlelib/device/beacon/BeaconUtilsTest.java
@@ -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
+ }));
+ }
+}
\ No newline at end of file
diff --git a/library/src/test/java/uk/co/alt236/bluetoothlelib/util/IBeaconUtilsTest.java b/library/src/test/java/uk/co/alt236/bluetoothlelib/device/beacon/ibeacon/IBeaconUtilsTest.java
similarity index 68%
rename from library/src/test/java/uk/co/alt236/bluetoothlelib/util/IBeaconUtilsTest.java
rename to library/src/test/java/uk/co/alt236/bluetoothlelib/device/beacon/ibeacon/IBeaconUtilsTest.java
index be5ffdc..681064f 100644
--- a/library/src/test/java/uk/co/alt236/bluetoothlelib/util/IBeaconUtilsTest.java
+++ b/library/src/test/java/uk/co/alt236/bluetoothlelib/device/beacon/ibeacon/IBeaconUtilsTest.java
@@ -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));
diff --git a/sample_app/src/main/java/uk/co/alt236/btlescan/activities/DeviceDetailsActivity.java b/sample_app/src/main/java/uk/co/alt236/btlescan/activities/DeviceDetailsActivity.java
index bb6abdb..1e3e10f 100644
--- a/sample_app/src/main/java/uk/co/alt236/btlescan/activities/DeviceDetailsActivity.java
+++ b/sample_app/src/main/java/uk/co/alt236/btlescan/activities/DeviceDetailsActivity.java
@@ -21,11 +21,12 @@ import butterknife.ButterKnife;
import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice;
import uk.co.alt236.bluetoothlelib.device.BluetoothService;
import uk.co.alt236.bluetoothlelib.device.adrecord.AdRecord;
-import uk.co.alt236.bluetoothlelib.device.mfdata.IBeaconManufacturerData;
+import uk.co.alt236.bluetoothlelib.device.beacon.BeaconType;
+import uk.co.alt236.bluetoothlelib.device.beacon.BeaconUtils;
+import uk.co.alt236.bluetoothlelib.device.beacon.ibeacon.IBeaconManufacturerData;
import uk.co.alt236.bluetoothlelib.resolvers.CompanyIdentifierResolver;
import uk.co.alt236.bluetoothlelib.util.AdRecordUtils;
import uk.co.alt236.bluetoothlelib.util.ByteUtils;
-import uk.co.alt236.bluetoothlelib.util.IBeaconUtils;
import uk.co.alt236.btlescan.R;
import uk.co.alt236.btlescan.util.TimeFormatter;
@@ -218,7 +219,7 @@ public class DeviceDetailsActivity extends AppCompatActivity {
}
}
- final boolean isIBeacon = IBeaconUtils.isThisAnIBeacon(device);
+ final boolean isIBeacon = BeaconUtils.getBeaconType(device) == BeaconType.IBEACON;
if (isIBeacon) {
final IBeaconManufacturerData iBeaconData = new IBeaconManufacturerData(device);
appendHeader(adapter, getString(R.string.header_ibeacon_data));
diff --git a/sample_app/src/main/java/uk/co/alt236/btlescan/adapters/LeDeviceListAdapter.java b/sample_app/src/main/java/uk/co/alt236/btlescan/adapters/LeDeviceListAdapter.java
index f7e8bf3..97cbdbc 100644
--- a/sample_app/src/main/java/uk/co/alt236/btlescan/adapters/LeDeviceListAdapter.java
+++ b/sample_app/src/main/java/uk/co/alt236/btlescan/adapters/LeDeviceListAdapter.java
@@ -9,8 +9,9 @@ import android.widget.ImageView;
import android.widget.TextView;
import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice;
-import uk.co.alt236.bluetoothlelib.device.IBeaconDevice;
-import uk.co.alt236.bluetoothlelib.util.IBeaconUtils;
+import uk.co.alt236.bluetoothlelib.device.beacon.BeaconType;
+import uk.co.alt236.bluetoothlelib.device.beacon.BeaconUtils;
+import uk.co.alt236.bluetoothlelib.device.beacon.ibeacon.IBeaconDevice;
import uk.co.alt236.btlescan.R;
import uk.co.alt236.btlescan.util.Constants;
import uk.co.alt236.easycursor.objectcursor.EasyObjectCursor;
@@ -76,7 +77,7 @@ public class LeDeviceListAdapter extends SimpleCursorAdapter {
viewHolder.deviceName.setText(R.string.unknown_device);
}
- if (IBeaconUtils.isThisAnIBeacon(device)) {
+ if (BeaconUtils.getBeaconType(device) == BeaconType.IBEACON) {
final IBeaconDevice iBeacon = new IBeaconDevice(device);
final String accuracy = Constants.DOUBLE_TWO_DIGIT_ACCURACY.format(iBeacon.getAccuracy());
diff --git a/sample_app/src/main/java/uk/co/alt236/btlescan/containers/BluetoothLeDeviceStore.java b/sample_app/src/main/java/uk/co/alt236/btlescan/containers/BluetoothLeDeviceStore.java
index ec3b9c1..8b99033 100644
--- a/sample_app/src/main/java/uk/co/alt236/btlescan/containers/BluetoothLeDeviceStore.java
+++ b/sample_app/src/main/java/uk/co/alt236/btlescan/containers/BluetoothLeDeviceStore.java
@@ -16,9 +16,10 @@ import java.util.Locale;
import java.util.Map;
import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice;
-import uk.co.alt236.bluetoothlelib.device.IBeaconDevice;
+import uk.co.alt236.bluetoothlelib.device.beacon.BeaconType;
+import uk.co.alt236.bluetoothlelib.device.beacon.BeaconUtils;
+import uk.co.alt236.bluetoothlelib.device.beacon.ibeacon.IBeaconDevice;
import uk.co.alt236.bluetoothlelib.util.ByteUtils;
-import uk.co.alt236.bluetoothlelib.util.IBeaconUtils;
import uk.co.alt236.btlescan.R;
import uk.co.alt236.btlescan.util.CsvWriterHelper;
import uk.co.alt236.btlescan.util.TimeFormatter;
@@ -92,7 +93,7 @@ public class BluetoothLeDeviceStore {
sb.append(CsvWriterHelper.addStuff(TimeFormatter.getIsoDateTime(device.getTimestamp())));
sb.append(CsvWriterHelper.addStuff(device.getRssi()));
sb.append(CsvWriterHelper.addStuff(ByteUtils.byteArrayToHexString(device.getScanRecord())));
- final boolean isIBeacon = IBeaconUtils.isThisAnIBeacon(device);
+ final boolean isIBeacon = BeaconUtils.getBeaconType(device) == BeaconType.IBEACON;
final String uuid;
final String minor;
final String major;