Full code reformat
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
+8
-8
@@ -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());
|
||||||
|
|||||||
+16
-9
@@ -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])));
|
||||||
|
|||||||
+1
-5
@@ -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,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|
||||||
|
|||||||
+104
-105
@@ -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);
|
||||||
|
|||||||
+11
-10
@@ -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;
|
||||||
|
|||||||
+23
-25
@@ -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
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user