package com.elinkthings.ailinksecrettooldemo;
import android.os.ParcelUuid;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* xing
* 2019/3/7
* 广播解析工具类
*/
public class BleBroadcastUtils {
private static final int DATA_TYPE_FLAGS = 0x01;
private static final int DATA_TYPE_SERVICE_UUIDS_16_BIT_PARTIAL = 0x02;
private static final int DATA_TYPE_SERVICE_UUIDS_16_BIT_COMPLETE = 0x03;
private static final int DATA_TYPE_SERVICE_UUIDS_32_BIT_PARTIAL = 0x04;
private static final int DATA_TYPE_SERVICE_UUIDS_32_BIT_COMPLETE = 0x05;
private static final int DATA_TYPE_SERVICE_UUIDS_128_BIT_PARTIAL = 0x06;
private static final int DATA_TYPE_SERVICE_UUIDS_128_BIT_COMPLETE = 0x07;
private static final int DATA_TYPE_LOCAL_NAME_SHORT = 0x08;
private static final int DATA_TYPE_LOCAL_NAME_COMPLETE = 0x09;
private static final int DATA_TYPE_TX_POWER_LEVEL = 0x0A;
private static final int DATA_TYPE_SERVICE_DATA_16_BIT = 0x16;
private static final int DATA_TYPE_SERVICE_DATA_32_BIT = 0x20;
private static final int DATA_TYPE_SERVICE_DATA_128_BIT = 0x21;
private static final int DATA_TYPE_MANUFACTURER_SPECIFIC_DATA = 0xFF;
private static final int DATA_TYPE_MANUFACTURER_SPECIFIC_DATA_MOVE = 0xFE;
private List mManufacturerByte;
private byte[] mManufacturerByteMove;
private List mServiceUuids;
private int mAdvertiseFlag = -1;
private Map mServiceData;
private String mDeviceName;
public BleBroadcastUtils(byte[] scanRecord) {
this(scanRecord, -1);
}
public BleBroadcastUtils(byte[] scanRecord, int manufacturerId) {
mManufacturerByte=new ArrayList<>();
getBleData(scanRecord, manufacturerId);
}
// Helper method to extract bytes from byte array.
private static byte[] extractBytes(byte[] scanRecord, int start, int length) {
byte[] bytes = new byte[length];
System.arraycopy(scanRecord, start, bytes, 0, length);
return bytes;
}
public List getManufacturerSpecificData() {
return mManufacturerByte;
}
public byte[] getManufacturerByteMove() {
return mManufacturerByteMove;
}
/**
* 服务uuid
*
* @return {@link List}<{@link ParcelUuid}>
*/
public List getServiceUuids() {
return mServiceUuids;
}
/**
* 广告标志
*
* @return int
*/
public int getAdvertiseFlag() {
return mAdvertiseFlag;
}
public String getDeviceName() {
return mDeviceName;
}
/**
* 服务数据
*
* @return {@link Map}<{@link ParcelUuid}, {@link byte[]}>
*/
public Map getServiceData() {
return mServiceData;
}
/**
* 服务数据
*
* @param serviceDataUuid 服务数据uuid
* @return {@link byte[]}
*/
public byte[] getServiceData(final ParcelUuid serviceDataUuid) {
//noinspection ConstantConditions
if (serviceDataUuid == null || mServiceData == null) {
return null;
}
return mServiceData.get(serviceDataUuid);
}
private void getBleData(byte[] scanRecord, int id) {
int currentPos = 0;
mServiceUuids = new ArrayList<>();
try {
while (currentPos < scanRecord.length) {
int length = scanRecord[currentPos++] & 0xFF;
if (length == 0)
break;
int dataLength = length - 1;
int fieldType = scanRecord[currentPos++] & 0xFF;
switch (fieldType) {
case DATA_TYPE_FLAGS:
mAdvertiseFlag = scanRecord[currentPos] & 0xFF;
break;
case DATA_TYPE_SERVICE_UUIDS_16_BIT_PARTIAL:
case DATA_TYPE_SERVICE_UUIDS_16_BIT_COMPLETE:
parseServiceUuid(scanRecord, currentPos, dataLength, BluetoothUuid.UUID_BYTES_16_BIT, mServiceUuids);
break;
case DATA_TYPE_SERVICE_UUIDS_32_BIT_PARTIAL:
case DATA_TYPE_SERVICE_UUIDS_32_BIT_COMPLETE:
parseServiceUuid(scanRecord, currentPos, dataLength, BluetoothUuid.UUID_BYTES_32_BIT, mServiceUuids);
break;
case DATA_TYPE_SERVICE_UUIDS_128_BIT_PARTIAL:
case DATA_TYPE_SERVICE_UUIDS_128_BIT_COMPLETE:
parseServiceUuid(scanRecord, currentPos, dataLength, BluetoothUuid.UUID_BYTES_128_BIT, mServiceUuids);
break;
case DATA_TYPE_SERVICE_DATA_16_BIT:
case DATA_TYPE_SERVICE_DATA_32_BIT:
case DATA_TYPE_SERVICE_DATA_128_BIT:
int serviceUuidLength = BluetoothUuid.UUID_BYTES_16_BIT;
if (fieldType == DATA_TYPE_SERVICE_DATA_32_BIT) {
serviceUuidLength = BluetoothUuid.UUID_BYTES_32_BIT;
} else if (fieldType == DATA_TYPE_SERVICE_DATA_128_BIT) {
serviceUuidLength = BluetoothUuid.UUID_BYTES_128_BIT;
}
final byte[] serviceDataUuidBytes = extractBytes(scanRecord, currentPos,
serviceUuidLength);
final ParcelUuid serviceDataUuid = BluetoothUuid.parseUuidFrom(
serviceDataUuidBytes);
final byte[] serviceDataArray = extractBytes(scanRecord,
currentPos + serviceUuidLength, dataLength - serviceUuidLength);
if (mServiceData == null)
mServiceData = new HashMap<>();
mServiceData.put(serviceDataUuid, serviceDataArray);
break;
case DATA_TYPE_LOCAL_NAME_SHORT:
case DATA_TYPE_LOCAL_NAME_COMPLETE:
mDeviceName = new String(extractBytes(scanRecord, currentPos, dataLength));
break;
case DATA_TYPE_MANUFACTURER_SPECIFIC_DATA:
if (id == -1) {
byte[] bytes = extractBytes(scanRecord, currentPos, dataLength);
mManufacturerByte.add(bytes);
} else {
int manufacturerId = ((scanRecord[currentPos + 1] & 0xFF) << 8) + (scanRecord[currentPos] & 0xFF);
if (manufacturerId == id) {
byte[] bytes = extractBytes(scanRecord, currentPos, dataLength);
mManufacturerByte.add(bytes);
} else {
currentPos += dataLength;
}
}
break;
case DATA_TYPE_MANUFACTURER_SPECIFIC_DATA_MOVE:
mManufacturerByteMove = extractBytes(scanRecord, currentPos, dataLength);
break;
default:
break;
}
currentPos += dataLength;
}
} catch (Exception e) {
mServiceUuids = null;
mManufacturerByte = null;
e.printStackTrace();
}
if (mServiceUuids!=null&&mServiceUuids.isEmpty()) {
mServiceUuids = null;
}
}
// Parse service UUIDs.
private static int parseServiceUuid(byte[] scanRecord, int currentPos, int dataLength, int uuidLength, List serviceUuids) {
while (dataLength > 0) {
byte[] uuidBytes = extractBytes(scanRecord, currentPos, uuidLength);
serviceUuids.add(BluetoothUuid.parseUuidFrom(uuidBytes));
dataLength -= uuidLength;
currentPos += uuidLength;
}
return currentPos;
}
}