Full code reformat

This commit is contained in:
Alexandros Schillings
2015-07-03 14:52:14 +01:00
parent 5f55a3ea45
commit 53138d5462
42 changed files with 3637 additions and 3625 deletions
+2 -1
View File
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest
package="uk.co.alt236.bluetoothlelib" package="uk.co.alt236.bluetoothlelib"
xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="2" android:versionCode="2"
android:versionName="0.0.2"> android:versionName="0.0.2">
@@ -1,5 +1,10 @@
package uk.co.alt236.bluetoothlelib.device; package uk.co.alt236.bluetoothlelib.device;
import android.bluetooth.BluetoothDevice;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import java.io.Serializable; import java.io.Serializable;
import java.util.Arrays; import java.util.Arrays;
import java.util.Iterator; import java.util.Iterator;
@@ -10,12 +15,9 @@ import uk.co.alt236.bluetoothlelib.resolvers.BluetoothClassResolver;
import uk.co.alt236.bluetoothlelib.util.AdRecordUtils; import uk.co.alt236.bluetoothlelib.util.AdRecordUtils;
import uk.co.alt236.bluetoothlelib.util.ByteUtils; import uk.co.alt236.bluetoothlelib.util.ByteUtils;
import uk.co.alt236.bluetoothlelib.util.LimitedLinkHashMap; import uk.co.alt236.bluetoothlelib.util.LimitedLinkHashMap;
import android.bluetooth.BluetoothDevice;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
// TODO: Auto-generated Javadoc // TODO: Auto-generated Javadoc
/** /**
* This is a wrapper around the default BluetoothDevice object * This is a wrapper around the default BluetoothDevice object
* As BluetoothDevice is final it cannot be extended, so to get it you * As BluetoothDevice is final it cannot be extended, so to get it you
@@ -24,28 +26,9 @@ import android.os.Parcelable;
* @author Alexandros Schillings * @author Alexandros Schillings
*/ */
public class BluetoothLeDevice implements Parcelable { public class BluetoothLeDevice implements Parcelable {
private static final String PARCEL_EXTRA_BLUETOOTH_DEVICE = "bluetooth_device"; /**
private static final String PARCEL_EXTRA_CURRENT_RSSI = "current_rssi"; * The Constant CREATOR.
private static final String PARCEL_EXTRA_CURRENT_TIMESTAMP = "current_timestamp"; */
private static final String PARCEL_EXTRA_DEVICE_RSSI_LOG = "device_rssi_log";
private static final String PARCEL_EXTRA_DEVICE_SCANRECORD = "device_scanrecord";
private static final String PARCEL_EXTRA_DEVICE_SCANRECORD_STORE = "device_scanrecord_store";
private static final String PARCEL_EXTRA_FIRST_RSSI = "device_first_rssi";
private static final String PARCEL_EXTRA_FIRST_TIMESTAMP = "first_timestamp";
private static final long LOG_INVALIDATION_THRESHOLD = 10 * 1000;
protected static final int MAX_RSSI_LOG_SIZE = 10;
private final AdRecordStore mRecordStore;
private final BluetoothDevice mDevice;
private final Map<Long, Integer> mRssiLog;
private final byte[] mScanRecord;
private final int mFirstRssi;
private final long mFirstTimestamp;
private int mCurrentRssi;
private long mCurrentTimestamp;
/** The Constant CREATOR. */
public static final Parcelable.Creator<BluetoothLeDevice> CREATOR = new Parcelable.Creator<BluetoothLeDevice>() { public static final Parcelable.Creator<BluetoothLeDevice> CREATOR = new Parcelable.Creator<BluetoothLeDevice>() {
public BluetoothLeDevice createFromParcel(final Parcel in) { public BluetoothLeDevice createFromParcel(final Parcel in) {
return new BluetoothLeDevice(in); return new BluetoothLeDevice(in);
@@ -55,6 +38,24 @@ public class BluetoothLeDevice implements Parcelable{
return new BluetoothLeDevice[size]; return new BluetoothLeDevice[size];
} }
}; };
protected static final int MAX_RSSI_LOG_SIZE = 10;
private static final String PARCEL_EXTRA_BLUETOOTH_DEVICE = "bluetooth_device";
private static final String PARCEL_EXTRA_CURRENT_RSSI = "current_rssi";
private static final String PARCEL_EXTRA_CURRENT_TIMESTAMP = "current_timestamp";
private static final String PARCEL_EXTRA_DEVICE_RSSI_LOG = "device_rssi_log";
private static final String PARCEL_EXTRA_DEVICE_SCANRECORD = "device_scanrecord";
private static final String PARCEL_EXTRA_DEVICE_SCANRECORD_STORE = "device_scanrecord_store";
private static final String PARCEL_EXTRA_FIRST_RSSI = "device_first_rssi";
private static final String PARCEL_EXTRA_FIRST_TIMESTAMP = "first_timestamp";
private static final long LOG_INVALIDATION_THRESHOLD = 10 * 1000;
private final AdRecordStore mRecordStore;
private final BluetoothDevice mDevice;
private final Map<Long, Integer> mRssiLog;
private final byte[] mScanRecord;
private final int mFirstRssi;
private final long mFirstTimestamp;
private int mCurrentRssi;
private long mCurrentTimestamp;
/** /**
* Instantiates a new Bluetooth LE device. * Instantiates a new Bluetooth LE device.
@@ -176,15 +177,6 @@ public class BluetoothLeDevice implements Parcelable{
return true; return true;
} }
/**
* Gets the address.
*
* @return the address
*/
public String getAddress(){
return mDevice.getAddress();
}
/** /**
* Gets the ad record store. * Gets the ad record store.
* *
@@ -194,6 +186,15 @@ public class BluetoothLeDevice implements Parcelable{
return mRecordStore; return mRecordStore;
} }
/**
* Gets the address.
*
* @return the address
*/
public String getAddress() {
return mDevice.getAddress();
}
/** /**
* Gets the bluetooth device bond state. * Gets the bluetooth device bond state.
* *
@@ -1,14 +1,17 @@
package uk.co.alt236.bluetoothlelib.device; package uk.co.alt236.bluetoothlelib.device;
import uk.co.alt236.bluetoothlelib.device.mfdata.IBeaconManufacturerData;
import uk.co.alt236.bluetoothlelib.util.IBeaconUtils;
import uk.co.alt236.bluetoothlelib.util.IBeaconUtils.IBeaconDistanceDescriptor;
import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice;
import android.os.Parcel; 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;
public class IBeaconDevice extends BluetoothLeDevice { public class IBeaconDevice extends BluetoothLeDevice {
/** The m iBeacon data. */ /**
* The m iBeacon data.
*/
private final IBeaconManufacturerData mIBeaconData; private final IBeaconManufacturerData mIBeaconData;
/** /**
@@ -1,14 +1,15 @@
package uk.co.alt236.bluetoothlelib.device.adrecord; package uk.co.alt236.bluetoothlelib.device.adrecord;
import java.util.Arrays;
import android.os.Bundle; import android.os.Bundle;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import java.util.Arrays;
/** /**
* Created by Dave Smith * Created by Dave Smith
* Double Encore, Inc. * Double Encore, Inc.
* * <p/>
* Expanded by Alexandros Schillings * Expanded by Alexandros Schillings
*/ */
public final class AdRecord implements Parcelable { public final class AdRecord implements Parcelable {
@@ -31,15 +32,11 @@ public final class AdRecord implements Parcelable{
// c5 # The 2's complement of the calibrated Tx Power // c5 # The 2's complement of the calibrated Tx Power
private static final String PARCEL_RECORD_DATA = "record_data";
private static final String PARCEL_RECORD_TYPE = "record_type";
private static final String PARCEL_RECORD_LENGTH = "record_length";
/** /**
* General FLAGS * General FLAGS
* * <p/>
* Description: Flags * Description: Flags
* * <p/>
* Information: * Information:
* Bit 0: LE Limited Discoverable Mode * Bit 0: LE Limited Discoverable Mode
* Bit 1: LE General Discoverable Mode * Bit 1: LE General Discoverable Mode
@@ -49,7 +46,6 @@ public final class AdRecord implements Parcelable{
* Bits 5-7 Reserved * Bits 5-7 Reserved
*/ */
public static final int TYPE_FLAGS = 0x01; public static final int TYPE_FLAGS = 0x01;
// SERVICE // SERVICE
public static final int TYPE_UUID16_INC = 0x02; public static final int TYPE_UUID16_INC = 0x02;
public static final int TYPE_UUID16 = 0x03; public static final int TYPE_UUID16 = 0x03;
@@ -57,23 +53,17 @@ public final class AdRecord implements Parcelable{
public static final int TYPE_UUID32 = 0x05; public static final int TYPE_UUID32 = 0x05;
public static final int TYPE_UUID128_INC = 0x06; public static final int TYPE_UUID128_INC = 0x06;
public static final int TYPE_UUID128 = 0x07; public static final int TYPE_UUID128 = 0x07;
// Local name // Local name
public static final int TYPE_LOCAL_NAME_SHORT = 0x08; public static final int TYPE_LOCAL_NAME_SHORT = 0x08;
public static final int TYPE_LOCAL_NAME_COMPLETE = 0x09; public static final int TYPE_LOCAL_NAME_COMPLETE = 0x09;
// TX Power Level // TX Power Level
public static final int TYPE_TX_POWER_LEVEL = 0x0A; public static final int TYPE_TX_POWER_LEVEL = 0x0A;
// SIMPLE PAIRING OPTIONAL OOB TAGS // SIMPLE PAIRING OPTIONAL OOB TAGS
public static final int TYPE_DEVICE_CLASS = 0x0D; public static final int TYPE_DEVICE_CLASS = 0x0D;
public static final int TYPE_SIMPLE_PAIRING_HASH_C = 0x0E; public static final int TYPE_SIMPLE_PAIRING_HASH_C = 0x0E;
public static final int TYPE_SIMPLE_PAIRING_RANDOMIZER_R = 0x0F; public static final int TYPE_SIMPLE_PAIRING_RANDOMIZER_R = 0x0F;
// SECURITY MANAGER TK VALUE // SECURITY MANAGER TK VALUE
public static final int TYPE_TK_VALUE = 0x10; public static final int TYPE_TK_VALUE = 0x10;
/* SECURITY MANAGER OOB FLAGS /* SECURITY MANAGER OOB FLAGS
* *
* Description: Flag (1 octet) * Description: Flag (1 octet)
@@ -86,8 +76,6 @@ public final class AdRecord implements Parcelable{
* Bits 4-7 Reserved * Bits 4-7 Reserved
*/ */
public static final int TYPE_SECURITY_MANAGER_OOB_FLAGS = 0x11; public static final int TYPE_SECURITY_MANAGER_OOB_FLAGS = 0x11;
/* SLAVE CONNECTION INTERVAL RANGE /* SLAVE CONNECTION INTERVAL RANGE
* *
* Description: Slave Connection Interval Range * Description: Slave Connection Interval Range
@@ -108,32 +96,21 @@ public final class AdRecord implements Parcelable{
* Values outside the range are reserved (excluding 0xFFFF) * Values outside the range are reserved (excluding 0xFFFF)
*/ */
public static final int TYPE_CONNECTION_INTERVAL_RANGE = 0x12; public static final int TYPE_CONNECTION_INTERVAL_RANGE = 0x12;
// SERVICE SOLICITATION // SERVICE SOLICITATION
public static final int TYPE_SERVICE_UUIDS_LIST_16BIT = 0x14; public static final int TYPE_SERVICE_UUIDS_LIST_16BIT = 0x14;
public static final int TYPE_SERVICE_UUIDS_LIST_128BIT = 0x15; public static final int TYPE_SERVICE_UUIDS_LIST_128BIT = 0x15;
/* SERVICE DATA /* SERVICE DATA
* *
* Description: Service Data (2 or more octets) * Description: Service Data (2 or more octets)
* Information: The first 2 octets contain the 16 bit Service UUID followed by additional service data * Information: The first 2 octets contain the 16 bit Service UUID followed by additional service data
*/ */
public static final int TYPE_SERVICE_DATA = 0x16; public static final int TYPE_SERVICE_DATA = 0x16;
/* MANUFACTURER SPECIFIC DATA /* MANUFACTURER SPECIFIC DATA
* *
* Description: Manufacturer Specific Data (2 or more octets) * Description: Manufacturer Specific Data (2 or more octets)
* Information: The first 2 octets contain the Company Identifier Code followed by additional manufacturer specific data * Information: The first 2 octets contain the Company Identifier Code followed by additional manufacturer specific data
*/ */
public static final int TYPE_MANUFACTURER_SPECIFIC_DATA = 0xFF; public static final int TYPE_MANUFACTURER_SPECIFIC_DATA = 0xFF;
/* Model Object Definition */
private final int mLength;
private final int mType;
private final byte[] mData;
public static final Parcelable.Creator<AdRecord> CREATOR = new Parcelable.Creator<AdRecord>() { public static final Parcelable.Creator<AdRecord> CREATOR = new Parcelable.Creator<AdRecord>() {
public AdRecord createFromParcel(final Parcel in) { public AdRecord createFromParcel(final Parcel in) {
return new AdRecord(in); return new AdRecord(in);
@@ -143,6 +120,13 @@ public final class AdRecord implements Parcelable{
return new AdRecord[size]; return new AdRecord[size];
} }
}; };
private static final String PARCEL_RECORD_DATA = "record_data";
private static final String PARCEL_RECORD_TYPE = "record_type";
private static final String PARCEL_RECORD_LENGTH = "record_length";
/* Model Object Definition */
private final int mLength;
private final int mType;
private final byte[] mData;
public AdRecord(final int length, final int type, final byte[] data) { public AdRecord(final int length, final int type, final byte[] data) {
mLength = length; mLength = length;
@@ -1,23 +1,20 @@
package uk.co.alt236.bluetoothlelib.device.adrecord; package uk.co.alt236.bluetoothlelib.device.adrecord;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.SparseArray;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import uk.co.alt236.bluetoothlelib.util.AdRecordUtils; import uk.co.alt236.bluetoothlelib.util.AdRecordUtils;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.SparseArray;
/** /**
* The Class AdRecordStore. * The Class AdRecordStore.
*/ */
public class AdRecordStore implements Parcelable { public class AdRecordStore implements Parcelable {
private final SparseArray<AdRecord> mAdRecords;
private final String mLocalNameComplete;
private final String mLocalNameShort;
public static final Parcelable.Creator<AdRecordStore> CREATOR = new Parcelable.Creator<AdRecordStore>() { public static final Parcelable.Creator<AdRecordStore> CREATOR = new Parcelable.Creator<AdRecordStore>() {
public AdRecordStore createFromParcel(final Parcel in) { public AdRecordStore createFromParcel(final Parcel in) {
return new AdRecordStore(in); return new AdRecordStore(in);
@@ -27,6 +24,9 @@ public class AdRecordStore implements Parcelable{
return new AdRecordStore[size]; return new AdRecordStore[size];
} }
}; };
private final SparseArray<AdRecord> mAdRecords;
private final String mLocalNameComplete;
private final String mLocalNameShort;
public AdRecordStore(final Parcel in) { public AdRecordStore(final Parcel in) {
final Bundle b = in.readBundle(getClass().getClassLoader()); final Bundle b = in.readBundle(getClass().getClassLoader());
@@ -8,9 +8,9 @@ import uk.co.alt236.bluetoothlelib.util.ByteUtils;
/** /**
* Parses the Manufactured Data field of an iBeacon * Parses the Manufactured Data field of an iBeacon
* * <p/>
* The parsing is based on the following schema: * The parsing is based on the following schema:
* * <p/>
* <p> * <p>
* 0 4C - Byte 1 (LSB) of Company identifier code * 0 4C - Byte 1 (LSB) of Company identifier code
* 1 00 - Byte 0 (MSB) of Company identifier code (0x004C == Apple) * 1 00 - Byte 0 (MSB) of Company identifier code (0x004C == Apple)
@@ -37,11 +37,10 @@ import uk.co.alt236.bluetoothlelib.util.ByteUtils;
* 22 00 - minor * 22 00 - minor
* 23 00 * 23 00
* 24 c5 - The 2's complement of the calibrated Tx Power * 24 c5 - The 2's complement of the calibrated Tx Power
* * <p/>
* </p> * </p>
* *
* @author Alexandros Schillings * @author Alexandros Schillings
*
*/ */
public final class IBeaconManufacturerData { public final class IBeaconManufacturerData {
@@ -59,7 +58,7 @@ public final class IBeaconManufacturerData {
/** /**
* Instantiates a new iBeacon manufacturer data object. * Instantiates a new iBeacon manufacturer data object.
*
* @param data the {@link uk.co.alt236.bluetoothlelib.device.adrecord.AdRecord#TYPE_MANUFACTURER_SPECIFIC_DATA} data array * @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 * @throws IndexOutOfBoundsException if the data array is shorter than expected
*/ */
@@ -129,10 +128,18 @@ public final class IBeaconManufacturerData {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
for (int i = 0; i < uuid.length; i++) { for (int i = 0; i < uuid.length; i++) {
if(i == 4){sb.append('-');} if (i == 4) {
if(i == 6){sb.append('-');} sb.append('-');
if(i == 8){sb.append('-');} }
if(i == 10){sb.append('-');} if (i == 6) {
sb.append('-');
}
if (i == 8) {
sb.append('-');
}
if (i == 10) {
sb.append('-');
}
sb.append( sb.append(
Integer.toHexString(ByteUtils.getIntFromByte(uuid[i]))); Integer.toHexString(ByteUtils.getIntFromByte(uuid[i])));
@@ -5,14 +5,12 @@ import java.util.Locale;
import java.util.Map; import java.util.Map;
/** /**
*
* The UUIDS have been collected from the following sources: * The UUIDS have been collected from the following sources:
* * <p/>
* - http://developer.nokia.com/community/wiki/Bluetooth_Services_for_Windows_Phone * - http://developer.nokia.com/community/wiki/Bluetooth_Services_for_Windows_Phone
* - The Bluez project * - The Bluez project
* *
* @author Alexandros Schillings * @author Alexandros Schillings
*
*/ */
public class GattAttributeResolver { public class GattAttributeResolver {
public static final String BASE_GUID = "00000001-0000-1000-8000-00805f9b34fb"; public static final String BASE_GUID = "00000001-0000-1000-8000-00805f9b34fb";
@@ -192,7 +190,6 @@ public class GattAttributeResolver {
public static final String ESTIMOTE_ADVERTISING_VECTOR = "b9402002-f5f8-466e-aff9-25556b57fe6d"; public static final String ESTIMOTE_ADVERTISING_VECTOR = "b9402002-f5f8-466e-aff9-25556b57fe6d";
private final static Map<String, String> sGattAttributesMap = populateGattAttributesMap(); private final static Map<String, String> sGattAttributesMap = populateGattAttributesMap();
public static String getAttributeName(final String uuid, final String fallback) { public static String getAttributeName(final String uuid, final String fallback) {
@@ -380,7 +377,6 @@ public class GattAttributeResolver {
map.put(ESTIMOTE_ADVERTISING_VECTOR, "Estimote Advertising Vector"); map.put(ESTIMOTE_ADVERTISING_VECTOR, "Estimote Advertising Vector");
return map; return map;
} }
} }
@@ -1,5 +1,8 @@
package uk.co.alt236.bluetoothlelib.util; package uk.co.alt236.bluetoothlelib.util;
import android.annotation.SuppressLint;
import android.util.SparseArray;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@@ -8,18 +11,20 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import uk.co.alt236.bluetoothlelib.device.adrecord.AdRecord; import uk.co.alt236.bluetoothlelib.device.adrecord.AdRecord;
import android.annotation.SuppressLint;
import android.util.SparseArray;
public class AdRecordUtils { public class AdRecordUtils {
public static String getRecordDataAsString(final AdRecord nameRecord) { public static String getRecordDataAsString(final AdRecord nameRecord) {
if(nameRecord == null){return "";} if (nameRecord == null) {
return "";
}
return new String(nameRecord.getData()); return new String(nameRecord.getData());
} }
public static byte[] getServiceData(final AdRecord serviceData) { public static byte[] getServiceData(final AdRecord serviceData) {
if (serviceData == null) {return null;} if (serviceData == null) {
return null;
}
if (serviceData.getType() != AdRecord.TYPE_SERVICE_DATA) return null; if (serviceData.getType() != AdRecord.TYPE_SERVICE_DATA) return null;
final byte[] raw = serviceData.getData(); final byte[] raw = serviceData.getData();
@@ -28,7 +33,9 @@ public class AdRecordUtils {
} }
public static int getServiceDataUuid(final AdRecord serviceData) { public static int getServiceDataUuid(final AdRecord serviceData) {
if (serviceData == null) {return -1;} if (serviceData == null) {
return -1;
}
if (serviceData.getType() != AdRecord.TYPE_SERVICE_DATA) return -1; if (serviceData.getType() != AdRecord.TYPE_SERVICE_DATA) return -1;
final byte[] raw = serviceData.getData(); final byte[] raw = serviceData.getData();
@@ -4,12 +4,14 @@ import java.nio.ByteBuffer;
public class ByteUtils { public class ByteUtils {
/** The Constant HEXES. */ /**
* The Constant HEXES.
*/
private static final String HEXES = "0123456789ABCDEF"; private static final String HEXES = "0123456789ABCDEF";
/** /**
* Gets a pretty representation of a Byte Array as a HEX String. * Gets a pretty representation of a Byte Array as a HEX String.
* * <p/>
* Sample output: [01, 30, FF, AA] * Sample output: [01, 30, FF, AA]
* *
* @param array the array * @param array the array
@@ -41,7 +43,9 @@ public class ByteUtils {
* @return true, if successful * @return true, if successful
*/ */
public static boolean doesArrayBeginWith(final byte[] array, final byte[] prefix) { public static boolean doesArrayBeginWith(final byte[] array, final byte[] prefix) {
if(array.length < prefix.length){return false;} if (array.length < prefix.length) {
return false;
}
for (int i = 0; i < prefix.length; i++) { for (int i = 0; i < prefix.length; i++) {
if (array[i] != prefix[i]) { if (array[i] != prefix[i]) {
@@ -71,7 +75,7 @@ public class ByteUtils {
/** /**
* Converts a byte to an int, preserving the sign. * Converts a byte to an int, preserving the sign.
* * <p/>
* For example, FF will be converted to 255 and not -1. * For example, FF will be converted to 255 and not -1.
* *
* @param bite the bite * @param bite the bite
@@ -112,8 +116,7 @@ public class ByteUtils {
final int size = array.length; final int size = array.length;
byte temp; byte temp;
for (int i = 0; i < size/2; i++) for (int i = 0; i < size / 2; i++) {
{
temp = array[i]; temp = array[i];
array[i] = array[size - 1 - i]; array[i] = array[size - 1 - i];
array[size - 1 - i] = temp; array[size - 1 - i] = temp;
@@ -0,0 +1,8 @@
package uk.co.alt236.bluetoothlelib.util;
public enum IBeaconDistanceDescriptor {
IMMEDIATE,
NEAR,
FAR,
UNKNOWN,
}
@@ -10,6 +10,29 @@ public class IBeaconUtils {
private static final byte[] MANUFACTURER_DATA_IBEACON_PREFIX = new byte[]{0x4C, 0x00, 0x02, 0x15}; private static final byte[] MANUFACTURER_DATA_IBEACON_PREFIX = new byte[]{0x4C, 0x00, 0x02, 0x15};
/**
* Calculates the accuracy of an RSSI reading.
* <p/>
* The code was taken from {@linktourl http://stackoverflow.com/questions/20416218/understanding-ibeacon-distancing}
*
* @param txPower the calibrated TX power of an iBeacon
* @param rssi the RSSI value of the iBeacon
* @return the calculated Accuracy
*/
public static double calculateAccuracy(final int txPower, final double rssi) {
if (rssi == 0) {
return -1.0; // if we cannot determine accuracy, return -1.
}
final double ratio = rssi * 1.0 / txPower;
if (ratio < 1.0) {
return Math.pow(ratio, 10);
} else {
final double accuracy = (0.89976) * Math.pow(ratio, 7.7095) + 0.111;
return accuracy;
}
}
public static IBeaconDistanceDescriptor getDistanceDescriptor(final double accuracy) { public static IBeaconDistanceDescriptor getDistanceDescriptor(final double accuracy) {
if (accuracy < DISTANCE_THRESHOLD_WTF) { if (accuracy < DISTANCE_THRESHOLD_WTF) {
return IBeaconDistanceDescriptor.UNKNOWN; return IBeaconDistanceDescriptor.UNKNOWN;
@@ -26,30 +49,6 @@ public class IBeaconUtils {
return IBeaconDistanceDescriptor.FAR; return IBeaconDistanceDescriptor.FAR;
} }
/**
* Calculates the accuracy of an RSSI reading.
*
* The code was taken from {@linktourl http://stackoverflow.com/questions/20416218/understanding-ibeacon-distancing}
*
* @param txPower the calibrated TX power of an iBeacon
* @param rssi the RSSI value of the iBeacon
* @return the calculated Accuracy
*/
public static double calculateAccuracy(final int txPower, final double rssi) {
if (rssi == 0) {
return -1.0; // if we cannot determine accuracy, return -1.
}
final double ratio = rssi*1.0/txPower;
if (ratio < 1.0) {
return Math.pow(ratio,10);
}
else {
final double accuracy = (0.89976)*Math.pow(ratio,7.7095) + 0.111;
return accuracy;
}
}
/** /**
* Ascertains whether a {@link uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice} is an iBeacon; * Ascertains whether a {@link uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice} is an iBeacon;
* *
@@ -68,10 +67,14 @@ public class IBeaconUtils {
* @return true if the manufacturer data belong to an iBeacon * @return true if the manufacturer data belong to an iBeacon
*/ */
public static boolean isThisAnIBeacon(final byte[] manufacturerData) { public static boolean isThisAnIBeacon(final byte[] manufacturerData) {
if(manufacturerData == null){return false;} if (manufacturerData == null) {
return false;
}
// An iBeacon record must be at least 25 chars long // An iBeacon record must be at least 25 chars long
if(!(manufacturerData.length >= 25)){return false;} if (!(manufacturerData.length >= 25)) {
return false;
}
if (ByteUtils.doesArrayBeginWith(manufacturerData, MANUFACTURER_DATA_IBEACON_PREFIX)) { if (ByteUtils.doesArrayBeginWith(manufacturerData, MANUFACTURER_DATA_IBEACON_PREFIX)) {
return true; return true;
@@ -80,10 +83,4 @@ public class IBeaconUtils {
return false; return false;
} }
public enum IBeaconDistanceDescriptor{
IMMEDIATE,
NEAR,
FAR,
UNKNOWN,
}
} }
+2 -1
View File
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest
package="uk.co.alt236.btlescan" package="uk.co.alt236.btlescan"
xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="3" android:versionCode="3"
android:versionName="0.0.3"> android:versionName="0.0.3">
@@ -16,16 +16,6 @@
package uk.co.alt236.btlescan.activities; package uk.co.alt236.btlescan.activities;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice;
import uk.co.alt236.bluetoothlelib.resolvers.GattAttributeResolver;
import uk.co.alt236.bluetoothlelib.util.ByteUtils;
import uk.co.alt236.btlescan.R;
import uk.co.alt236.btlescan.services.BluetoothLeService;
import android.app.Activity; import android.app.Activity;
import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService; import android.bluetooth.BluetoothGattService;
@@ -44,8 +34,19 @@ import android.view.View;
import android.widget.ExpandableListView; import android.widget.ExpandableListView;
import android.widget.SimpleExpandableListAdapter; import android.widget.SimpleExpandableListAdapter;
import android.widget.TextView; import android.widget.TextView;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import butterknife.InjectView; import butterknife.InjectView;
import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice;
import uk.co.alt236.bluetoothlelib.resolvers.GattAttributeResolver;
import uk.co.alt236.bluetoothlelib.util.ByteUtils;
import uk.co.alt236.btlescan.R;
import uk.co.alt236.btlescan.services.BluetoothLeService;
/** /**
* For a given BLE device, this Activity provides the user interface to connect, display data, * For a given BLE device, this Activity provides the user interface to connect, display data,
@@ -54,29 +55,54 @@ import butterknife.InjectView;
* Bluetooth LE API. * Bluetooth LE API.
*/ */
public class DeviceControlActivity extends Activity { public class DeviceControlActivity extends Activity {
private final static String TAG = DeviceControlActivity.class.getSimpleName();
public static final String EXTRA_DEVICE = "extra_device"; public static final String EXTRA_DEVICE = "extra_device";
private final static String TAG = DeviceControlActivity.class.getSimpleName();
private static final String LIST_NAME = "NAME"; private static final String LIST_NAME = "NAME";
private static final String LIST_UUID = "UUID"; private static final String LIST_UUID = "UUID";
@InjectView(R.id.gatt_services_list)
ExpandableListView mGattServicesList;
@InjectView(R.id.connection_state)
TextView mConnectionState;
@InjectView(R.id.uuid)
TextView mGattUUID;
@InjectView(R.id.description)
TextView mGattUUIDDesc;
@InjectView(R.id.data_as_string)
TextView mDataAsString;
@InjectView(R.id.data_as_array)
TextView mDataAsArray;
private BluetoothGattCharacteristic mNotifyCharacteristic; private BluetoothGattCharacteristic mNotifyCharacteristic;
private BluetoothLeService mBluetoothLeService; private BluetoothLeService mBluetoothLeService;
private List<List<BluetoothGattCharacteristic>> mGattCharacteristics = new ArrayList<List<BluetoothGattCharacteristic>>(); private List<List<BluetoothGattCharacteristic>> mGattCharacteristics = new ArrayList<List<BluetoothGattCharacteristic>>();
// If a given GATT characteristic is selected, check for supported features. This sample
// demonstrates 'Read' and 'Notify' features. See
// http://d.android.com/reference/android/bluetooth/BluetoothGatt.html for the complete
// list of supported characteristic features.
private final ExpandableListView.OnChildClickListener servicesListClickListner = new ExpandableListView.OnChildClickListener() {
@Override
public boolean onChildClick(final ExpandableListView parent, final View v, final int groupPosition, final int childPosition, final long id) {
if (mGattCharacteristics != null) {
final BluetoothGattCharacteristic characteristic = mGattCharacteristics.get(groupPosition).get(childPosition);
final int charaProp = characteristic.getProperties();
if ((charaProp | BluetoothGattCharacteristic.PROPERTY_READ) > 0) {
// If there is an active notification on a characteristic, clear
// it first so it doesn't update the data field on the user interface.
if (mNotifyCharacteristic != null) {
mBluetoothLeService.setCharacteristicNotification(mNotifyCharacteristic, false);
mNotifyCharacteristic = null;
}
mBluetoothLeService.readCharacteristic(characteristic);
}
if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
mNotifyCharacteristic = characteristic;
mBluetoothLeService.setCharacteristicNotification(characteristic, true);
}
return true;
}
return false;
}
};
private String mDeviceAddress; private String mDeviceAddress;
private String mDeviceName;
@InjectView(R.id.gatt_services_list) ExpandableListView mGattServicesList;
@InjectView(R.id.connection_state) TextView mConnectionState;
@InjectView(R.id.uuid) TextView mGattUUID;
@InjectView(R.id.description) TextView mGattUUIDDesc;
@InjectView(R.id.data_as_string) TextView mDataAsString;
@InjectView(R.id.data_as_array) TextView mDataAsArray;
private boolean mConnected = false;
private String mExportString;
// Code to manage Service lifecycle. // Code to manage Service lifecycle.
private final ServiceConnection mServiceConnection = new ServiceConnection() { private final ServiceConnection mServiceConnection = new ServiceConnection() {
@Override @Override
@@ -95,7 +121,9 @@ public class DeviceControlActivity extends Activity {
mBluetoothLeService = null; mBluetoothLeService = null;
} }
}; };
private String mDeviceName;
private boolean mConnected = false;
private String mExportString;
// Handles various events fired by the Service. // Handles various events fired by the Service.
// ACTION_GATT_CONNECTED: connected to a GATT server. // ACTION_GATT_CONNECTED: connected to a GATT server.
// ACTION_GATT_DISCONNECTED: disconnected from a GATT server. // ACTION_GATT_DISCONNECTED: disconnected from a GATT server.
@@ -131,35 +159,6 @@ public class DeviceControlActivity extends Activity {
} }
}; };
// If a given GATT characteristic is selected, check for supported features. This sample
// demonstrates 'Read' and 'Notify' features. See
// http://d.android.com/reference/android/bluetooth/BluetoothGatt.html for the complete
// list of supported characteristic features.
private final ExpandableListView.OnChildClickListener servicesListClickListner = new ExpandableListView.OnChildClickListener() {
@Override
public boolean onChildClick(final ExpandableListView parent, final View v, final int groupPosition, final int childPosition, final long id) {
if (mGattCharacteristics != null) {
final BluetoothGattCharacteristic characteristic = mGattCharacteristics.get(groupPosition).get(childPosition);
final int charaProp = characteristic.getProperties();
if ((charaProp | BluetoothGattCharacteristic.PROPERTY_READ) > 0) {
// If there is an active notification on a characteristic, clear
// it first so it doesn't update the data field on the user interface.
if (mNotifyCharacteristic != null) {
mBluetoothLeService.setCharacteristicNotification(mNotifyCharacteristic, false);
mNotifyCharacteristic = null;
}
mBluetoothLeService.readCharacteristic(characteristic);
}
if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
mNotifyCharacteristic = characteristic;
mBluetoothLeService.setCharacteristicNotification(characteristic, true);
}
return true;
}
return false;
}
};
private void clearUI() { private void clearUI() {
mGattServicesList.setAdapter((SimpleExpandableListAdapter) null); mGattServicesList.setAdapter((SimpleExpandableListAdapter) null);
mGattUUID.setText(R.string.no_data); mGattUUID.setText(R.string.no_data);
@@ -168,55 +167,6 @@ public class DeviceControlActivity extends Activity {
mDataAsString.setText(R.string.no_data); mDataAsString.setText(R.string.no_data);
} }
private void generateExportString(final List<BluetoothGattService> gattServices){
final String unknownServiceString = getResources().getString(R.string.unknown_service);
final String unknownCharaString = getResources().getString(R.string.unknown_characteristic);
final StringBuilder exportBuilder = new StringBuilder();
exportBuilder.append("Device Name: ");
exportBuilder.append(mDeviceName);
exportBuilder.append('\n');
exportBuilder.append("Device Address: ");
exportBuilder.append(mDeviceAddress);
exportBuilder.append('\n');
exportBuilder.append('\n');
exportBuilder.append("Services:");
exportBuilder.append("--------------------------");
exportBuilder.append('\n');
String uuid = null;
for (final BluetoothGattService gattService : gattServices) {
uuid = gattService.getUuid().toString();
exportBuilder.append(GattAttributeResolver.getAttributeName(uuid, unknownServiceString));
exportBuilder.append(" (");
exportBuilder.append(uuid);
exportBuilder.append(')');
exportBuilder.append('\n');
final List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
for (final BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
uuid = gattCharacteristic.getUuid().toString();
exportBuilder.append('\t');
exportBuilder.append(GattAttributeResolver.getAttributeName(uuid, unknownCharaString));
exportBuilder.append(" (");
exportBuilder.append(uuid);
exportBuilder.append(')');
exportBuilder.append('\n');
}
exportBuilder.append('\n');
exportBuilder.append('\n');
}
exportBuilder.append("--------------------------");
exportBuilder.append('\n');
mExportString = exportBuilder.toString();
}
// Demonstrates how to iterate through the supported GATT Services/Characteristics. // Demonstrates how to iterate through the supported GATT Services/Characteristics.
// In this sample, we populate the data structure that is bound to the ExpandableListView // In this sample, we populate the data structure that is bound to the ExpandableListView
// on the UI. // on the UI.
@@ -273,6 +223,55 @@ public class DeviceControlActivity extends Activity {
invalidateOptionsMenu(); invalidateOptionsMenu();
} }
private void generateExportString(final List<BluetoothGattService> gattServices) {
final String unknownServiceString = getResources().getString(R.string.unknown_service);
final String unknownCharaString = getResources().getString(R.string.unknown_characteristic);
final StringBuilder exportBuilder = new StringBuilder();
exportBuilder.append("Device Name: ");
exportBuilder.append(mDeviceName);
exportBuilder.append('\n');
exportBuilder.append("Device Address: ");
exportBuilder.append(mDeviceAddress);
exportBuilder.append('\n');
exportBuilder.append('\n');
exportBuilder.append("Services:");
exportBuilder.append("--------------------------");
exportBuilder.append('\n');
String uuid = null;
for (final BluetoothGattService gattService : gattServices) {
uuid = gattService.getUuid().toString();
exportBuilder.append(GattAttributeResolver.getAttributeName(uuid, unknownServiceString));
exportBuilder.append(" (");
exportBuilder.append(uuid);
exportBuilder.append(')');
exportBuilder.append('\n');
final List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
for (final BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
uuid = gattCharacteristic.getUuid().toString();
exportBuilder.append('\t');
exportBuilder.append(GattAttributeResolver.getAttributeName(uuid, unknownCharaString));
exportBuilder.append(" (");
exportBuilder.append(uuid);
exportBuilder.append(')');
exportBuilder.append('\n');
}
exportBuilder.append('\n');
exportBuilder.append('\n');
}
exportBuilder.append("--------------------------");
exportBuilder.append('\n');
mExportString = exportBuilder.toString();
}
@Override @Override
public void onCreate(final Bundle savedInstanceState) { public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@@ -1,8 +1,19 @@
package uk.co.alt236.btlescan.activities; package uk.co.alt236.btlescan.activities;
import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.commonsware.cwac.merge.MergeAdapter;
import java.util.Collection; import java.util.Collection;
import java.util.Locale; import java.util.Locale;
import butterknife.ButterKnife;
import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice; import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice;
import uk.co.alt236.bluetoothlelib.device.adrecord.AdRecord; import uk.co.alt236.bluetoothlelib.device.adrecord.AdRecord;
import uk.co.alt236.bluetoothlelib.device.mfdata.IBeaconManufacturerData; import uk.co.alt236.bluetoothlelib.device.mfdata.IBeaconManufacturerData;
@@ -12,16 +23,6 @@ import uk.co.alt236.bluetoothlelib.util.ByteUtils;
import uk.co.alt236.bluetoothlelib.util.IBeaconUtils; import uk.co.alt236.bluetoothlelib.util.IBeaconUtils;
import uk.co.alt236.btlescan.R; import uk.co.alt236.btlescan.R;
import uk.co.alt236.btlescan.util.TimeFormatter; import uk.co.alt236.btlescan.util.TimeFormatter;
import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.LinearLayout;
import android.widget.TextView;
import butterknife.ButterKnife;
import com.commonsware.cwac.merge.MergeAdapter;
public class DeviceDetailsActivity extends ListActivity { public class DeviceDetailsActivity extends ListActivity {
public static final String EXTRA_DEVICE = "extra_device"; public static final String EXTRA_DEVICE = "extra_device";
@@ -1,12 +1,5 @@
package uk.co.alt236.btlescan.activities; package uk.co.alt236.btlescan.activities;
import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice;
import uk.co.alt236.btlescan.R;
import uk.co.alt236.btlescan.adapters.LeDeviceListAdapter;
import uk.co.alt236.btlescan.containers.BluetoothLeDeviceStore;
import uk.co.alt236.btlescan.util.BluetoothLeScanner;
import uk.co.alt236.btlescan.util.BluetoothUtils;
import uk.co.alt236.easycursor.objectcursor.EasyObjectCursor;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.ListActivity; import android.app.ListActivity;
import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter;
@@ -22,13 +15,24 @@ import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.widget.ListView; import android.widget.ListView;
import android.widget.TextView; import android.widget.TextView;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import butterknife.InjectView; import butterknife.InjectView;
import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice;
import uk.co.alt236.btlescan.R;
import uk.co.alt236.btlescan.adapters.LeDeviceListAdapter;
import uk.co.alt236.btlescan.containers.BluetoothLeDeviceStore;
import uk.co.alt236.btlescan.util.BluetoothLeScanner;
import uk.co.alt236.btlescan.util.BluetoothUtils;
import uk.co.alt236.easycursor.objectcursor.EasyObjectCursor;
public class MainActivity extends ListActivity { public class MainActivity extends ListActivity {
@InjectView(R.id.tvBluetoothLe) TextView mTvBluetoothLeStatus; @InjectView(R.id.tvBluetoothLe)
@InjectView(R.id.tvBluetoothStatus) TextView mTvBluetoothStatus; TextView mTvBluetoothLeStatus;
@InjectView(R.id.tvItemCount) TextView mTvItemCount; @InjectView(R.id.tvBluetoothStatus)
TextView mTvBluetoothStatus;
@InjectView(R.id.tvItemCount)
TextView mTvItemCount;
private BluetoothUtils mBluetoothUtils; private BluetoothUtils mBluetoothUtils;
private BluetoothLeScanner mScanner; private BluetoothLeScanner mScanner;
@@ -53,13 +57,6 @@ public class MainActivity extends ListActivity {
} }
}; };
private void updateItemCount(final int count){
mTvItemCount.setText(
getString(
R.string.formatter_item_count,
String.valueOf(count)));
}
private void displayAboutDialog() { private void displayAboutDialog() {
// REALLY REALLY LAZY LINKIFIED DIALOG // REALLY REALLY LAZY LINKIFIED DIALOG
final int paddingSizeDp = 5; final int paddingSizeDp = 5;
@@ -79,7 +76,8 @@ public class MainActivity extends ListActivity {
.setTitle(R.string.menu_about) .setTitle(R.string.menu_about)
.setCancelable(false) .setCancelable(false)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(final DialogInterface dialog, final int id) {} public void onClick(final DialogInterface dialog, final int id) {
}
}) })
.setView(textView) .setView(textView)
.show(); .show();
@@ -192,4 +190,11 @@ public class MainActivity extends ListActivity {
} }
} }
private void updateItemCount(final int count) {
mTvItemCount.setText(
getString(
R.string.formatter_item_count,
String.valueOf(count)));
}
} }
@@ -1,11 +1,5 @@
package uk.co.alt236.btlescan.adapters; package uk.co.alt236.btlescan.adapters;
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.btlescan.R;
import uk.co.alt236.btlescan.util.Constants;
import uk.co.alt236.easycursor.objectcursor.EasyObjectCursor;
import android.app.Activity; import android.app.Activity;
import android.support.v4.widget.SimpleCursorAdapter; import android.support.v4.widget.SimpleCursorAdapter;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@@ -13,6 +7,14 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; 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.btlescan.R;
import uk.co.alt236.btlescan.util.Constants;
import uk.co.alt236.easycursor.objectcursor.EasyObjectCursor;
// Adapter for holding devices found through scanning. // Adapter for holding devices found through scanning.
public class LeDeviceListAdapter extends SimpleCursorAdapter { public class LeDeviceListAdapter extends SimpleCursorAdapter {
private final LayoutInflater mInflator; private final LayoutInflater mInflator;
@@ -1,5 +1,9 @@
package uk.co.alt236.btlescan.containers; package uk.co.alt236.btlescan.containers;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import java.io.File; import java.io.File;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
@@ -19,9 +23,6 @@ import uk.co.alt236.btlescan.R;
import uk.co.alt236.btlescan.util.CsvWriterHelper; import uk.co.alt236.btlescan.util.CsvWriterHelper;
import uk.co.alt236.btlescan.util.TimeFormatter; import uk.co.alt236.btlescan.util.TimeFormatter;
import uk.co.alt236.easycursor.objectcursor.EasyObjectCursor; import uk.co.alt236.easycursor.objectcursor.EasyObjectCursor;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
public class BluetoothLeDeviceStore { public class BluetoothLeDeviceStore {
private final Map<String, BluetoothLeDevice> mDeviceMap; private final Map<String, BluetoothLeDevice> mDeviceMap;
@@ -43,26 +44,6 @@ public class BluetoothLeDeviceStore {
mDeviceMap.clear(); mDeviceMap.clear();
} }
private static FileWriter generateFile(final File file, final String contents){
FileWriter writer = null;
try {
writer = new FileWriter(file);
writer.append(contents);
writer.flush();
} catch (final IOException e) {
e.printStackTrace();
}finally{
try {
writer.close();
} catch (final IOException e) {
e.printStackTrace();
}
}
return writer;
}
public EasyObjectCursor<BluetoothLeDevice> getDeviceCursor() { public EasyObjectCursor<BluetoothLeDevice> getDeviceCursor() {
return new EasyObjectCursor<BluetoothLeDevice>( return new EasyObjectCursor<BluetoothLeDevice>(
BluetoothLeDevice.class, BluetoothLeDevice.class,
@@ -84,7 +65,6 @@ public class BluetoothLeDeviceStore {
return methodResult; return methodResult;
} }
private String getListAsCsv() { private String getListAsCsv() {
final List<BluetoothLeDevice> list = getDeviceList(); final List<BluetoothLeDevice> list = getDeviceList();
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
@@ -151,7 +131,6 @@ public class BluetoothLeDeviceStore {
return sb.toString(); return sb.toString();
} }
public void shareDataAsEmail(final Context context) { public void shareDataAsEmail(final Context context) {
final long timeInMillis = System.currentTimeMillis(); final long timeInMillis = System.currentTimeMillis();
@@ -179,4 +158,23 @@ public class BluetoothLeDeviceStore {
e.printStackTrace(); e.printStackTrace();
} }
} }
private static FileWriter generateFile(final File file, final String contents) {
FileWriter writer = null;
try {
writer = new FileWriter(file);
writer.append(contents);
writer.flush();
} catch (final IOException e) {
e.printStackTrace();
} finally {
try {
writer.close();
} catch (final IOException e) {
e.printStackTrace();
}
}
return writer;
}
} }
@@ -16,8 +16,6 @@
package uk.co.alt236.btlescan.services; package uk.co.alt236.btlescan.services;
import java.util.List;
import android.app.Service; import android.app.Service;
import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice;
@@ -33,33 +31,44 @@ import android.os.Binder;
import android.os.IBinder; import android.os.IBinder;
import android.util.Log; import android.util.Log;
import java.util.List;
/** /**
* Service for managing connection and data communication with a GATT server hosted on a * Service for managing connection and data communication with a GATT server hosted on a
* given Bluetooth LE device. * given Bluetooth LE device.
*/ */
public class BluetoothLeService extends Service { public class BluetoothLeService extends Service {
private final static String TAG = BluetoothLeService.class.getSimpleName();
private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private String mBluetoothDeviceAddress;
private BluetoothGatt mBluetoothGatt;
private int mConnectionState = STATE_DISCONNECTED;
private static final int STATE_DISCONNECTED = 0;
private static final int STATE_CONNECTING = 1;
private static final int STATE_CONNECTED = 2;
public final static String ACTION_GATT_CONNECTED = "com.example.bluetooth.le.ACTION_GATT_CONNECTED"; public final static String ACTION_GATT_CONNECTED = "com.example.bluetooth.le.ACTION_GATT_CONNECTED";
public final static String ACTION_GATT_DISCONNECTED = "com.example.bluetooth.le.ACTION_GATT_DISCONNECTED"; public final static String ACTION_GATT_DISCONNECTED = "com.example.bluetooth.le.ACTION_GATT_DISCONNECTED";
public final static String ACTION_GATT_SERVICES_DISCOVERED = "com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED"; public final static String ACTION_GATT_SERVICES_DISCOVERED = "com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED";
public final static String ACTION_DATA_AVAILABLE = "com.example.bluetooth.le.ACTION_DATA_AVAILABLE"; public final static String ACTION_DATA_AVAILABLE = "com.example.bluetooth.le.ACTION_DATA_AVAILABLE";
public final static String EXTRA_DATA_RAW = "com.example.bluetooth.le.EXTRA_DATA_RAW"; public final static String EXTRA_DATA_RAW = "com.example.bluetooth.le.EXTRA_DATA_RAW";
public final static String EXTRA_UUID_CHAR = "com.example.bluetooth.le.EXTRA_UUID_CHAR"; public final static String EXTRA_UUID_CHAR = "com.example.bluetooth.le.EXTRA_UUID_CHAR";
private final static String TAG = BluetoothLeService.class.getSimpleName();
private static final int STATE_DISCONNECTED = 0;
private static final int STATE_CONNECTING = 1;
private static final int STATE_CONNECTED = 2;
private final IBinder mBinder = new LocalBinder();
private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private String mBluetoothDeviceAddress;
private BluetoothGatt mBluetoothGatt;
private int mConnectionState = STATE_DISCONNECTED;
// Implements callback methods for GATT events that the app cares about. For example, // Implements callback methods for GATT events that the app cares about. For example,
// connection change and services discovered. // connection change and services discovered.
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override
public void onCharacteristicChanged(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
@Override
public void onCharacteristicRead(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, final int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
@Override @Override
public void onConnectionStateChange(final BluetoothGatt gatt, final int status, final int newState) { public void onConnectionStateChange(final BluetoothGatt gatt, final int status, final int newState) {
final String intentAction; final String intentAction;
@@ -87,18 +96,6 @@ public class BluetoothLeService extends Service {
Log.w(TAG, "onServicesDiscovered received: " + status); Log.w(TAG, "onServicesDiscovered received: " + status);
} }
} }
@Override
public void onCharacteristicRead(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, final int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
@Override
public void onCharacteristicChanged(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}; };
private void broadcastUpdate(final String action) { private void broadcastUpdate(final String action) {
@@ -119,58 +116,22 @@ public class BluetoothLeService extends Service {
sendBroadcast(intent); sendBroadcast(intent);
} }
public class LocalBinder extends Binder {
public BluetoothLeService getService() {
return BluetoothLeService.this;
}
}
@Override
public IBinder onBind(final Intent intent) {
return mBinder;
}
@Override
public boolean onUnbind(final Intent intent) {
// After using a given device, you should make sure that BluetoothGatt.close() is called
// such that resources are cleaned up properly. In this particular example, close() is
// invoked when the UI is disconnected from the Service.
close();
return super.onUnbind(intent);
}
private final IBinder mBinder = new LocalBinder();
/** /**
* Initializes a reference to the local Bluetooth adapter. * After using a given BLE device, the app must call this method to ensure resources are
* * released properly.
* @return Return true if the initialization is successful.
*/ */
public boolean initialize() { public void close() {
// For API level 18 and above, get a reference to BluetoothAdapter through if (mBluetoothGatt == null) {
// BluetoothManager. return;
if (mBluetoothManager == null) {
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (mBluetoothManager == null) {
Log.e(TAG, "Unable to initialize BluetoothManager.");
return false;
} }
} mBluetoothGatt.close();
mBluetoothGatt = null;
mBluetoothAdapter = mBluetoothManager.getAdapter();
if (mBluetoothAdapter == null) {
Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
return false;
}
return true;
} }
/** /**
* Connects to the GATT server hosted on the Bluetooth LE device. * Connects to the GATT server hosted on the Bluetooth LE device.
* *
* @param address The device address of the destination device. * @param address The device address of the destination device.
*
* @return Return true if the connection is initiated successfully. The connection result * @return Return true if the connection is initiated successfully. The connection result
* is reported asynchronously through the * is reported asynchronously through the
* {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)} * {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
@@ -225,15 +186,54 @@ public class BluetoothLeService extends Service {
} }
/** /**
* After using a given BLE device, the app must call this method to ensure resources are * Retrieves a list of supported GATT services on the connected device. This should be
* released properly. * invoked only after {@code BluetoothGatt#discoverServices()} completes successfully.
*
* @return A {@code List} of supported services.
*/ */
public void close() { public List<BluetoothGattService> getSupportedGattServices() {
if (mBluetoothGatt == null) { if (mBluetoothGatt == null) return null;
return;
return mBluetoothGatt.getServices();
} }
mBluetoothGatt.close();
mBluetoothGatt = null; /**
* Initializes a reference to the local Bluetooth adapter.
*
* @return Return true if the initialization is successful.
*/
public boolean initialize() {
// For API level 18 and above, get a reference to BluetoothAdapter through
// BluetoothManager.
if (mBluetoothManager == null) {
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (mBluetoothManager == null) {
Log.e(TAG, "Unable to initialize BluetoothManager.");
return false;
}
}
mBluetoothAdapter = mBluetoothManager.getAdapter();
if (mBluetoothAdapter == null) {
Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
return false;
}
return true;
}
@Override
public IBinder onBind(final Intent intent) {
return mBinder;
}
@Override
public boolean onUnbind(final Intent intent) {
// After using a given device, you should make sure that BluetoothGatt.close() is called
// such that resources are cleaned up properly. In this particular example, close() is
// invoked when the UI is disconnected from the Service.
close();
return super.onUnbind(intent);
} }
/** /**
@@ -265,15 +265,9 @@ public class BluetoothLeService extends Service {
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled); mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
} }
/** public class LocalBinder extends Binder {
* Retrieves a list of supported GATT services on the connected device. This should be public BluetoothLeService getService() {
* invoked only after {@code BluetoothGatt#discoverServices()} completes successfully. return BluetoothLeService.this;
* }
* @return A {@code List} of supported services.
*/
public List<BluetoothGattService> getSupportedGattServices() {
if (mBluetoothGatt == null) return null;
return mBluetoothGatt.getServices();
} }
} }
@@ -22,7 +22,9 @@ public class BluetoothLeScanner {
public void scanLeDevice(final int duration, final boolean enable) { public void scanLeDevice(final int duration, final boolean enable) {
if (enable) { if (enable) {
if(mScanning){return;} if (mScanning) {
return;
}
Log.d("TAG", "~ Starting Scan"); Log.d("TAG", "~ Starting Scan");
// Stops scanning after a pre-defined scan period. // Stops scanning after a pre-defined scan period.
if (duration > 0) { if (duration > 0) {
@@ -8,11 +8,10 @@ import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
public final class BluetoothUtils { public final class BluetoothUtils {
public final static int REQUEST_ENABLE_BT = 2001;
private final Activity mActivity; private final Activity mActivity;
private final BluetoothAdapter mBluetoothAdapter; private final BluetoothAdapter mBluetoothAdapter;
public final static int REQUEST_ENABLE_BT = 2001;
public BluetoothUtils(final Activity activity) { public BluetoothUtils(final Activity activity) {
mActivity = activity; mActivity = activity;
final BluetoothManager btManager = (BluetoothManager) mActivity.getSystemService(Context.BLUETOOTH_SERVICE); final BluetoothManager btManager = (BluetoothManager) mActivity.getSystemService(Context.BLUETOOTH_SERVICE);
@@ -2,6 +2,7 @@ package uk.co.alt236.btlescan.util;
public class CsvWriterHelper { public class CsvWriterHelper {
private static final String QUOTE = "\""; private static final String QUOTE = "\"";
public static String addStuff(final Integer text) { public static String addStuff(final Integer text) {
return QUOTE + text + QUOTE + ","; return QUOTE + text + QUOTE + ",";
} }
@@ -15,7 +16,9 @@ public class CsvWriterHelper {
} }
public static String addStuff(String text) { public static String addStuff(String text) {
if(text == null){text = "<blank>";} if (text == null) {
text = "<blank>";
}
text = text.replace(QUOTE, "'"); text = text.replace(QUOTE, "'");
return QUOTE + text.trim() + QUOTE + ","; return QUOTE + text.trim() + QUOTE + ",";
@@ -1,9 +1,10 @@
/******************************************************************************* /**
* ****************************************************************************
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
* * <p/>
* GenieConnect Ltd. ("COMPANY") CONFIDENTIAL * GenieConnect Ltd. ("COMPANY") CONFIDENTIAL
* Unpublished Copyright (c) 2010-2013 GenieConnect Ltd., All Rights Reserved. * Unpublished Copyright (c) 2010-2013 GenieConnect Ltd., All Rights Reserved.
* * <p/>
* NOTICE: * NOTICE:
* All information contained herein is, and remains the property of COMPANY. * All information contained herein is, and remains the property of COMPANY.
* The intellectual and technical concepts contained herein are proprietary to * The intellectual and technical concepts contained herein are proprietary to
@@ -14,11 +15,11 @@
* contained herein is hereby forbidden to anyone except current COMPANY employees, * contained herein is hereby forbidden to anyone except current COMPANY employees,
* managers or contractors who have executed Confidentiality and Non-disclosure * managers or contractors who have executed Confidentiality and Non-disclosure
* agreements explicitly covering such access. * agreements explicitly covering such access.
* * <p/>
* The copyright notice above does not evidence any actual or intended publication * The copyright notice above does not evidence any actual or intended publication
* or disclosure of this source code, which includes information that is * or disclosure of this source code, which includes information that is
* confidential and/or proprietary, and is a trade secret, of COMPANY. * confidential and/or proprietary, and is a trade secret, of COMPANY.
* * <p/>
* ANY REPRODUCTION, MODIFICATION, DISTRIBUTION, PUBLIC PERFORMANCE, OR PUBLIC * ANY REPRODUCTION, MODIFICATION, DISTRIBUTION, PUBLIC PERFORMANCE, OR PUBLIC
* DISPLAY OF OR THROUGH USE OF THIS SOURCE CODE WITHOUT THE EXPRESS WRITTEN * DISPLAY OF OR THROUGH USE OF THIS SOURCE CODE WITHOUT THE EXPRESS WRITTEN
* CONSENT OF COMPANY IS STRICTLY PROHIBITED, AND IN VIOLATION OF APPLICABLE LAWS * CONSENT OF COMPANY IS STRICTLY PROHIBITED, AND IN VIOLATION OF APPLICABLE LAWS
@@ -26,15 +27,16 @@
* AND/OR RELATED INFORMATION DOES NOT CONVEY OR IMPLY ANY RIGHTS TO REPRODUCE, * AND/OR RELATED INFORMATION DOES NOT CONVEY OR IMPLY ANY RIGHTS TO REPRODUCE,
* DISCLOSE OR DISTRIBUTE ITS CONTENTS, OR TO MANUFACTURE, USE, OR SELL ANYTHING * DISCLOSE OR DISTRIBUTE ITS CONTENTS, OR TO MANUFACTURE, USE, OR SELL ANYTHING
* THAT IT MAY DESCRIBE, IN WHOLE OR IN PART. * THAT IT MAY DESCRIBE, IN WHOLE OR IN PART.
******************************************************************************/ * ****************************************************************************
*/
package uk.co.alt236.btlescan.util; package uk.co.alt236.btlescan.util;
import android.annotation.SuppressLint;
import java.text.DateFormatSymbols; import java.text.DateFormatSymbols;
import java.util.Locale; import java.util.Locale;
import java.util.TimeZone; import java.util.TimeZone;
import android.annotation.SuppressLint;
public class UtcDateFormatter extends java.text.SimpleDateFormat { public class UtcDateFormatter extends java.text.SimpleDateFormat {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -1,5 +1,4 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin"
@@ -92,8 +92,8 @@
android:id="@+id/listContainer" android:id="@+id/listContainer"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:layout_above="@id/infoContainer" android:layout_above="@id/infoContainer"
android:layout_alignParentTop="true"
android:orientation="vertical"> android:orientation="vertical">
<ListView <ListView
@@ -22,10 +22,10 @@
<ImageView <ImageView
android:id="@+id/device_icon" android:id="@+id/device_icon"
android:paddingTop="5dp"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingRight="5dp" android:paddingRight="5dp"
android:paddingTop="5dp"
android:src="@drawable/ic_bluetooth"/> android:src="@drawable/ic_bluetooth"/>
<LinearLayout <LinearLayout
+1 -1
View File
@@ -33,9 +33,9 @@
android:title="@string/menu_stop"/> android:title="@string/menu_stop"/>
<item <item
android:id="@+id/menu_share" android:id="@+id/menu_share"
android:icon="@drawable/ic_action_share"
android:orderInCategory="102" android:orderInCategory="102"
android:showAsAction="ifRoom" android:showAsAction="ifRoom"
android:icon="@drawable/ic_action_share"
android:title="@string/menu_share"/> android:title="@string/menu_share"/>
<item <item
android:id="@+id/menu_about" android:id="@+id/menu_about"