Android 解析蓝牙广播数据

buffer.append(key).append(“=”).append(Arrays.toString(map.get(key)));

if (it.hasNext()) {

buffer.append(", ");

}

}

buffer.append(‘}’);

return buffer.toString();

}

private static final String TAG = “ScanRecordUtil”;

// The following data type values are assigned by Bluetooth SIG.

// For more details refer to Bluetooth 4.1 specification, Volume 3, Part C, Section 18.

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 = 0x16;

private static final int DATA_TYPE_MANUFACTURER_SPECIFIC_DATA = 0xFF;

// Flags of the advertising data.

private final int mAdvertiseFlags;

@Nullable

private final List mServiceUuids;

private final SparseArray<byte[]> mManufacturerSpecificData;

private final Map<ParcelUuid, byte[]> mServiceData;

// Transmission power level(in dB).

private final int mTxPowerLevel;

// Local name of the Bluetooth LE device.

private final String mDeviceName;

// Raw bytes of scan record.

private final byte[] mBytes;

/**

  • Returns the advertising flags indicating the discoverable mode and capability of the device.

  • Returns -1 if the flag field is not set.

*/

public int getAdvertiseFlags() {

return mAdvertiseFlags;

}

/**

  • Returns a list of service UUIDs within the advertisement that are used to identify the

  • bluetooth GATT services.

*/

public List getServiceUuids() {

return mServiceUuids;

}

/**

  • Returns a sparse array of manufacturer identifier and its corresponding manufacturer specific

  • data.

*/

public SparseArray<byte[]> getManufacturerSpecificData() {

return mManufacturerSpecificData;

}

/**

  • Returns the manufacturer specific data associated with the manufacturer id. Returns

  • {@code null} if the {@code manufacturerId} is not found.

*/

@Nullable

public byte[] getManufacturerSpecificData(int manufacturerId) {

return mManufacturerSpecificData.get(manufacturerId);

}

/**

  • Returns a map of service UUID and its corresponding service data.

*/

public Map<ParcelUuid, byte[]> getServiceData() {

return mServiceData;

}

/**

  • Returns the service data byte array associated with the {@code serviceUuid}. Returns

  • {@code null} if the {@code serviceDataUuid} is not found.

*/

@Nullable

public byte[] getServiceData(ParcelUuid serviceDataUuid) {

if (serviceDataUuid == null) {

return null;

}

return mServiceData.get(serviceDataUuid);

}

/**

  • Returns the transmission power level of the packet in dBm. Returns {@link Integer#MIN_VALUE}

  • if the field is not set. This value can be used to calculate the path loss of a received

  • packet using the following equation:

  • pathloss = txPowerLevel - rssi

*/

public int getTxPowerLevel() {

return mTxPowerLevel;

}

/**

  • Returns the local name of the BLE device. The is a UTF-8 encoded string.

*/

@Nullable

public String getDeviceName() {

return mDeviceName;

}

/**

  • Returns raw bytes of scan record.

*/

public byte[] getBytes() {

return mBytes;

}

private ScanRecordUtil(List serviceUuids,

SparseArray<byte[]> manufacturerData,

Map<ParcelUuid, byte[]> serviceData,

int advertiseFlags, int txPowerLevel,

String localName, byte[] bytes) {

mServiceUuids = serviceUuids;

mManufacturerSpecificData = manufacturerData;

mServiceData = serviceData;

mDeviceName = localName;

mAdvertiseFlags = advertiseFlags;

mTxPowerLevel = txPowerLevel;

mBytes = bytes;

}

/**

  • Parse scan record bytes to {@link ScanRecord}.

  • The format is defined in Bluetooth 4.1 specification, Volume 3, Part C, Section 11 and 18.

  • All numerical multi-byte entities and values shall use little-endian byte

  • order.

  • @param scanRecord The scan record of Bluetooth LE advertisement and/or scan response.

  • @hide

*/

public static ScanRecordUtil parseFromBytes(byte[] scanRecord) {

if (scanRecord == null) {

return null;

}

Log.e(TAG + “MYX23P”, “进入parseFromBytes”);

int currentPos = 0;

int advertiseFlag = -1;

List serviceUuids = new ArrayList();

String localName = null;

int txPowerLevel = Integer.MIN_VALUE;

SparseArray<byte[]> manufacturerData = new SparseArray<byte[]>();

Map<ParcelUuid, byte[]> serviceData = new ArrayMap<ParcelUuid, byte[]>();

try {

while (currentPos < scanRecord.length) {

// length is unsigned int.

int length = scanRecord[currentPos++] & 0xFF;

if (length == 0) {

break;

}

// Note the length includes the length of the field type itself.

int dataLength = length - 1;

// fieldType is unsigned int.

int fieldType = scanRecord[currentPos++] & 0xFF;

switch (fieldType) {

case DATA_TYPE_FLAGS:

advertiseFlag = scanRecord[currentPos] & 0xFF;

break;

case DATA_TYPE_SERVICE_UUIDS_16_BIT_PARTIAL:

case DATA_TYPE_SERVICE_UUIDS_16_BIT_COMPLETE:

parseServiceUuid(scanRecord, currentPos,

dataLength,16, serviceUuids);

break;

case DATA_TYPE_SERVICE_UUIDS_32_BIT_PARTIAL:

case DATA_TYPE_SERVICE_UUIDS_32_BIT_COMPLETE:

parseServiceUuid(scanRecord, currentPos, dataLength,

32, serviceUuids);

break;

case DATA_TYPE_SERVICE_UUIDS_128_BIT_PARTIAL:

case DATA_TYPE_SERVICE_UUIDS_128_BIT_COMPLETE:

parseServiceUuid(scanRecord, currentPos, dataLength,

128, serviceUuids);

break;

case DATA_TYPE_LOCAL_NAME_SHORT:

case DATA_TYPE_LOCAL_NAME_COMPLETE:

localName = new String(

extractBytes(scanRecord, currentPos, dataLength));

break;

case DATA_TYPE_TX_POWER_LEVEL:

txPowerLevel = scanRecord[currentPos];

break;

case DATA_TYPE_SERVICE_DATA:

// The first two bytes of the service data are service data UUID in little

// endian. The rest bytes are service data.

int serviceUuidLength = 16;

byte[] serviceDataUuidBytes = extractBytes(scanRecord, currentPos,

serviceUuidLength);

ParcelUuid serviceDataUuid = parseUuidFrom(

serviceDataUuidBytes);

byte[] serviceDataArray = extractBytes(scanRecord,

currentPos + serviceUuidLength, dataLength - serviceUuidLength);

serviceData.put(serviceDataUuid, serviceDataArray);

break;

case DATA_TYPE_MANUFACTURER_SPECIFIC_DATA:

// The first two bytes of the manufacturer specific data are

// manufacturer ids in little endian.

int manufacturerId = ((scanRecord[currentPos + 1] & 0xFF) << 8) +

(scanRecord[currentPos] & 0xFF);

byte[] manufacturerDataBytes = extractBytes(scanRecord, currentPos + 2,

dataLength - 2);

manufacturerData.put(manufacturerId, manufacturerDataBytes);

break;

default:

// Just ignore, we don’t handle such data type.

break;

}

currentPos += dataLength;

}

if (serviceUuids.isEmpty()) {

serviceUuids = null;

}

return new ScanRecordUtil(serviceUuids, manufacturerData, serviceData,

advertiseFlag, txPowerLevel, localName, scanRecord);

} catch (Exception e) {

Log.e(TAG, "unable to parse scan record: " + Arrays.toString(scanRecord));

// As the record is invalid, ignore all the parsed results for this packet

// and return an empty record with raw scanRecord bytes in results

return new ScanRecordUtil(null, null, null, -1, Integer.MIN_VALUE, null, scanRecord);

}

}

@Override

public String toString() {

return “ScanRecord [mAdvertiseFlags=” + mAdvertiseFlags + “, mServiceUuids=” + mServiceUuids

  • “, mManufacturerSpecificData=” + ScanRecordUtil.toString(mManufacturerSpecificData)

  • “, mServiceData=” + ScanRecordUtil.toString(mServiceData)

  • “, mTxPowerLevel=” + mTxPowerLevel + “, mDeviceName=” + mDeviceName + “]”;

}

/**

  • byte数组转化为string

*/

static final char[] hexArray = “0123456789ABCDEF”.toCharArray();

public static String bytesToHex(byte[] bytes) {

char[] hexChars = new char[bytes.length * 2];

for (int j = 0; j < bytes.length; j++) {

int v = bytes[j] & 0xFF;

hexChars[j * 2] = hexArray[v >>> 4];

hexChars[j * 2 + 1] = hexArray[v & 0x0F];

}

return new String(hexChars);

}

// 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(parseUuidFrom(uuidBytes));

dataLength -= uuidLength;
先自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以扫码领取!!!!

文末

今天关于面试的分享就到这里,还是那句话,有些东西你不仅要懂,而且要能够很好地表达出来,能够让面试官认可你的理解,例如Handler机制,这个是面试必问之题。有些晦涩的点,或许它只活在面试当中,实际工作当中你压根不会用到它,但是你要知道它是什么东西。

最后在这里小编分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司2021年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

还有 高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

【Android核心高级技术PDF文档,BAT大厂面试真题解析】

【算法合集】

【延伸Android必备知识点】

【Android部分高级架构视频学习资源】

Android精讲视频领取学习后更加是如虎添翼!进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》
点击传送门,即可免费领取!

节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

【Android核心高级技术PDF文档,BAT大厂面试真题解析】

[外链图片转存中…(img-M8U2srA5-1711221102561)]

【算法合集】

[外链图片转存中…(img-CR8G3nKU-1711221102562)]

【延伸Android必备知识点】

[外链图片转存中…(img-Ud1u7Jcg-1711221102562)]

【Android部分高级架构视频学习资源】

Android精讲视频领取学习后更加是如虎添翼!进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》
点击传送门,即可免费领取!

  • 11
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值