@@ -4,18 +4,16 @@ | |||
<component name="GradleSettings"> | |||
<option name="linkedExternalProjectsSettings"> | |||
<GradleProjectSettings> | |||
<option name="testRunner" value="PLATFORM" /> | |||
<option name="testRunner" value="GRADLE" /> | |||
<option name="distributionType" value="DEFAULT_WRAPPED" /> | |||
<option name="externalProjectPath" value="$PROJECT_DIR$" /> | |||
<option name="gradleHome" value="$APPLICATION_HOME_DIR$/gradle/gradle-5.1.1" /> | |||
<option name="gradleJvm" value="Embedded JDK" /> | |||
<option name="modules"> | |||
<set> | |||
<option value="$PROJECT_DIR$" /> | |||
<option value="$PROJECT_DIR$/app" /> | |||
</set> | |||
</option> | |||
<option name="resolveModulePerSourceSet" value="false" /> | |||
<option name="useQualifiedModuleNames" value="true" /> | |||
</GradleProjectSettings> | |||
</option> | |||
</component> |
@@ -5,7 +5,7 @@ | |||
<configuration PROFILE_NAME="Debug" CONFIG_NAME="Debug" /> | |||
</configurations> | |||
</component> | |||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK"> | |||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="corretto-1.8" project-jdk-type="JavaSDK"> | |||
<output url="file://$PROJECT_DIR$/build/classes" /> | |||
</component> | |||
<component name="ProjectType"> |
@@ -1,12 +0,0 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<project version="4"> | |||
<component name="RunConfigurationProducerService"> | |||
<option name="ignoredProducers"> | |||
<set> | |||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" /> | |||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" /> | |||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" /> | |||
</set> | |||
</option> | |||
</component> | |||
</project> |
@@ -0,0 +1,208 @@ | |||
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<br> | |||
* 2019/3/7<br> | |||
* 广播解析工具类 | |||
*/ | |||
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<byte[]> mManufacturerByte; | |||
private byte[] mManufacturerByteMove; | |||
private List<ParcelUuid> mServiceUuids; | |||
private int mAdvertiseFlag = -1; | |||
private Map<ParcelUuid, byte[]> 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<byte[]> getManufacturerSpecificData() { | |||
return mManufacturerByte; | |||
} | |||
public byte[] getManufacturerByteMove() { | |||
return mManufacturerByteMove; | |||
} | |||
/** | |||
* 服务uuid | |||
* | |||
* @return {@link List}<{@link ParcelUuid}> | |||
*/ | |||
public List<ParcelUuid> getServiceUuids() { | |||
return mServiceUuids; | |||
} | |||
/** | |||
* 广告标志 | |||
* | |||
* @return int | |||
*/ | |||
public int getAdvertiseFlag() { | |||
return mAdvertiseFlag; | |||
} | |||
public String getDeviceName() { | |||
return mDeviceName; | |||
} | |||
/** | |||
* 服务数据 | |||
* | |||
* @return {@link Map}<{@link ParcelUuid}, {@link byte[]}> | |||
*/ | |||
public Map<ParcelUuid, byte[]> 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<ParcelUuid> serviceUuids) { | |||
while (dataLength > 0) { | |||
byte[] uuidBytes = extractBytes(scanRecord, currentPos, uuidLength); | |||
serviceUuids.add(BluetoothUuid.parseUuidFrom(uuidBytes)); | |||
dataLength -= uuidLength; | |||
currentPos += uuidLength; | |||
} | |||
return currentPos; | |||
} | |||
} |
@@ -0,0 +1,303 @@ | |||
/* | |||
* Copyright (C) 2009 The Android Open Source Project | |||
* | |||
* Licensed under the Apache License, Version 2.0 (the "License"); | |||
* you may not use this file except in compliance with the License. | |||
* You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
package com.elinkthings.ailinksecrettooldemo; | |||
import android.os.ParcelUuid; | |||
import java.nio.ByteBuffer; | |||
import java.nio.ByteOrder; | |||
import java.util.Arrays; | |||
import java.util.HashSet; | |||
import java.util.UUID; | |||
/** | |||
* Static helper methods and constants to decode the ParcelUuid of remote devices. | |||
* @hide | |||
*/ | |||
public final class BluetoothUuid { | |||
/* See Bluetooth Assigned Numbers document - SDP section, to get the values of UUIDs | |||
* for the various services. | |||
* | |||
* The following 128 bit values are calculated as: | |||
* uuid * 2^96 + BASE_UUID | |||
*/ | |||
public static final ParcelUuid AudioSink = | |||
ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB"); | |||
public static final ParcelUuid AudioSource = | |||
ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB"); | |||
public static final ParcelUuid AdvAudioDist = | |||
ParcelUuid.fromString("0000110D-0000-1000-8000-00805F9B34FB"); | |||
public static final ParcelUuid HSP = | |||
ParcelUuid.fromString("00001108-0000-1000-8000-00805F9B34FB"); | |||
public static final ParcelUuid HSP_AG = | |||
ParcelUuid.fromString("00001112-0000-1000-8000-00805F9B34FB"); | |||
public static final ParcelUuid Handsfree = | |||
ParcelUuid.fromString("0000111E-0000-1000-8000-00805F9B34FB"); | |||
public static final ParcelUuid Handsfree_AG = | |||
ParcelUuid.fromString("0000111F-0000-1000-8000-00805F9B34FB"); | |||
public static final ParcelUuid AvrcpController = | |||
ParcelUuid.fromString("0000110E-0000-1000-8000-00805F9B34FB"); | |||
public static final ParcelUuid AvrcpTarget = | |||
ParcelUuid.fromString("0000110C-0000-1000-8000-00805F9B34FB"); | |||
public static final ParcelUuid ObexObjectPush = | |||
ParcelUuid.fromString("00001105-0000-1000-8000-00805f9b34fb"); | |||
public static final ParcelUuid Hid = | |||
ParcelUuid.fromString("00001124-0000-1000-8000-00805f9b34fb"); | |||
public static final ParcelUuid Hogp = | |||
ParcelUuid.fromString("00001812-0000-1000-8000-00805f9b34fb"); | |||
public static final ParcelUuid PANU = | |||
ParcelUuid.fromString("00001115-0000-1000-8000-00805F9B34FB"); | |||
public static final ParcelUuid NAP = | |||
ParcelUuid.fromString("00001116-0000-1000-8000-00805F9B34FB"); | |||
public static final ParcelUuid BNEP = | |||
ParcelUuid.fromString("0000000f-0000-1000-8000-00805F9B34FB"); | |||
public static final ParcelUuid PBAP_PCE = | |||
ParcelUuid.fromString("0000112e-0000-1000-8000-00805F9B34FB"); | |||
public static final ParcelUuid PBAP_PSE = | |||
ParcelUuid.fromString("0000112f-0000-1000-8000-00805F9B34FB"); | |||
public static final ParcelUuid MAP = | |||
ParcelUuid.fromString("00001134-0000-1000-8000-00805F9B34FB"); | |||
public static final ParcelUuid MNS = | |||
ParcelUuid.fromString("00001133-0000-1000-8000-00805F9B34FB"); | |||
public static final ParcelUuid MAS = | |||
ParcelUuid.fromString("00001132-0000-1000-8000-00805F9B34FB"); | |||
public static final ParcelUuid BASE_UUID = | |||
ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB"); | |||
/** Length of bytes for 16 bit UUID */ | |||
public static final int UUID_BYTES_16_BIT = 2; | |||
/** Length of bytes for 32 bit UUID */ | |||
public static final int UUID_BYTES_32_BIT = 4; | |||
/** Length of bytes for 128 bit UUID */ | |||
public static final int UUID_BYTES_128_BIT = 16; | |||
public static final ParcelUuid[] RESERVED_UUIDS = { | |||
AudioSink, AudioSource, AdvAudioDist, HSP, Handsfree, AvrcpController, AvrcpTarget, | |||
ObexObjectPush, PANU, NAP, MAP, MNS, MAS}; | |||
public static boolean isAudioSource(ParcelUuid uuid) { | |||
return uuid.equals(AudioSource); | |||
} | |||
public static boolean isAudioSink(ParcelUuid uuid) { | |||
return uuid.equals(AudioSink); | |||
} | |||
public static boolean isAdvAudioDist(ParcelUuid uuid) { | |||
return uuid.equals(AdvAudioDist); | |||
} | |||
public static boolean isHandsfree(ParcelUuid uuid) { | |||
return uuid.equals(Handsfree); | |||
} | |||
public static boolean isHeadset(ParcelUuid uuid) { | |||
return uuid.equals(HSP); | |||
} | |||
public static boolean isAvrcpController(ParcelUuid uuid) { | |||
return uuid.equals(AvrcpController); | |||
} | |||
public static boolean isAvrcpTarget(ParcelUuid uuid) { | |||
return uuid.equals(AvrcpTarget); | |||
} | |||
public static boolean isInputDevice(ParcelUuid uuid) { | |||
return uuid.equals(Hid); | |||
} | |||
public static boolean isPanu(ParcelUuid uuid) { | |||
return uuid.equals(PANU); | |||
} | |||
public static boolean isNap(ParcelUuid uuid) { | |||
return uuid.equals(NAP); | |||
} | |||
public static boolean isBnep(ParcelUuid uuid) { | |||
return uuid.equals(BNEP); | |||
} | |||
public static boolean isMap(ParcelUuid uuid) { | |||
return uuid.equals(MAP); | |||
} | |||
public static boolean isMns(ParcelUuid uuid) { | |||
return uuid.equals(MNS); | |||
} | |||
public static boolean isMas(ParcelUuid uuid) { | |||
return uuid.equals(MAS); | |||
} | |||
/** | |||
* Returns true if ParcelUuid is present in uuidArray | |||
* | |||
* @param uuidArray - Array of ParcelUuids | |||
* @param uuid | |||
*/ | |||
public static boolean isUuidPresent(ParcelUuid[] uuidArray, ParcelUuid uuid) { | |||
if ((uuidArray == null || uuidArray.length == 0) && uuid == null) | |||
return true; | |||
if (uuidArray == null) | |||
return false; | |||
for (ParcelUuid element: uuidArray) { | |||
if (element.equals(uuid)) return true; | |||
} | |||
return false; | |||
} | |||
/** | |||
* Returns true if there any common ParcelUuids in uuidA and uuidB. | |||
* | |||
* @param uuidA - List of ParcelUuids | |||
* @param uuidB - List of ParcelUuids | |||
* | |||
*/ | |||
public static boolean containsAnyUuid(ParcelUuid[] uuidA, ParcelUuid[] uuidB) { | |||
if (uuidA == null && uuidB == null) return true; | |||
if (uuidA == null) { | |||
return uuidB.length == 0 ? true : false; | |||
} | |||
if (uuidB == null) { | |||
return uuidA.length == 0 ? true : false; | |||
} | |||
HashSet<ParcelUuid> uuidSet = new HashSet<ParcelUuid>(Arrays.asList(uuidA)); | |||
for (ParcelUuid uuid: uuidB) { | |||
if (uuidSet.contains(uuid)) return true; | |||
} | |||
return false; | |||
} | |||
/** | |||
* Returns true if all the ParcelUuids in ParcelUuidB are present in | |||
* ParcelUuidA | |||
* | |||
* @param uuidA - Array of ParcelUuidsA | |||
* @param uuidB - Array of ParcelUuidsB | |||
* | |||
*/ | |||
public static boolean containsAllUuids(ParcelUuid[] uuidA, ParcelUuid[] uuidB) { | |||
if (uuidA == null && uuidB == null) return true; | |||
if (uuidA == null) { | |||
return uuidB.length == 0 ? true : false; | |||
} | |||
if (uuidB == null) return true; | |||
HashSet<ParcelUuid> uuidSet = new HashSet<ParcelUuid>(Arrays.asList(uuidA)); | |||
for (ParcelUuid uuid: uuidB) { | |||
if (!uuidSet.contains(uuid)) return false; | |||
} | |||
return true; | |||
} | |||
/** | |||
* Extract the Service Identifier or the actual uuid from the Parcel Uuid. | |||
* For example, if 0000110B-0000-1000-8000-00805F9B34FB is the parcel Uuid, | |||
* this function will return 110B | |||
* @param parcelUuid | |||
* @return the service identifier. | |||
*/ | |||
public static int getServiceIdentifierFromParcelUuid(ParcelUuid parcelUuid) { | |||
UUID uuid = parcelUuid.getUuid(); | |||
long value = (uuid.getMostSignificantBits() & 0x0000FFFF00000000L) >>> 32; | |||
return (int)value; | |||
} | |||
/** | |||
* Parse UUID from bytes. The {@code uuidBytes} can represent a 16-bit, 32-bit or 128-bit UUID, | |||
* but the returned UUID is always in 128-bit format. | |||
* Note UUID is little endian in Bluetooth. | |||
* | |||
* @param uuidBytes Byte representation of uuid. | |||
* @return {@link ParcelUuid} parsed from bytes. | |||
* @throws IllegalArgumentException If the {@code uuidBytes} cannot be parsed. | |||
*/ | |||
public static ParcelUuid parseUuidFrom(byte[] uuidBytes) { | |||
if (uuidBytes == null) { | |||
throw new IllegalArgumentException("uuidBytes cannot be null"); | |||
} | |||
int length = uuidBytes.length; | |||
if (length != UUID_BYTES_16_BIT && length != UUID_BYTES_32_BIT && | |||
length != UUID_BYTES_128_BIT) { | |||
throw new IllegalArgumentException("uuidBytes length invalid - " + length); | |||
} | |||
// Construct a 128 bit UUID. | |||
if (length == UUID_BYTES_128_BIT) { | |||
ByteBuffer buf = ByteBuffer.wrap(uuidBytes).order(ByteOrder.LITTLE_ENDIAN); | |||
long msb = buf.getLong(8); | |||
long lsb = buf.getLong(0); | |||
return new ParcelUuid(new UUID(msb, lsb)); | |||
} | |||
// For 16 bit and 32 bit UUID we need to convert them to 128 bit value. | |||
// 128_bit_value = uuid * 2^96 + BASE_UUID | |||
long shortUuid; | |||
if (length == UUID_BYTES_16_BIT) { | |||
shortUuid = uuidBytes[0] & 0xFF; | |||
shortUuid += (uuidBytes[1] & 0xFF) << 8; | |||
} else { | |||
shortUuid = uuidBytes[0] & 0xFF ; | |||
shortUuid += (uuidBytes[1] & 0xFF) << 8; | |||
shortUuid += (uuidBytes[2] & 0xFF) << 16; | |||
shortUuid += (uuidBytes[3] & 0xFF) << 24; | |||
} | |||
long msb = BASE_UUID.getUuid().getMostSignificantBits() + (shortUuid << 32); | |||
long lsb = BASE_UUID.getUuid().getLeastSignificantBits(); | |||
return new ParcelUuid(new UUID(msb, lsb)); | |||
} | |||
/** | |||
* Check whether the given parcelUuid can be converted to 16 bit bluetooth uuid. | |||
* | |||
* @param parcelUuid | |||
* @return true if the parcelUuid can be converted to 16 bit uuid, false otherwise. | |||
*/ | |||
public static boolean is16BitUuid(ParcelUuid parcelUuid) { | |||
UUID uuid = parcelUuid.getUuid(); | |||
if (uuid.getLeastSignificantBits() != BASE_UUID.getUuid().getLeastSignificantBits()) { | |||
return false; | |||
} | |||
return ((uuid.getMostSignificantBits() & 0xFFFF0000FFFFFFFFL) == 0x1000L); | |||
} | |||
/** | |||
* Check whether the given parcelUuid can be converted to 32 bit bluetooth uuid. | |||
* | |||
* @param parcelUuid | |||
* @return true if the parcelUuid can be converted to 32 bit uuid, false otherwise. | |||
*/ | |||
public static boolean is32BitUuid(ParcelUuid parcelUuid) { | |||
UUID uuid = parcelUuid.getUuid(); | |||
if (uuid.getLeastSignificantBits() != BASE_UUID.getUuid().getLeastSignificantBits()) { | |||
return false; | |||
} | |||
if (is16BitUuid(parcelUuid)) { | |||
return false; | |||
} | |||
return ((uuid.getMostSignificantBits() & 0xFFFFFFFFL) == 0x1000L); | |||
} | |||
} |
@@ -26,6 +26,8 @@ import android.os.Looper; | |||
import android.os.Message; | |||
import android.os.ParcelUuid; | |||
import android.provider.Settings; | |||
import android.util.Log; | |||
import android.util.SparseArray; | |||
import android.view.View; | |||
import android.widget.AdapterView; | |||
import android.widget.ArrayAdapter; | |||
@@ -48,6 +50,8 @@ import androidx.core.app.ActivityCompat; | |||
public class MainActivity extends AppCompatActivity implements View.OnClickListener, OnAnalyticalListener { | |||
private static final String TAG = "MainActivity"; | |||
/** | |||
* 停止搜索 | |||
*/ | |||
@@ -161,10 +165,11 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe | |||
for (byte aB : b) { | |||
int a = aB & 0XFF; | |||
stmp = Integer.toHexString(a); | |||
if (stmp.length() == 1) | |||
if (stmp.length() == 1) { | |||
hs = hs + "0" + stmp + " "; | |||
else | |||
} else { | |||
hs = hs + stmp + " "; | |||
} | |||
} | |||
return hs; | |||
} | |||
@@ -260,14 +265,18 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe | |||
List<ScanFilter> filters = new ArrayList<>(); | |||
if (scanUUID != null && scanUUID.length > 0) { | |||
for (UUID uuid : scanUUID) { | |||
ScanFilter filter = new ScanFilter.Builder().setServiceUuid(new ParcelUuid(uuid)).build(); | |||
ScanFilter filter = new ScanFilter.Builder().setServiceUuid(new ParcelUuid(uuid)) | |||
.build(); | |||
filters.add(filter); | |||
} | |||
} | |||
if (mScanCallback == null) | |||
if (mScanCallback == null) { | |||
mScanCallback = new MyScanCallback(); | |||
ScanSettings settings = new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build(); | |||
mBluetoothAdapter.getBluetoothLeScanner().startScan(filters, settings, mScanCallback); | |||
} | |||
ScanSettings settings = new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) | |||
.build(); | |||
mBluetoothAdapter.getBluetoothLeScanner() | |||
.startScan(filters, settings, mScanCallback); | |||
} else { | |||
mBluetoothAdapter.startLeScan(mLeScanCallback); | |||
} | |||
@@ -327,12 +336,18 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe | |||
public void onScanResult(int callbackType, ScanResult result) { | |||
super.onScanResult(callbackType, result); | |||
String address = result.getDevice().getAddress(); | |||
saveScanData(address); | |||
// SparseArray<byte[]> manufacturerSpecificData = result.getScanRecord().getManufacturerSpecificData();//获取自定义厂商数据列表,正常情况只有1个 | |||
// if (manufacturerSpecificData.size() > 0) { | |||
// byte[] data = manufacturerSpecificData.get(0); | |||
// decryptBroadcastExample(data); | |||
// } | |||
// saveScanData(address); | |||
//获取自定义厂商数据列表,正常情况只有1个 | |||
BleBroadcastUtils bleBroadcastUtils = new BleBroadcastUtils(result.getScanRecord().getBytes()); | |||
List<byte[]> manufacturerSpecificData = bleBroadcastUtils.getManufacturerSpecificData(); | |||
if (manufacturerSpecificData.size() > 0) { | |||
byte[] data = manufacturerSpecificData.get(0); | |||
if (data != null) { | |||
decryptBroadcastExample(data); | |||
} | |||
} | |||
} | |||
@@ -353,10 +368,12 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe | |||
/** | |||
* 解密广播数据参考例子 | |||
* | |||
* @param data 自定义厂商数据 | |||
*/ | |||
private void decryptBroadcastExample(byte[] data){ | |||
byte[] decryptData= mAnalyticalDataUtil.decryptBroadcast(data);//获取解密后的数据 | |||
private void decryptBroadcastExample(byte[] data) { | |||
byte[] decryptData = mAnalyticalDataUtil.decryptBroadcast(data);//获取解密后的数据 | |||
Log.i(TAG, "decryptBroadcastExample: " + byte2HexStr(decryptData)); | |||
} | |||
@@ -5,7 +5,7 @@ buildscript { | |||
jcenter() | |||
} | |||
dependencies { | |||
classpath "com.android.tools.build:gradle:4.0.1" | |||
classpath 'com.android.tools.build:gradle:7.1.2' | |||
// NOTE: Do not place your application dependencies here; they belong | |||
// in the individual module build.gradle files |
@@ -1,6 +1,6 @@ | |||
#Thu Apr 22 19:01:02 CST 2021 | |||
#Fri Dec 01 15:14:20 CST 2023 | |||
distributionBase=GRADLE_USER_HOME | |||
distributionPath=wrapper/dists | |||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip | |||
zipStoreBase=GRADLE_USER_HOME | |||
zipStorePath=wrapper/dists | |||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip |