More tests and general code cleanup
This commit is contained in:
+27
@@ -0,0 +1,27 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Run Android Tests" type="AndroidTestRunConfigurationType" factoryName="Android Tests">
|
||||
<module name="library" />
|
||||
<option name="TESTING_TYPE" value="0" />
|
||||
<option name="INSTRUMENTATION_RUNNER_CLASS" value="" />
|
||||
<option name="METHOD_NAME" value="" />
|
||||
<option name="CLASS_NAME" value="" />
|
||||
<option name="PACKAGE_NAME" value="" />
|
||||
<option name="TARGET_SELECTION_MODE" value="SHOW_DIALOG" />
|
||||
<option name="USE_LAST_SELECTED_DEVICE" value="true" />
|
||||
<option name="PREFERRED_AVD" value="" />
|
||||
<option name="USE_COMMAND_LINE" value="true" />
|
||||
<option name="COMMAND_LINE" value="" />
|
||||
<option name="WIPE_USER_DATA" value="false" />
|
||||
<option name="DISABLE_BOOT_ANIMATION" value="false" />
|
||||
<option name="NETWORK_SPEED" value="full" />
|
||||
<option name="NETWORK_LATENCY" value="none" />
|
||||
<option name="CLEAR_LOGCAT" value="false" />
|
||||
<option name="SHOW_LOGCAT_AUTOMATICALLY" value="true" />
|
||||
<option name="FILTER_LOGCAT_AUTOMATICALLY" value="true" />
|
||||
<option name="SELECTED_MATRIX_CONFIGURATION_ID" value="-1" />
|
||||
<option name="SELECTED_CLOUD_PROJECT_ID" value="Please select a project..." />
|
||||
<option name="IS_VALID_CLOUD_SELECTION" value="false" />
|
||||
<option name="INVALID_CLOUD_SELECTION_ERROR" value="Matrix configuration not specified" />
|
||||
<method />
|
||||
</configuration>
|
||||
</component>
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Run JUnit Tests" type="JUnit" factoryName="JUnit">
|
||||
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
|
||||
<module name="library" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
<option name="ALTERNATIVE_JRE_PATH" value="" />
|
||||
<option name="PACKAGE_NAME" value="uk.co.alt236.bluetoothlelib" />
|
||||
<option name="MAIN_CLASS_NAME" value="" />
|
||||
<option name="METHOD_NAME" value="" />
|
||||
<option name="TEST_OBJECT" value="package" />
|
||||
<option name="VM_PARAMETERS" value="-ea" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
|
||||
<option name="ENV_VARIABLES" />
|
||||
<option name="PASS_PARENT_ENVS" value="true" />
|
||||
<option name="TEST_SEARCH_SCOPE">
|
||||
<value defaultName="moduleWithDependencies" />
|
||||
</option>
|
||||
<envs />
|
||||
<patterns />
|
||||
<method />
|
||||
</configuration>
|
||||
</component>
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Run Sample App" type="AndroidRunConfigurationType" factoryName="Android Application">
|
||||
<module name="sample_app" />
|
||||
<option name="ACTIVITY_CLASS" value="" />
|
||||
<option name="MODE" value="default_activity" />
|
||||
<option name="DEPLOY" value="true" />
|
||||
<option name="ARTIFACT_NAME" value="" />
|
||||
<option name="TARGET_SELECTION_MODE" value="SHOW_DIALOG" />
|
||||
<option name="USE_LAST_SELECTED_DEVICE" value="true" />
|
||||
<option name="PREFERRED_AVD" value="" />
|
||||
<option name="USE_COMMAND_LINE" value="true" />
|
||||
<option name="COMMAND_LINE" value="" />
|
||||
<option name="WIPE_USER_DATA" value="false" />
|
||||
<option name="DISABLE_BOOT_ANIMATION" value="false" />
|
||||
<option name="NETWORK_SPEED" value="full" />
|
||||
<option name="NETWORK_LATENCY" value="none" />
|
||||
<option name="CLEAR_LOGCAT" value="false" />
|
||||
<option name="SHOW_LOGCAT_AUTOMATICALLY" value="true" />
|
||||
<option name="FILTER_LOGCAT_AUTOMATICALLY" value="true" />
|
||||
<option name="SELECTED_MATRIX_CONFIGURATION_ID" value="-1" />
|
||||
<option name="SELECTED_CLOUD_PROJECT_ID" value="Please select a project..." />
|
||||
<option name="IS_VALID_CLOUD_SELECTION" value="false" />
|
||||
<option name="INVALID_CLOUD_SELECTION_ERROR" value="Matrix configuration not specified" />
|
||||
<method />
|
||||
</configuration>
|
||||
</component>
|
||||
+20
-32
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
* <p/>
|
||||
|
||||
@@ -13,7 +13,7 @@ public class IBeaconUtils {
|
||||
/**
|
||||
* Calculates the accuracy of an RSSI reading.
|
||||
* <p/>
|
||||
* The code was taken from {@linktourl http://stackoverflow.com/questions/20416218/understanding-ibeacon-distancing}
|
||||
* The code was taken from <a href="http://stackoverflow.com/questions/20416218/understanding-ibeacon-distancing" /a>
|
||||
*
|
||||
* @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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<AdRecord> 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<Integer, AdRecord> 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<AdRecord> 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());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user