|
|
@ -28,12 +28,15 @@ import androidx.core.app.ActivityCompat; |
|
|
|
import androidx.core.content.ContextCompat; |
|
|
|
|
|
|
|
import com.iflytop.profilometer.core.migration.channel.BleDeviceUartChannel; |
|
|
|
import com.iflytop.profilometer.core.system.DeviceState; |
|
|
|
import com.iflytop.profilometer.core.system.SystemService; |
|
|
|
|
|
|
|
import java.util.ArrayList; |
|
|
|
import java.util.HashMap; |
|
|
|
import java.util.HashSet; |
|
|
|
import java.util.List; |
|
|
|
import java.util.Map; |
|
|
|
import java.util.Set; |
|
|
|
import java.util.UUID; |
|
|
|
|
|
|
|
/** |
|
|
@ -48,8 +51,10 @@ public class BleManager { |
|
|
|
private final BluetoothManager bluetoothManager; |
|
|
|
private BluetoothAdapter bluetoothAdapter; |
|
|
|
private BluetoothLeScanner bluetoothLeScanner; |
|
|
|
// 仅添加支持目标服务的设备 |
|
|
|
private final List<BluetoothDevice> scannedDevices = new ArrayList<>(); |
|
|
|
private ScanCallback scanCallback; |
|
|
|
// 设备连接后的通信回调(用于 connectToDevice 方法) |
|
|
|
private BluetoothGatt bluetoothGatt; |
|
|
|
private final Context context; |
|
|
|
|
|
|
@ -60,13 +65,15 @@ public class BleManager { |
|
|
|
public static final UUID CLIENT_CHARACTERISTIC_CONFIG_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"); |
|
|
|
|
|
|
|
//【扫描时设备实时性管理】 |
|
|
|
// 超时阈值:10秒内未更新则认为设备已消失 |
|
|
|
private static final long DEVICE_TIMEOUT = 10000; |
|
|
|
// 超时阈值:20秒内未更新则认为设备已消失 |
|
|
|
private static final long DEVICE_TIMEOUT = 20000; |
|
|
|
// 清理间隔:每5秒执行一次清理任务 |
|
|
|
private static final long CLEANUP_INTERVAL = 5000; |
|
|
|
private final Handler cleanupHandler = new Handler(Looper.getMainLooper()); |
|
|
|
// 记录设备最后出现时间 |
|
|
|
private final Map<BluetoothDevice, Long> deviceLastSeenMap = new HashMap<>(); |
|
|
|
// 记录已经进行服务查询的设备(以 MAC 地址为 key),避免重复连接 |
|
|
|
private final Set<String> processedDevices = new HashSet<>(); |
|
|
|
|
|
|
|
// 数据回调接口,外部可以通过此接口接收 BLE 设备返回的数据 |
|
|
|
public interface BleDataListener { |
|
|
@ -85,7 +92,7 @@ public class BleManager { |
|
|
|
this.bleDataListener = listener; |
|
|
|
} |
|
|
|
|
|
|
|
// 定时清理 Runnable |
|
|
|
// 定时清理 Runnable,移除超时设备,同时清除 processedDevices 中的记录 |
|
|
|
private final Runnable cleanupRunnable = new Runnable() { |
|
|
|
@SuppressLint("MissingPermission") |
|
|
|
@Override |
|
|
@ -101,6 +108,7 @@ public class BleManager { |
|
|
|
for (BluetoothDevice device : toRemove) { |
|
|
|
deviceLastSeenMap.remove(device); |
|
|
|
scannedDevices.remove(device); |
|
|
|
processedDevices.remove(device.getAddress()); |
|
|
|
Log.d(TAG, "移除超时设备: " + device.getName() + " - " + device.getAddress()); |
|
|
|
} |
|
|
|
} |
|
|
@ -108,7 +116,7 @@ public class BleManager { |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
// BluetoothGattCallback 处理连接、服务发现、通知及数据写入结果 |
|
|
|
// 原有的 BluetoothGattCallback 用于设备连接后的通信处理 |
|
|
|
private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() { |
|
|
|
@SuppressLint("MissingPermission") |
|
|
|
@Override |
|
|
@ -119,6 +127,8 @@ public class BleManager { |
|
|
|
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) { |
|
|
|
Log.d(TAG, "设备已断开连接"); |
|
|
|
bluetoothGatt = null; |
|
|
|
DeviceState deviceState = SystemService.getInstance().getDeviceState(); |
|
|
|
deviceState.setConnected(false); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -147,10 +157,8 @@ public class BleManager { |
|
|
|
|
|
|
|
@Override |
|
|
|
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { |
|
|
|
// 收到通知数据后,将数据通过回调接口传递出去 |
|
|
|
if (NOTIFY_CHARACTERISTIC_UUID.equals(characteristic.getUuid())) { |
|
|
|
byte[] data = characteristic.getValue(); |
|
|
|
// Log.d(TAG, "收到通知数据: " + new String(data)); |
|
|
|
if (bleDataListener != null) { |
|
|
|
bleDataListener.onDataReceived(data); |
|
|
|
} |
|
|
@ -160,7 +168,7 @@ public class BleManager { |
|
|
|
@Override |
|
|
|
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { |
|
|
|
if (status == BluetoothGatt.GATT_SUCCESS) { |
|
|
|
// Log.d(TAG, "数据写入成功"); |
|
|
|
// 数据写入成功 |
|
|
|
} else { |
|
|
|
Log.e(TAG, "数据写入失败,错误码:" + status); |
|
|
|
} |
|
|
@ -168,6 +176,51 @@ public class BleManager { |
|
|
|
}; |
|
|
|
|
|
|
|
/** |
|
|
|
* 内部类:用于扫描过程中连接设备后进行服务查询,判断设备是否支持目标服务 |
|
|
|
*/ |
|
|
|
private class ServiceDiscoveryGattCallback extends BluetoothGattCallback { |
|
|
|
private final BluetoothDevice device; |
|
|
|
|
|
|
|
public ServiceDiscoveryGattCallback(BluetoothDevice device) { |
|
|
|
this.device = device; |
|
|
|
} |
|
|
|
|
|
|
|
@SuppressLint("MissingPermission") |
|
|
|
@Override |
|
|
|
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { |
|
|
|
if (newState == BluetoothProfile.STATE_CONNECTED) { |
|
|
|
Log.d(TAG, "已连接到 " + device.getAddress() + ",开始发现服务"); |
|
|
|
gatt.discoverServices(); |
|
|
|
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) { |
|
|
|
Log.d(TAG, "与 " + device.getAddress() + " 断开连接"); |
|
|
|
gatt.close(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@SuppressLint("MissingPermission") |
|
|
|
@Override |
|
|
|
public void onServicesDiscovered(BluetoothGatt gatt, int status) { |
|
|
|
if (status == BluetoothGatt.GATT_SUCCESS) { |
|
|
|
Log.d(TAG, "在 " + device.getAddress() + " 上发现服务"); |
|
|
|
BluetoothGattService service = gatt.getService(SERVICE_UUID); |
|
|
|
if (service != null) { |
|
|
|
// 设备支持目标服务,添加到 scannedDevices 列表(切换到主线程操作) |
|
|
|
new Handler(Looper.getMainLooper()).post(() -> { |
|
|
|
if (!scannedDevices.contains(device)) { |
|
|
|
scannedDevices.add(device); |
|
|
|
Log.d(TAG, "设备 " + device.getName() + " 支持目标服务,已添加"); |
|
|
|
} |
|
|
|
}); |
|
|
|
} else { |
|
|
|
Log.d(TAG, "设备 " + device.getAddress() + " 不支持目标服务"); |
|
|
|
} |
|
|
|
} |
|
|
|
// 完成服务发现后断开连接 |
|
|
|
gatt.disconnect(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 私有构造函数,防止外部直接实例化。 |
|
|
|
* |
|
|
|
* @param context 上下文 |
|
|
@ -239,7 +292,7 @@ public class BleManager { |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 开始扫描 BLE 设备,并记录扫描到设备的最后出现时间,定时清理超时设备。 |
|
|
|
* 开始扫描 BLE 设备,扫描到的每个设备均依次连接进行服务查询。 |
|
|
|
*/ |
|
|
|
@SuppressLint("MissingPermission") |
|
|
|
public void startScan() { |
|
|
@ -256,31 +309,45 @@ public class BleManager { |
|
|
|
Log.e(TAG, "获取 BluetoothLeScanner 失败"); |
|
|
|
return; |
|
|
|
} |
|
|
|
// 清空之前的数据 |
|
|
|
scannedDevices.clear(); |
|
|
|
deviceLastSeenMap.clear(); |
|
|
|
processedDevices.clear(); |
|
|
|
|
|
|
|
scanCallback = new ScanCallback() { |
|
|
|
@Override |
|
|
|
public void onScanResult(int callbackType, ScanResult result) { |
|
|
|
BluetoothDevice device = result.getDevice(); |
|
|
|
if (device != null) { |
|
|
|
deviceLastSeenMap.put(device, System.currentTimeMillis()); |
|
|
|
if (!scannedDevices.contains(device)) { |
|
|
|
scannedDevices.add(device); |
|
|
|
Log.d(TAG, "发现设备: " + device.getName() + " - " + device.getAddress()); |
|
|
|
if (device != null && device.getName() != null) { |
|
|
|
if (result.getScanRecord() != null) { |
|
|
|
deviceLastSeenMap.put(device, System.currentTimeMillis()); |
|
|
|
} |
|
|
|
String address = device.getAddress(); |
|
|
|
// 如果该设备已经处理过,则跳过连接 |
|
|
|
if (processedDevices.contains(address)) { |
|
|
|
return; |
|
|
|
} |
|
|
|
processedDevices.add(address); |
|
|
|
// 对扫描到的设备进行连接,查询服务 |
|
|
|
device.connectGatt(context, false, new ServiceDiscoveryGattCallback(device)); |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public void onBatchScanResults(List<ScanResult> results) { |
|
|
|
for (ScanResult result : results) { |
|
|
|
BluetoothDevice device = result.getDevice(); |
|
|
|
if (device != null) { |
|
|
|
deviceLastSeenMap.put(device, System.currentTimeMillis()); |
|
|
|
if (!scannedDevices.contains(device)) { |
|
|
|
scannedDevices.add(device); |
|
|
|
Log.d(TAG, "批量发现设备: " + device.getName() + " - " + device.getAddress()); |
|
|
|
if(device != null && device.getName() != null){ |
|
|
|
if (result.getScanRecord() != null) { |
|
|
|
deviceLastSeenMap.put(device, System.currentTimeMillis()); |
|
|
|
} |
|
|
|
String address = device.getAddress(); |
|
|
|
if (processedDevices.contains(address)) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
processedDevices.add(address); |
|
|
|
device.connectGatt(context, false, new ServiceDiscoveryGattCallback(device)); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -290,6 +357,8 @@ public class BleManager { |
|
|
|
Log.e(TAG, "BLE 扫描失败,错误码:" + errorCode); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
// 开始扫描(此处未使用 ScanFilter,若设备广播中包含目标服务 UUID 也可添加过滤器) |
|
|
|
bluetoothLeScanner.startScan(scanCallback); |
|
|
|
cleanupHandler.postDelayed(cleanupRunnable, CLEANUP_INTERVAL); |
|
|
|
} |
|
|
@ -314,7 +383,7 @@ public class BleManager { |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 返回当前扫描到的设备列表(仅包含实时在线设备)。 |
|
|
|
* 返回当前扫描到的设备列表(仅包含支持目标服务的设备)。 |
|
|
|
*/ |
|
|
|
public List<BluetoothDevice> getScannedDevices() { |
|
|
|
return scannedDevices; |
|
|
@ -356,7 +425,8 @@ public class BleManager { |
|
|
|
BleDeviceUartChannel channel = SystemService.getInstance().getChannel(); |
|
|
|
channel.init(); |
|
|
|
channel.setDeviceOnReportListener(new BleDeviceListener()); |
|
|
|
|
|
|
|
DeviceState deviceState = SystemService.getInstance().getDeviceState(); |
|
|
|
deviceState.setConnected(true); |
|
|
|
} catch (IllegalArgumentException e) { |
|
|
|
Log.e(TAG, "无效的 MAC 地址: " + macAddress, e); |
|
|
|
} |
|
|
@ -397,6 +467,8 @@ public class BleManager { |
|
|
|
bluetoothGatt.disconnect(); |
|
|
|
bluetoothGatt.close(); |
|
|
|
bluetoothGatt = null; |
|
|
|
DeviceState deviceState = SystemService.getInstance().getDeviceState(); |
|
|
|
deviceState.setConnected(false); |
|
|
|
Log.d(TAG, "当前蓝牙设备已断开连接"); |
|
|
|
} |
|
|
|
} |
|
|
|