Working on exposing the iBeacon Manufacturer specific data

This commit is contained in:
Alexandros Schillings
2014-03-11 11:29:08 +00:00
parent 851c0ccf72
commit 39d7b9a882
4 changed files with 147 additions and 34 deletions
@@ -5,8 +5,10 @@ import java.util.Collection;
import uk.co.alt236.btlescan.R; import uk.co.alt236.btlescan.R;
import uk.co.alt236.btlescan.containers.AdRecord; import uk.co.alt236.btlescan.containers.AdRecord;
import uk.co.alt236.btlescan.containers.BluetoothLeDevice; import uk.co.alt236.btlescan.containers.BluetoothLeDevice;
import uk.co.alt236.btlescan.containers.ManufacturerDataIBeacon;
import uk.co.alt236.btlescan.util.AdRecordUtils; import uk.co.alt236.btlescan.util.AdRecordUtils;
import uk.co.alt236.btlescan.util.ByteUtils; import uk.co.alt236.btlescan.util.ByteUtils;
import uk.co.alt236.btlescan.util.IBeaconUtils;
import android.app.Activity; import android.app.Activity;
import android.os.Bundle; import android.os.Bundle;
import android.widget.TextView; import android.widget.TextView;
@@ -61,11 +63,38 @@ public class DetailsActivity extends Activity{
append(sb, AdRecordUtils.getRecordDataAsString(record), null); append(sb, AdRecordUtils.getRecordDataAsString(record), null);
append(sb, "", null); append(sb, "", null);
} }
append(sb, "Additional", null);
append(sb, "-----------------", null);
final boolean isIBeacon = IBeaconUtils.isThisAnIBeacon(device);
append(sb, "Is iBeacon", isIBeacon);
if(isIBeacon){
final ManufacturerDataIBeacon iBeaconData = new ManufacturerDataIBeacon(device);
append(sb, "Company ID", iBeaconData.getCompanyIdentifier());
append(sb, "iBeacon Advertisment", iBeaconData.getIBeaconAdvertisement());
append(sb, "UUID", iBeaconData.getUUID());
append(sb, "Major", iBeaconData.getMajor());
append(sb, "Minor", iBeaconData.getMinor());
append(sb, "TX Power", iBeaconData.getCalibratedTxPower());
}
} }
mTvDetails.setText(sb.toString()); mTvDetails.setText(sb.toString());
} }
private void append(StringBuilder sb, String label, boolean value) {
append(sb, label, String.valueOf(value));
}
private void append(StringBuilder sb, String label, int value) {
append(sb, label, String.valueOf(value));
}
private void append(StringBuilder sb, String label, long value) {
append(sb, label, String.valueOf(value));
}
private static void append(StringBuilder sb, byte[] value){ private static void append(StringBuilder sb, byte[] value){
append(sb, ByteUtils.byteArrayToHexString(value), null); append(sb, ByteUtils.byteArrayToHexString(value), null);
} }
@@ -1,41 +1,88 @@
package uk.co.alt236.btlescan.containers; package uk.co.alt236.btlescan.containers;
import java.util.Arrays;
import uk.co.alt236.btlescan.util.ByteUtils;
public final class ManufacturerDataIBeacon { public final class ManufacturerDataIBeacon {
// 0 FF # Manufacturer specific data AD type // 0 4C # Byte 1 (LSB) of Company identifier code
// 1 4C # Byte 1 of Company identifier code // 1 00 # Byte 0 (MSB) of Company identifier code (0x004C == Apple)
// 2 00 # Byte 0 of Company identifier code (0x004C == Apple) // 2 02 # Byte 0 of iBeacon advertisement indicator
// 3 02 # Byte 0 of iBeacon advertisement indicator // 3 15 # Byte 1 of iBeacon advertisement indicator
// 4 15 # Byte 1 of iBeacon advertisement indicator // 4 e2 |\
// 5 e2 # // 5 c5 |\\
// 6 c5 ## // 6 6d |#\\
// 7 6d ### // 7 b5 |##\\
// 8 b5 #### // 8 df |###\\
// 9 df ##### // 9 fb |####\\
// 10 fb ###### // 10 48 |#####\\
// 11 48 ####### // 11 d2 |#####|| iBeacon proximity UUID
// 12 d2 ######## iBeacon proximity uuid // 12 b0 |#####||
// 13 b0 ######## // 13 60 |#####//
// 14 60 ####### // 14 d0 |####//
// 15 d0 ###### // 15 f5 |###//
// 16 f5 ##### // 16 a7 |##//
// 17 a7 #### // 17 10 |#//
// 18 10 ### // 18 96 |//
// 19 96 ## // 19 e0 |/
// 20 e0 # // 20 00 # major
// 21 00 // 21 00
// 22 00 # major // 22 00# minor
// 23 00 // 23 00
// 24 00 # minor // 24 c5 # The 2's complement of the calibrated Tx Power
// 25 c5 # The 2's complement of the calibrated Tx Power
private final byte[] mData; private final byte[] mData;
private final int mTxPower; private final int mCalibratedTxPower;
private final int mCompanyIdentidier;
private final int mIBeaconAdvertisment;
private final int mMajor;
private final int mMinor;
private final long mUUID;
public ManufacturerDataIBeacon(BluetoothLeDevice device){
this(device.getAdRecordStore().getRecord(AdRecord.TYPE_MANUFACTURER_SPECIFIC_DATA).getData());
}
public ManufacturerDataIBeacon(byte[] data){ public ManufacturerDataIBeacon(byte[] data){
mData = data; mData = data;
mTxPower = 0; mCompanyIdentidier = convert2ByteArrayToInt(Arrays.copyOfRange(mData, 0, 2));
mIBeaconAdvertisment = convert2ByteArrayToInt(Arrays.copyOfRange(mData, 2, 2));
mUUID = ByteUtils.getLongFromByteArray(Arrays.copyOfRange(mData, 4, 16));
mMajor = convert2ByteArrayToInt(Arrays.copyOfRange(mData, 20, 2));
mMinor = convert2ByteArrayToInt(Arrays.copyOfRange(mData, 22, 2));
mCalibratedTxPower = ByteUtils.getIntFromByte(data[24]);
} }
private static int convert2ByteArrayToInt(byte[] array){
final byte[] result = new byte[4];
result[2] = array[0];
result[3] = array[1];
return ByteUtils.getIntFromByteArray(result);
}
public int getCalibratedTxPower(){
return mCalibratedTxPower;
}
public int getCompanyIdentifier(){
return mCompanyIdentidier;
}
public int getIBeaconAdvertisement(){
return mIBeaconAdvertisment;
}
public int getMajor(){
return mMajor;
}
public int getMinor(){
return mMinor;
}
public long getUUID(){
return mUUID;
}
// Code taken from: http://stackoverflow.com/questions/20416218/understanding-ibeacon-distancing // Code taken from: http://stackoverflow.com/questions/20416218/understanding-ibeacon-distancing
protected static double calculateAccuracy(int txPower, double rssi) { protected static double calculateAccuracy(int txPower, double rssi) {
@@ -48,7 +95,7 @@ public final class ManufacturerDataIBeacon {
return Math.pow(ratio,10); return Math.pow(ratio,10);
} }
else { else {
double accuracy = (0.89976)*Math.pow(ratio,7.7095) + 0.111; final double accuracy = (0.89976)*Math.pow(ratio,7.7095) + 0.111;
return accuracy; return accuracy;
} }
} }
@@ -51,7 +51,7 @@ public class AdRecordUtils {
//Done once we run out of records //Done once we run out of records
if (length == 0) break; if (length == 0) break;
final int type = ByteUtils.convertByteToInt(scanRecord[index]); final int type = ByteUtils.getIntFromByte(scanRecord[index]);
//Done if our record isn't a valid type //Done if our record isn't a valid type
if (type == 0) break; if (type == 0) break;
@@ -77,7 +77,7 @@ public class AdRecordUtils {
//Done once we run out of records //Done once we run out of records
if (length == 0) break; if (length == 0) break;
final int type = ByteUtils.convertByteToInt(scanRecord[index]); final int type = ByteUtils.getIntFromByte(scanRecord[index]);
//Done if our record isn't a valid type //Done if our record isn't a valid type
if (type == 0) break; if (type == 0) break;
@@ -102,7 +102,7 @@ public class AdRecordUtils {
//Done once we run out of records //Done once we run out of records
if (length == 0) break; if (length == 0) break;
final int type = ByteUtils.convertByteToInt(scanRecord[index]); final int type = ByteUtils.getIntFromByte(scanRecord[index]);
//Done if our record isn't a valid type //Done if our record isn't a valid type
if (type == 0) break; if (type == 0) break;
+41 -4
View File
@@ -1,8 +1,18 @@
package uk.co.alt236.btlescan.util; package uk.co.alt236.btlescan.util;
public class ByteUtils { import java.nio.ByteBuffer;
static final String HEXES = "0123456789ABCDEF";
public class ByteUtils {
private static final String HEXES = "0123456789ABCDEF";
/**
* Gets a pretty representation of a Byte Array as a HEX String.
*
* Sample output: [01, 30, FF, AA]
*
* @param array the array
* @return the string
*/
public static String byteArrayToHexString(final byte[] array){ public static String byteArrayToHexString(final byte[] array){
final StringBuffer sb = new StringBuffer(); final StringBuffer sb = new StringBuffer();
boolean firstEntry = true; boolean firstEntry = true;
@@ -21,8 +31,35 @@ public class ByteUtils {
return sb.toString(); return sb.toString();
} }
/**
public static int convertByteToInt(byte bite){ * Converts a byte to an int, preserving the sign.
*
* For example, FF will be converted to 255 and not -1.
*
* @param bite the bite
* @return the int from byte
*/
public static int getIntFromByte(final byte bite){
return Integer.valueOf(bite & 0xFF); return Integer.valueOf(bite & 0xFF);
} }
/**
* Converts a byte array to an integer;
*
* @param bytes the bytes
* @return the int from byte array
*/
public static int getIntFromByteArray(final byte[] bytes) {
return ByteBuffer.wrap(bytes).getInt();
}
/**
* Converts a byte array to a long;
*
* @param bytes the bytes
* @return the long from byte array
*/
public static long getLongFromByteArray(final byte[] bytes) {
return ByteBuffer.wrap(bytes).getLong();
}
} }