Android 蓝牙连接类
package com.tech.idealled.ble; import android.annotation.SuppressLint; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCallback; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattDescriptor; import android.bluetooth.BluetoothGattService; import android.bluetooth.BluetoothManager; import android.bluetooth.BluetoothProfile; import android.content.Context; import android.os.Build; import android.os.Handler; import android.support.annotation.RequiresApi; import android.text.TextUtils; import android.util.Log; import com.example.lightstrip.entity.BleData; import com.example.lightstrip.exposed.SendCallBack; import com.example.lightstrip.exposed.WriteCallBack; import com.example.lightstrip.ui.connect.DeviceCallback; import com.tech.idealled.App; import com.tech.idealled.core.data.Agreement; import com.tech.idealled.core.db.bean.Device; import com.tech.idealled.core.db.dao.DeviceDao; import com.tech.idealled.ui.home.MainActivity; import com.tech.idealled.util.LogUtil; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.UUID; ; /** * @author xiaotie * 2022、2、17 * lightStrip 专用类 */ import cn.com.heaton.blelibrary.ble.L; import cn.com.heaton.blelibrary.ble.model.BleDevice; import cn.com.heaton.blelibrary.ble.utils.ByteUtils; @SuppressLint("MissingPermission") @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public class LightStripBleManager { public static final HashMap<String,BleData> devices = new HashMap<>(); public static final HashMap<String,Runnable> runnableCallback = new HashMap<>(); private static final LightStripBleManager instance = new LightStripBleManager(); private final BleListenerImpl bleListener; private final DeviceDao deviceDao; private BleManager bleManager = BleManager.getInstance(); private DeviceCallback deviceCallback; private BluetoothManager bluetoothManager; private BluetoothAdapter bluetoothAdapter; private static final UUID SERVICE = UUID.fromString("0000fff0-0000-1000-8000-00805f9b34fb"); private static final UUID Write1 = UUID.fromString("d44bc439-abfd-45a2-b575-925416129600"); private static final UUID Write2 = UUID.fromString("d44bc439-abfd-45a2-b575-92541612960a"); private static final UUID Write3 = UUID.fromString("d44bc439-abfd-45a2-b575-92541612960b"); private static final UUID Notify = UUID.fromString("d44bc439-abfd-45a2-b575-925416129601"); private final BluetoothGattCallback bluetoothGattCallback; private final Handler handler = new Handler(); private final int timeOut = 5000; private List<HashMap<String,List<byte[]>>> cache= new ArrayList<>(); private List<WriteCallBack> callBacks = new ArrayList<>(); private SendCallBack sendCallBack; private Runnable sendTimeOut = new Runnable() { @Override public void run() { if(sendCallBack!=null && cache.size()>0 && cache.get(cache.size()-1)!=null){ for (String address:cache.get(cache.size()-1).keySet()) { sendCallBack.timeOut(devices.get(address)); }; } } }; private double curTime; private LightStripBleManager(){ bleListener = new BleListenerImpl(); bleManager.registerBleListener(bleListener); deviceDao = App.getDaoSession().getDeviceDao(); bluetoothGattCallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { super.onConnectionStateChange(gatt, status, newState); BleData bleData = devices.get(gatt.getDevice().getAddress()); //操作成功 if(status == BluetoothGatt.GATT_SUCCESS){ if(bleData == null){ LogUtil.e( "device cache miss."); return; } if(newState == BluetoothProfile.STATE_DISCONNECTED){ bleData.setConnectionState(newState); if(deviceCallback != null){ deviceCallback.onBleData(bleData,false); } gatt.close(); devices.remove(gatt.getDevice().getAddress()); LogUtil.d("connectOrDis + 断开连接"+bleData.getBleAddress()+"---"+bleData.getBleName()); }else if(newState == BluetoothProfile.STATE_CONNECTED){ LogUtil.d("connectOrDis + 获取服务"+gatt.getDevice().getAddress()+"---"+gatt.getDevice().getName()); boolean b = bleData.getBluetoothGatt().discoverServices(); if(!b){ LogUtil.d("connectOrDis + GATT Service acquisition failed"); devices.remove(bleData.getBleAddress()); gatt.disconnect(); return; }else { runnableCallback.put(bleData.getBleAddress(), () -> { LogUtil.d("connectOrDis + GATT Service No reaction"); devices.remove(bleData.getBleAddress()); gatt.disconnect(); }); handler.postDelayed(runnableCallback.get(bleData.getBleAddress()), timeOut); } } } if(status == 133){ LogUtil.d("connectOrDis + status 133"); devices.remove(bleData.getBleAddress()); gatt.disconnect(); } } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { super.onServicesDiscovered(gatt, status); handler.removeCallbacks(runnableCallback.get(gatt.getDevice().getAddress())); LogUtil.d("connectOrDis + 设置mtu"+gatt.getDevice().getAddress()+"---"+gatt.getDevice().getName()); gatt.requestMtu(512); } @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { super.onCharacteristicRead(gatt, characteristic, status); } @Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { super.onCharacteristicWrite(gatt, characteristic, status); } @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { super.onCharacteristicChanged(gatt, characteristic); byte[] dataEd = Agreement.getDecodeData(characteristic.getValue()); String address = gatt.getDevice().getAddress(); for (WriteCallBack callBack :callBacks) { callBack.onCharacteristicChanged(devices.get(address),dataEd); } for (int i = 0; i < cache.size(); i++) { HashMap<String,List<byte[]>> item = cache.get(i); if(item.containsKey(address)){ List<byte[]> bytes = item.get(address); String arrays = Arrays.toString(bytes.get(0)); String censor = arrays.substring(1, arrays.length()-1); if(Arrays.toString(dataEd).contains(censor)){ boolean result = true; if(bytes.get(1)!=null && bytes.size()<3 && bytes.get(1).length != 0){ result= write(gatt, bytes.get(1), Write1); }else if(bytes.get(1)!=null) { result = write(gatt, bytes.get(1), Write2); } if(!result && sendCallBack!=null){ sendCallBack.fail(devices.get(address)); } bytes.remove(1); if(bytes.size()<2 || bytes.get(1).length==0){ item.remove(address); if(result){ for (HashMap<String,List<byte[]>> it: cache) { result = it.get(address)==null; } if(result){ sendCallBack.success(devices.get(address)); } } }else { item.put(address,bytes); } if(cache.get(i).size() ==0){ cache.remove(i); } if(cache.size() ==0 && sendCallBack!=null){ sendCallBack.successAll(); } return; } } } } @Override public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { super.onDescriptorRead(gatt, descriptor, status); } @Override public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { super.onDescriptorWrite(gatt, descriptor, status); } @Override public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) { super.onMtuChanged(gatt, mtu, status); BleData bleData = devices.get(gatt.getDevice().getAddress()); if(bleData == null){ LogUtil.d( "connectOrDis + device cache miss."); return; } LogUtil.d("connectOrDis + 设置mtu成功"+bleData.getBleAddress()+"---"+bleData.getBleName()); BluetoothGatt bluetoothGatt = bleData.getBluetoothGatt(); BluetoothGattService gattService = bluetoothGatt.getService(SERVICE); if(gattService != null){ BluetoothGattCharacteristic characteristic = gattService.getCharacteristic(Notify); if(characteristic != null){ enableNotification(bluetoothGatt,true, characteristic); LogUtil.d("connectOrDis + 更新设备"+bleData.getBleAddress()+"---"+bleData.getBleName()); bleData.setConnectionState(BluetoothProfile.STATE_CONNECTED); if(deviceCallback != null){ deviceCallback.onBleData(bleData,false); } devices.put(bleData.getBleAddress(),bleData); }else { LogUtil.d("connectOrDis + Characteristic null "+bleData.getBleAddress()+"---"+bleData.getBleName()); gatt.disconnect(); devices.remove(bleData.getBleAddress()); } }else { LogUtil.d("connectOrDis + GATT Service null "+bleData.getBleAddress()+"---"+bleData.getBleName()); gatt.disconnect(); devices.remove(bleData.getBleAddress()); } } }; } public void registerCallback(WriteCallBack writeCallBack){ callBacks.add(writeCallBack); } public void unregisterCallback(WriteCallBack writeCallBack){ callBacks.remove(writeCallBack); } /** * * @param bluetoothGatt Gatt * @param enable 注册(true)/注销(false) * @param characteristic 通知特征ID */ public void enableNotification(BluetoothGatt bluetoothGatt, boolean enable, BluetoothGattCharacteristic characteristic) { if (bluetoothGatt == null || characteristic == null) { return; } if (!bluetoothGatt.setCharacteristicNotification(characteristic, enable)) { return; } //获取到Notify当中的Descriptor通道 然后再进行注册 List<BluetoothGattDescriptor> clientConfigs = characteristic.getDescriptors(); if (clientConfigs == null || clientConfigs.size() ==0) { return; } if (enable) { for (BluetoothGattDescriptor clientConfig: clientConfigs) { clientConfig.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); boolean b = bluetoothGatt.writeDescriptor(clientConfig); LogUtil.d("connectOrDis + 注册通知"+b); } } else { for (BluetoothGattDescriptor clientConfig: clientConfigs) { clientConfig.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE); boolean b = bluetoothGatt.writeDescriptor(clientConfig); LogUtil.d("connectOrDis + 注销通知"+b); } } } public static LightStripBleManager getInstance(){ return instance; } @SuppressLint("MissingPermission") public void disconnectAll(){ for (BleData bleData:devices.values()) { bleData.getBluetoothGatt().disconnect(); } } public void setCallBack(DeviceCallback deviceCallback){ this.deviceCallback = deviceCallback; } public List<BleData> getDevices() { return new ArrayList<>(devices.values()); } private boolean write (BluetoothGatt gatt, byte[] data,UUID write) { BluetoothGattService gattService = gatt.getService(SERVICE); if(gattService==null){ LogUtil.d("Write + GATT 服务丢失"); return false; } BluetoothGattCharacteristic characteristic = gattService.getCharacteristic(write); if(characteristic==null){ LogUtil.d("Write + Characteristic 特征丢失"); return false; } characteristic.setValue(data); return gatt.writeCharacteristic(characteristic); } public boolean write1(byte[] data) { boolean result = false; for (BleData bleData :devices.values()) { if(bleData.getConnectionState() == BluetoothProfile.STATE_CONNECTED){ result = write(bleData.getBluetoothGatt(),data,Write1); } } return result; } /** * @param data 发送的数据 * @param sendCallBack {@link SendCallBack} * @param list 后续要发的东西 格式: * byte[0] 触动发送的条件 例:new byte[]{'X', 'I', 'A', 'Y', 'I', 'B','U'} * byte[1] byte[last-1] 发送的东西(write2) 例:new byte[]{'S', J', 'Y', 'I'} * byte[last] 发送结束的通知(write1) 例:new byte[]{'O', 'K'}, 不需要时可以为new byte[0] * @return */ @SafeVarargs public final boolean write1(byte[] data, SendCallBack sendCallBack, List<byte[]>... list) { this.sendCallBack = sendCallBack; cache.clear(); handler.removeCallbacks(sendTimeOut); handler.postDelayed(sendTimeOut,10*1000); boolean result = false; if(devices.size() ==0 ){ if(sendCallBack!=null){ sendCallBack.fail(null); } return false; } HashMap<String, List<byte[]>> stringHash; for (List<byte[]> item : list) { stringHash = new HashMap<>(); for (BleData bleData : devices.values()){ stringHash.put(bleData.getBleAddress(), new ArrayList<>(item)); } cache.add(stringHash); } for (BleData bleData : devices.values()) { if (bleData.getConnectionState() == BluetoothProfile.STATE_CONNECTED) { result = write(bleData.getBluetoothGatt(), data, Write1); if(!result && sendCallBack!=null){ sendCallBack.fail(bleData); } } } return result; } public boolean write3(byte[] data) { boolean result = false; for (BleData bleData :devices.values()) { if(bleData.getConnectionState() == BluetoothProfile.STATE_CONNECTED){ result = write(bleData.getBluetoothGatt(),data,Write3); } } return result; } public boolean write1(BluetoothGatt gatt, byte[] dataEd) { return write(gatt,dataEd,Write1); } class BleListenerImpl extends BleListener{ @Override public boolean filterDevice(BleDevice device, int rssi, byte[] scanRecord) { if(!LightStripBleConfig.matchProduct(scanRecord)) {return true;} BleData bleData = new BleData(); bleData.setBluetoothDevice(device.getBluetoothDevice()); bleData.setScanRecord(scanRecord); bleData.setConnectionState(BluetoothProfile.STATE_DISCONNECTED); bleData.setBleAddress(device.getBleAddress()); bleData.setBleName(device.getBleName()); bleData.setOtaVersion(""); if(deviceCallback != null){ deviceCallback.onBleData(bleData,true); } if(isReConnect(bleData.getBleAddress())){ if (System.currentTimeMillis() - curTime > 1500) { connectOrDis(bleData); curTime = System.currentTimeMillis(); } } return super.filterDevice(device, rssi, scanRecord); } @Override public void onStart() { super.onStart(); } @Override public void onStop() { super.onStop(); } @Override public void onChanged(BleDevice device, byte[] data) { } } /** * 保存 是否可以重连地址 * * @param bleName 设备名称 * @param bleAddress 设备地址 * @param isReConnect 是否可以重连 */ public void saveDevice(String bleName, String bleAddress, boolean isReConnect) { try { Device device = deviceDao.queryBuilder().where(DeviceDao.Properties.Mac.eq(bleAddress)).unique(); if (device != null && !TextUtils.isEmpty(device.getMac())) { device.setDeviceName(bleName); device.setIsReConnect(isReConnect); device.setMac(bleAddress); deviceDao.update(device); } else { Device device1 = new Device(); device1.setDeviceName(bleName); device1.setIsReConnect(isReConnect); device1.setMac(bleAddress); deviceDao.save(device1); } } catch (Exception e) { e.printStackTrace(); } } /** * 连接、断开设备 * */ @SuppressLint("MissingPermission") public void connectOrDis(BleData bleData){ if(devices.get(bleData.getBleAddress()) == null || (devices.get(bleData.getBleAddress()).getConnectionState() == bleData.getConnectionState() && devices.get(bleData.getBleAddress()).getConnectionState() != BluetoothProfile.STATE_CONNECTING && devices.get(bleData.getBleAddress()).getConnectionState() != BluetoothProfile.STATE_DISCONNECTING) ){}else {return;} LogUtil.d("connectOrDis + 操作中"+bleData.getBleAddress()+"---"+bleData.getBleName()+"---"+bleData.getConnectionState()); //检查蓝牙地址 if(!BluetoothAdapter.checkBluetoothAddress(bleData.getBleAddress())){ LogUtil.e( "checkBluetoothAddress False"); return; } //断开设备 if(bleData.getConnectionState() == BluetoothProfile.STATE_CONNECTED){ LogUtil.d("connectOrDis + 断开设备"+bleData.getBleAddress()+"---"+bleData.getBleName()); bleData.getBluetoothGatt().disconnect(); bleData.setConnectionState(BluetoothProfile.STATE_DISCONNECTING); runnableCallback.put(bleData.getBleAddress(), () -> { LogUtil.d("connectOrDis + GATT Service No reaction"); devices.remove(bleData.getBleAddress()); }); devices.put(bleData.getBleAddress(),bleData); return; } //连接设备 if (bluetoothManager == null) { bluetoothManager = (BluetoothManager) App.getContext().getSystemService(Context.BLUETOOTH_SERVICE); if (bluetoothManager == null) { LogUtil.e( "Unable to initBLE BluetoothManager."); return; } } if (bluetoothAdapter == null) { bluetoothAdapter = bluetoothManager.getAdapter(); if (bluetoothAdapter == null) { LogUtil.e( "Unable to obtain a BluetoothAdapter."); return; } } LogUtil.d("connectOrDis + 获取设备"+bleData.getBleAddress()+"---"+bleData.getBleName()); BluetoothDevice device = bluetoothAdapter.getRemoteDevice(bleData.getBleAddress()); LogUtil.d("connectOrDis + 保存设备"+bleData.getBleAddress()+"---"+bleData.getBleName()); // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // //GATT连接到远程双模设备优先BLE // bleData.setBluetoothGatt(device.connectGatt(App.getContext(), false, bluetoothGattCallback, BluetoothDevice.TRANSPORT_LE)); // }else { bleData.setBluetoothGatt(device.connectGatt(App.getContext(), false, bluetoothGattCallback)); // } bleData.setConnectionState(BluetoothProfile.STATE_CONNECTING); devices.put(bleData.getBleAddress(),bleData); } /** * 是否可以重连 * * @param bleAddress 设备地址 * @return 是否可以重连 */ private boolean isReConnect(String bleAddress) { try { if (!TextUtils.isEmpty(bleAddress)) { Device device = deviceDao.queryBuilder().where(DeviceDao.Properties.Mac.eq(bleAddress)).unique(); if (device != null) { return device.getIsReConnect(); } } } catch (Exception e) { e.printStackTrace(); } return false; } }