first commit
This commit is contained in:
906
FastBleLib/src/main/java/com/clj/fastble/BleManager.java
Normal file
906
FastBleLib/src/main/java/com/clj/fastble/BleManager.java
Normal file
@@ -0,0 +1,906 @@
|
||||
package com.clj.fastble;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Application;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothGatt;
|
||||
import android.bluetooth.BluetoothGattCharacteristic;
|
||||
import android.bluetooth.BluetoothGattService;
|
||||
import android.bluetooth.BluetoothManager;
|
||||
import android.bluetooth.BluetoothProfile;
|
||||
import android.bluetooth.le.ScanRecord;
|
||||
import android.bluetooth.le.ScanResult;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.Looper;
|
||||
|
||||
import com.clj.fastble.bluetooth.BleBluetooth;
|
||||
import com.clj.fastble.bluetooth.MultipleBluetoothController;
|
||||
import com.clj.fastble.bluetooth.SplitWriter;
|
||||
import com.clj.fastble.callback.BleGattCallback;
|
||||
import com.clj.fastble.callback.BleIndicateCallback;
|
||||
import com.clj.fastble.callback.BleMtuChangedCallback;
|
||||
import com.clj.fastble.callback.BleNotifyCallback;
|
||||
import com.clj.fastble.callback.BleReadCallback;
|
||||
import com.clj.fastble.callback.BleRssiCallback;
|
||||
import com.clj.fastble.callback.BleScanAndConnectCallback;
|
||||
import com.clj.fastble.callback.BleScanCallback;
|
||||
import com.clj.fastble.callback.BleWriteCallback;
|
||||
import com.clj.fastble.data.BleDevice;
|
||||
import com.clj.fastble.data.BleScanState;
|
||||
import com.clj.fastble.exception.OtherException;
|
||||
import com.clj.fastble.scan.BleScanRuleConfig;
|
||||
import com.clj.fastble.scan.BleScanner;
|
||||
import com.clj.fastble.utils.BleLog;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class BleManager {
|
||||
|
||||
private Application context;
|
||||
private BleScanRuleConfig bleScanRuleConfig;
|
||||
private BluetoothAdapter bluetoothAdapter;
|
||||
private MultipleBluetoothController multipleBluetoothController;
|
||||
private BluetoothManager bluetoothManager;
|
||||
|
||||
public static final int DEFAULT_SCAN_TIME = 10000;
|
||||
private static final int DEFAULT_MAX_MULTIPLE_DEVICE = 7;
|
||||
private static final int DEFAULT_OPERATE_TIME = 5000;
|
||||
private static final int DEFAULT_CONNECT_RETRY_COUNT = 0;
|
||||
private static final int DEFAULT_CONNECT_RETRY_INTERVAL = 5000;
|
||||
private static final int DEFAULT_MTU = 23;
|
||||
private static final int DEFAULT_MAX_MTU = 512;
|
||||
private static final int DEFAULT_WRITE_DATA_SPLIT_COUNT = 20;
|
||||
private static final int DEFAULT_CONNECT_OVER_TIME = 10000;
|
||||
|
||||
private int maxConnectCount = DEFAULT_MAX_MULTIPLE_DEVICE;
|
||||
private int operateTimeout = DEFAULT_OPERATE_TIME;
|
||||
private int reConnectCount = DEFAULT_CONNECT_RETRY_COUNT;
|
||||
private long reConnectInterval = DEFAULT_CONNECT_RETRY_INTERVAL;
|
||||
private int splitWriteNum = DEFAULT_WRITE_DATA_SPLIT_COUNT;
|
||||
private long connectOverTime = DEFAULT_CONNECT_OVER_TIME;
|
||||
|
||||
public static BleManager getInstance() {
|
||||
return BleManagerHolder.sBleManager;
|
||||
}
|
||||
|
||||
private static class BleManagerHolder {
|
||||
private static final BleManager sBleManager = new BleManager();
|
||||
}
|
||||
|
||||
public void init(Application app) {
|
||||
if (context == null && app != null) {
|
||||
context = app;
|
||||
if (isSupportBle()) {
|
||||
bluetoothManager =
|
||||
(BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
|
||||
bluetoothAdapter = bluetoothManager.getAdapter();
|
||||
} else {
|
||||
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||
}
|
||||
multipleBluetoothController = new MultipleBluetoothController();
|
||||
bleScanRuleConfig = new BleScanRuleConfig();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Context
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Context getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the BluetoothManager
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public BluetoothManager getBluetoothManager() {
|
||||
return bluetoothManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the BluetoothAdapter
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public BluetoothAdapter getBluetoothAdapter() {
|
||||
return bluetoothAdapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the ScanRuleConfig
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public BleScanRuleConfig getScanRuleConfig() {
|
||||
return bleScanRuleConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the multiple Bluetooth Controller
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public MultipleBluetoothController getMultipleBluetoothController() {
|
||||
return multipleBluetoothController;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure scan and connection properties
|
||||
*
|
||||
* @param config
|
||||
*/
|
||||
public void initScanRule(BleScanRuleConfig config) {
|
||||
this.bleScanRuleConfig = config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum number of connections
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getMaxConnectCount() {
|
||||
return maxConnectCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum number of connections
|
||||
*
|
||||
* @param count
|
||||
* @return BleManager
|
||||
*/
|
||||
public BleManager setMaxConnectCount(int count) {
|
||||
if (count > DEFAULT_MAX_MULTIPLE_DEVICE)
|
||||
count = DEFAULT_MAX_MULTIPLE_DEVICE;
|
||||
this.maxConnectCount = count;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get operate timeout
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getOperateTimeout() {
|
||||
return operateTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set operate timeout
|
||||
*
|
||||
* @param count
|
||||
* @return BleManager
|
||||
*/
|
||||
public BleManager setOperateTimeout(int count) {
|
||||
this.operateTimeout = count;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get connect retry count
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getReConnectCount() {
|
||||
return reConnectCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get connect retry interval
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public long getReConnectInterval() {
|
||||
return reConnectInterval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set connect retry count and interval
|
||||
*
|
||||
* @param count
|
||||
* @return BleManager
|
||||
*/
|
||||
public BleManager setReConnectCount(int count) {
|
||||
return setReConnectCount(count, DEFAULT_CONNECT_RETRY_INTERVAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set connect retry count and interval
|
||||
*
|
||||
* @param count
|
||||
* @return BleManager
|
||||
*/
|
||||
public BleManager setReConnectCount(int count, long interval) {
|
||||
if (count > 10)
|
||||
count = 10;
|
||||
if (interval < 0)
|
||||
interval = 0;
|
||||
this.reConnectCount = count;
|
||||
this.reConnectInterval = interval;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get operate split Write Num
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getSplitWriteNum() {
|
||||
return splitWriteNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set split Writ eNum
|
||||
*
|
||||
* @param num
|
||||
* @return BleManager
|
||||
*/
|
||||
public BleManager setSplitWriteNum(int num) {
|
||||
if (num > 0) {
|
||||
this.splitWriteNum = num;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get operate connect Over Time
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public long getConnectOverTime() {
|
||||
return connectOverTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set connect Over Time
|
||||
*
|
||||
* @param time
|
||||
* @return BleManager
|
||||
*/
|
||||
public BleManager setConnectOverTime(long time) {
|
||||
if (time <= 0) {
|
||||
time = 100;
|
||||
}
|
||||
this.connectOverTime = time;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* print log?
|
||||
*
|
||||
* @param enable
|
||||
* @return BleManager
|
||||
*/
|
||||
public BleManager enableLog(boolean enable) {
|
||||
BleLog.isPrint = enable;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* scan device around
|
||||
*
|
||||
* @param callback
|
||||
*/
|
||||
public void scan(BleScanCallback callback) {
|
||||
if (callback == null) {
|
||||
throw new IllegalArgumentException("BleScanCallback can not be Null!");
|
||||
}
|
||||
|
||||
if (!isBlueEnable()) {
|
||||
BleLog.e("Bluetooth not enable!");
|
||||
callback.onScanStarted(false);
|
||||
return;
|
||||
}
|
||||
|
||||
UUID[] serviceUuids = bleScanRuleConfig.getServiceUuids();
|
||||
String[] deviceNames = bleScanRuleConfig.getDeviceNames();
|
||||
String deviceMac = bleScanRuleConfig.getDeviceMac();
|
||||
boolean fuzzy = bleScanRuleConfig.isFuzzy();
|
||||
long timeOut = bleScanRuleConfig.getScanTimeOut();
|
||||
|
||||
BleScanner.getInstance()
|
||||
.scan(serviceUuids, deviceNames, deviceMac, fuzzy, timeOut, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* scan device then connect
|
||||
*
|
||||
* @param callback
|
||||
*/
|
||||
public void scanAndConnect(BleScanAndConnectCallback callback) {
|
||||
if (callback == null) {
|
||||
throw new IllegalArgumentException("BleScanAndConnectCallback can not be Null!");
|
||||
}
|
||||
|
||||
if (!isBlueEnable()) {
|
||||
BleLog.e("Bluetooth not enable!");
|
||||
callback.onScanStarted(false);
|
||||
return;
|
||||
}
|
||||
|
||||
UUID[] serviceUuids = bleScanRuleConfig.getServiceUuids();
|
||||
String[] deviceNames = bleScanRuleConfig.getDeviceNames();
|
||||
String deviceMac = bleScanRuleConfig.getDeviceMac();
|
||||
boolean fuzzy = bleScanRuleConfig.isFuzzy();
|
||||
long timeOut = bleScanRuleConfig.getScanTimeOut();
|
||||
|
||||
BleScanner.getInstance()
|
||||
.scanAndConnect(serviceUuids, deviceNames, deviceMac, fuzzy, timeOut, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* connect a known device
|
||||
*
|
||||
* @param bleDevice
|
||||
* @param bleGattCallback
|
||||
* @return
|
||||
*/
|
||||
public BluetoothGatt connect(BleDevice bleDevice, BleGattCallback bleGattCallback) {
|
||||
if (bleGattCallback == null) {
|
||||
throw new IllegalArgumentException("BleGattCallback can not be Null!");
|
||||
}
|
||||
|
||||
if (!isBlueEnable()) {
|
||||
BleLog.e("Bluetooth not enable!");
|
||||
bleGattCallback.onConnectFail(bleDevice, new OtherException("Bluetooth not enable!"));
|
||||
return null;
|
||||
}
|
||||
|
||||
if (Looper.myLooper() == null || Looper.myLooper() != Looper.getMainLooper()) {
|
||||
BleLog.w("Be careful: currentThread is not MainThread!");
|
||||
}
|
||||
|
||||
if (bleDevice == null || bleDevice.getDevice() == null) {
|
||||
bleGattCallback.onConnectFail(bleDevice, new OtherException("Not Found Device " +
|
||||
"Exception Occurred!"));
|
||||
} else {
|
||||
BleBluetooth bleBluetooth = multipleBluetoothController.buildConnectingBle(bleDevice);
|
||||
boolean autoConnect = bleScanRuleConfig.isAutoConnect();
|
||||
return bleBluetooth.connect(bleDevice, autoConnect, bleGattCallback);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* connect a device through its mac without scan,whether or not it has been connected
|
||||
*
|
||||
* @param mac
|
||||
* @param bleGattCallback
|
||||
* @return
|
||||
*/
|
||||
public BluetoothGatt connect(String mac, BleGattCallback bleGattCallback) {
|
||||
BluetoothDevice bluetoothDevice = getBluetoothAdapter().getRemoteDevice(mac);
|
||||
BleDevice bleDevice = new BleDevice(bluetoothDevice, 0, null, 0);
|
||||
return connect(bleDevice, bleGattCallback);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cancel scan
|
||||
*/
|
||||
public void cancelScan() {
|
||||
BleScanner.getInstance().stopLeScan();
|
||||
}
|
||||
|
||||
/**
|
||||
* notify
|
||||
*
|
||||
* @param bleDevice
|
||||
* @param uuid_service
|
||||
* @param uuid_notify
|
||||
* @param callback
|
||||
*/
|
||||
public void notify(BleDevice bleDevice, String uuid_service, String uuid_notify,
|
||||
BleNotifyCallback callback) {
|
||||
notify(bleDevice, uuid_service, uuid_notify, false, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* notify
|
||||
*
|
||||
* @param bleDevice
|
||||
* @param uuid_service
|
||||
* @param uuid_notify
|
||||
* @param useCharacteristicDescriptor
|
||||
* @param callback
|
||||
*/
|
||||
public void notify(BleDevice bleDevice, String uuid_service, String uuid_notify,
|
||||
boolean useCharacteristicDescriptor, BleNotifyCallback callback) {
|
||||
if (callback == null) {
|
||||
throw new IllegalArgumentException("BleNotifyCallback can not be Null!");
|
||||
}
|
||||
|
||||
BleBluetooth bleBluetooth = multipleBluetoothController.getBleBluetooth(bleDevice);
|
||||
if (bleBluetooth == null) {
|
||||
callback.onNotifyFailure(new OtherException("This device not connect!"));
|
||||
} else {
|
||||
bleBluetooth.newBleConnector().withUUIDString(uuid_service, uuid_notify)
|
||||
.enableCharacteristicNotify(callback, uuid_notify, useCharacteristicDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* indicate
|
||||
*
|
||||
* @param bleDevice
|
||||
* @param uuid_service
|
||||
* @param uuid_indicate
|
||||
* @param callback
|
||||
*/
|
||||
public void indicate(BleDevice bleDevice, String uuid_service, String uuid_indicate,
|
||||
BleIndicateCallback callback) {
|
||||
indicate(bleDevice, uuid_service, uuid_indicate, false, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* indicate
|
||||
*
|
||||
* @param bleDevice
|
||||
* @param uuid_service
|
||||
* @param uuid_indicate
|
||||
* @param useCharacteristicDescriptor
|
||||
* @param callback
|
||||
*/
|
||||
public void indicate(BleDevice bleDevice, String uuid_service, String uuid_indicate,
|
||||
boolean useCharacteristicDescriptor, BleIndicateCallback callback) {
|
||||
if (callback == null) {
|
||||
throw new IllegalArgumentException("BleIndicateCallback can not be Null!");
|
||||
}
|
||||
|
||||
BleBluetooth bleBluetooth = multipleBluetoothController.getBleBluetooth(bleDevice);
|
||||
if (bleBluetooth == null) {
|
||||
callback.onIndicateFailure(new OtherException("This device not connect!"));
|
||||
} else {
|
||||
bleBluetooth.newBleConnector().withUUIDString(uuid_service, uuid_indicate)
|
||||
.enableCharacteristicIndicate(callback, uuid_indicate,
|
||||
useCharacteristicDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* stop notify, remove callback
|
||||
*
|
||||
* @param bleDevice
|
||||
* @param uuid_service
|
||||
* @param uuid_notify
|
||||
* @return
|
||||
*/
|
||||
public boolean stopNotify(BleDevice bleDevice, String uuid_service, String uuid_notify) {
|
||||
return stopNotify(bleDevice, uuid_service, uuid_notify, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* stop notify, remove callback
|
||||
*
|
||||
* @param bleDevice
|
||||
* @param uuid_service
|
||||
* @param uuid_notify
|
||||
* @param useCharacteristicDescriptor
|
||||
* @return
|
||||
*/
|
||||
public boolean stopNotify(BleDevice bleDevice, String uuid_service, String uuid_notify,
|
||||
boolean useCharacteristicDescriptor) {
|
||||
BleBluetooth bleBluetooth = multipleBluetoothController.getBleBluetooth(bleDevice);
|
||||
if (bleBluetooth == null) {
|
||||
return false;
|
||||
}
|
||||
boolean success = bleBluetooth.newBleConnector().withUUIDString(uuid_service, uuid_notify)
|
||||
.disableCharacteristicNotify(useCharacteristicDescriptor);
|
||||
if (success) {
|
||||
bleBluetooth.removeNotifyCallback(uuid_notify);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* stop indicate, remove callback
|
||||
*
|
||||
* @param bleDevice
|
||||
* @param uuid_service
|
||||
* @param uuid_indicate
|
||||
* @return
|
||||
*/
|
||||
public boolean stopIndicate(BleDevice bleDevice, String uuid_service, String uuid_indicate) {
|
||||
return stopIndicate(bleDevice, uuid_service, uuid_indicate, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* stop indicate, remove callback
|
||||
*
|
||||
* @param bleDevice
|
||||
* @param uuid_service
|
||||
* @param uuid_indicate
|
||||
* @param useCharacteristicDescriptor
|
||||
* @return
|
||||
*/
|
||||
public boolean stopIndicate(BleDevice bleDevice, String uuid_service, String uuid_indicate,
|
||||
boolean useCharacteristicDescriptor) {
|
||||
BleBluetooth bleBluetooth = multipleBluetoothController.getBleBluetooth(bleDevice);
|
||||
if (bleBluetooth == null) {
|
||||
return false;
|
||||
}
|
||||
boolean success = bleBluetooth.newBleConnector().withUUIDString(uuid_service, uuid_indicate)
|
||||
.disableCharacteristicIndicate(useCharacteristicDescriptor);
|
||||
if (success) {
|
||||
bleBluetooth.removeIndicateCallback(uuid_indicate);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* write
|
||||
*
|
||||
* @param bleDevice
|
||||
* @param uuid_service
|
||||
* @param uuid_write
|
||||
* @param data
|
||||
* @param callback
|
||||
*/
|
||||
public void write(BleDevice bleDevice, String uuid_service, String uuid_write, byte[] data,
|
||||
BleWriteCallback callback) {
|
||||
write(bleDevice, uuid_service, uuid_write, data, true, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* write
|
||||
*
|
||||
* @param bleDevice
|
||||
* @param uuid_service
|
||||
* @param uuid_write
|
||||
* @param data
|
||||
* @param split
|
||||
* @param callback
|
||||
*/
|
||||
public void write(BleDevice bleDevice, String uuid_service, String uuid_write, byte[] data,
|
||||
boolean split, BleWriteCallback callback) {
|
||||
|
||||
write(bleDevice, uuid_service, uuid_write, data, split, true, 0, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* write
|
||||
*
|
||||
* @param bleDevice
|
||||
* @param uuid_service
|
||||
* @param uuid_write
|
||||
* @param data
|
||||
* @param split
|
||||
* @param sendNextWhenLastSuccess
|
||||
* @param intervalBetweenTwoPackage
|
||||
* @param callback
|
||||
*/
|
||||
public void write(BleDevice bleDevice, String uuid_service, String uuid_write, byte[] data,
|
||||
boolean split, boolean sendNextWhenLastSuccess,
|
||||
long intervalBetweenTwoPackage, BleWriteCallback callback) {
|
||||
|
||||
if (callback == null) {
|
||||
throw new IllegalArgumentException("BleWriteCallback can not be Null!");
|
||||
}
|
||||
|
||||
if (data == null) {
|
||||
BleLog.e("data is Null!");
|
||||
callback.onWriteFailure(new OtherException("data is Null!"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.length > 20 && !split) {
|
||||
BleLog.w("Be careful: data's length beyond 20! Ensure MTU higher than 23, or use " +
|
||||
"spilt write!");
|
||||
}
|
||||
|
||||
BleBluetooth bleBluetooth = multipleBluetoothController.getBleBluetooth(bleDevice);
|
||||
if (bleBluetooth == null) {
|
||||
callback.onWriteFailure(new OtherException("This device not connect!"));
|
||||
} else {
|
||||
if (split && data.length > getSplitWriteNum()) {
|
||||
new SplitWriter().splitWrite(bleBluetooth, uuid_service, uuid_write, data,
|
||||
sendNextWhenLastSuccess, intervalBetweenTwoPackage, callback);
|
||||
} else {
|
||||
bleBluetooth.newBleConnector().withUUIDString(uuid_service, uuid_write)
|
||||
.writeCharacteristic(data, callback, uuid_write);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* read
|
||||
*
|
||||
* @param bleDevice
|
||||
* @param uuid_service
|
||||
* @param uuid_read
|
||||
* @param callback
|
||||
*/
|
||||
public void read(BleDevice bleDevice, String uuid_service, String uuid_read,
|
||||
BleReadCallback callback) {
|
||||
if (callback == null) {
|
||||
throw new IllegalArgumentException("BleReadCallback can not be Null!");
|
||||
}
|
||||
|
||||
BleBluetooth bleBluetooth = multipleBluetoothController.getBleBluetooth(bleDevice);
|
||||
if (bleBluetooth == null) {
|
||||
callback.onReadFailure(new OtherException("This device is not connected!"));
|
||||
} else {
|
||||
bleBluetooth.newBleConnector().withUUIDString(uuid_service, uuid_read)
|
||||
.readCharacteristic(callback, uuid_read);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* read Rssi
|
||||
*
|
||||
* @param bleDevice
|
||||
* @param callback
|
||||
*/
|
||||
public void readRssi(BleDevice bleDevice, BleRssiCallback callback) {
|
||||
if (callback == null) {
|
||||
throw new IllegalArgumentException("BleRssiCallback can not be Null!");
|
||||
}
|
||||
|
||||
BleBluetooth bleBluetooth = multipleBluetoothController.getBleBluetooth(bleDevice);
|
||||
if (bleBluetooth == null) {
|
||||
callback.onRssiFailure(new OtherException("This device is not connected!"));
|
||||
} else {
|
||||
bleBluetooth.newBleConnector().readRemoteRssi(callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set Mtu
|
||||
*
|
||||
* @param bleDevice
|
||||
* @param mtu
|
||||
* @param callback
|
||||
*/
|
||||
public void setMtu(BleDevice bleDevice, int mtu, BleMtuChangedCallback callback) {
|
||||
if (callback == null) {
|
||||
throw new IllegalArgumentException("BleMtuChangedCallback can not be Null!");
|
||||
}
|
||||
|
||||
if (mtu > DEFAULT_MAX_MTU) {
|
||||
BleLog.e("requiredMtu should lower than 512 !");
|
||||
callback.onSetMTUFailure(new OtherException("requiredMtu should lower than 512 !"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (mtu < DEFAULT_MTU) {
|
||||
BleLog.e("requiredMtu should higher than 23 !");
|
||||
callback.onSetMTUFailure(new OtherException("requiredMtu should higher than 23 !"));
|
||||
return;
|
||||
}
|
||||
|
||||
BleBluetooth bleBluetooth = multipleBluetoothController.getBleBluetooth(bleDevice);
|
||||
if (bleBluetooth == null) {
|
||||
callback.onSetMTUFailure(new OtherException("This device is not connected!"));
|
||||
} else {
|
||||
bleBluetooth.newBleConnector().setMtu(mtu, callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* requestConnectionPriority
|
||||
*
|
||||
* @param connectionPriority Request a specific connection priority. Must be one of
|
||||
* {@link BluetoothGatt#CONNECTION_PRIORITY_BALANCED},
|
||||
* {@link BluetoothGatt#CONNECTION_PRIORITY_HIGH}
|
||||
* or {@link BluetoothGatt#CONNECTION_PRIORITY_LOW_POWER}.
|
||||
* @throws IllegalArgumentException If the parameters are outside of their
|
||||
* specified range.
|
||||
*/
|
||||
public boolean requestConnectionPriority(BleDevice bleDevice, int connectionPriority) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
BleBluetooth bleBluetooth = multipleBluetoothController.getBleBluetooth(bleDevice);
|
||||
if (bleBluetooth == null) {
|
||||
return false;
|
||||
} else {
|
||||
return bleBluetooth.newBleConnector().requestConnectionPriority(connectionPriority);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* is support ble?
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isSupportBle() {
|
||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 && context.getApplicationContext()
|
||||
.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open bluetooth
|
||||
*/
|
||||
public void enableBluetooth() {
|
||||
if (bluetoothAdapter != null) {
|
||||
bluetoothAdapter.enable();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable bluetooth
|
||||
*/
|
||||
public void disableBluetooth() {
|
||||
if (bluetoothAdapter != null) {
|
||||
if (bluetoothAdapter.isEnabled())
|
||||
bluetoothAdapter.disable();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* judge Bluetooth is enable
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isBlueEnable() {
|
||||
return bluetoothAdapter != null && bluetoothAdapter.isEnabled();
|
||||
}
|
||||
|
||||
|
||||
public BleDevice convertBleDevice(BluetoothDevice bluetoothDevice) {
|
||||
return new BleDevice(bluetoothDevice);
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
public BleDevice convertBleDevice(ScanResult scanResult) {
|
||||
if (scanResult == null) {
|
||||
throw new IllegalArgumentException("scanResult can not be Null!");
|
||||
}
|
||||
BluetoothDevice bluetoothDevice = scanResult.getDevice();
|
||||
int rssi = scanResult.getRssi();
|
||||
ScanRecord scanRecord = scanResult.getScanRecord();
|
||||
byte[] bytes = null;
|
||||
if (scanRecord != null)
|
||||
bytes = scanRecord.getBytes();
|
||||
long timestampNanos = scanResult.getTimestampNanos();
|
||||
return new BleDevice(bluetoothDevice, rssi, bytes, timestampNanos);
|
||||
}
|
||||
|
||||
public BleBluetooth getBleBluetooth(BleDevice bleDevice) {
|
||||
if (multipleBluetoothController != null) {
|
||||
return multipleBluetoothController.getBleBluetooth(bleDevice);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public BluetoothGatt getBluetoothGatt(BleDevice bleDevice) {
|
||||
BleBluetooth bleBluetooth = getBleBluetooth(bleDevice);
|
||||
if (bleBluetooth != null)
|
||||
return bleBluetooth.getBluetoothGatt();
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<BluetoothGattService> getBluetoothGattServices(BleDevice bleDevice) {
|
||||
BluetoothGatt gatt = getBluetoothGatt(bleDevice);
|
||||
if (gatt != null) {
|
||||
return gatt.getServices();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<BluetoothGattCharacteristic> getBluetoothGattCharacteristics(BluetoothGattService service) {
|
||||
return service.getCharacteristics();
|
||||
}
|
||||
|
||||
public void removeConnectGattCallback(BleDevice bleDevice) {
|
||||
BleBluetooth bleBluetooth = getBleBluetooth(bleDevice);
|
||||
if (bleBluetooth != null)
|
||||
bleBluetooth.removeConnectGattCallback();
|
||||
}
|
||||
|
||||
public void removeRssiCallback(BleDevice bleDevice) {
|
||||
BleBluetooth bleBluetooth = getBleBluetooth(bleDevice);
|
||||
if (bleBluetooth != null)
|
||||
bleBluetooth.removeRssiCallback();
|
||||
}
|
||||
|
||||
public void removeMtuChangedCallback(BleDevice bleDevice) {
|
||||
BleBluetooth bleBluetooth = getBleBluetooth(bleDevice);
|
||||
if (bleBluetooth != null)
|
||||
bleBluetooth.removeMtuChangedCallback();
|
||||
}
|
||||
|
||||
public void removeNotifyCallback(BleDevice bleDevice, String uuid_notify) {
|
||||
BleBluetooth bleBluetooth = getBleBluetooth(bleDevice);
|
||||
if (bleBluetooth != null)
|
||||
bleBluetooth.removeNotifyCallback(uuid_notify);
|
||||
}
|
||||
|
||||
public void removeIndicateCallback(BleDevice bleDevice, String uuid_indicate) {
|
||||
BleBluetooth bleBluetooth = getBleBluetooth(bleDevice);
|
||||
if (bleBluetooth != null)
|
||||
bleBluetooth.removeIndicateCallback(uuid_indicate);
|
||||
}
|
||||
|
||||
public void removeWriteCallback(BleDevice bleDevice, String uuid_write) {
|
||||
BleBluetooth bleBluetooth = getBleBluetooth(bleDevice);
|
||||
if (bleBluetooth != null)
|
||||
bleBluetooth.removeWriteCallback(uuid_write);
|
||||
}
|
||||
|
||||
public void removeReadCallback(BleDevice bleDevice, String uuid_read) {
|
||||
BleBluetooth bleBluetooth = getBleBluetooth(bleDevice);
|
||||
if (bleBluetooth != null)
|
||||
bleBluetooth.removeReadCallback(uuid_read);
|
||||
}
|
||||
|
||||
public void clearCharacterCallback(BleDevice bleDevice) {
|
||||
BleBluetooth bleBluetooth = getBleBluetooth(bleDevice);
|
||||
if (bleBluetooth != null)
|
||||
bleBluetooth.clearCharacterCallback();
|
||||
}
|
||||
|
||||
public BleScanState getScanSate() {
|
||||
return BleScanner.getInstance().getScanState();
|
||||
}
|
||||
|
||||
public List<BleDevice> getAllConnectedDevice() {
|
||||
if (multipleBluetoothController == null)
|
||||
return null;
|
||||
return multipleBluetoothController.getDeviceList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bleDevice
|
||||
* @return State of the profile connection. One of
|
||||
* {@link BluetoothProfile#STATE_CONNECTED},
|
||||
* {@link BluetoothProfile#STATE_CONNECTING},
|
||||
* {@link BluetoothProfile#STATE_DISCONNECTED},
|
||||
* {@link BluetoothProfile#STATE_DISCONNECTING}
|
||||
*/
|
||||
public int getConnectState(BleDevice bleDevice) {
|
||||
if (bleDevice != null) {
|
||||
return bluetoothManager.getConnectionState(bleDevice.getDevice(),
|
||||
BluetoothProfile.GATT);
|
||||
} else {
|
||||
return BluetoothProfile.STATE_DISCONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isConnected(BleDevice bleDevice) {
|
||||
if (!isBlueEnable())
|
||||
return false;
|
||||
return getConnectState(bleDevice) == BluetoothProfile.STATE_CONNECTED;
|
||||
}
|
||||
|
||||
public boolean isConnected(String mac) {
|
||||
if (!isBlueEnable())
|
||||
return false;
|
||||
List<BleDevice> list = getAllConnectedDevice();
|
||||
for (BleDevice bleDevice : list) {
|
||||
if (bleDevice != null) {
|
||||
if (bleDevice.getMac().equals(mac)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void disconnect(BleDevice bleDevice) {
|
||||
if (multipleBluetoothController != null) {
|
||||
multipleBluetoothController.disconnect(bleDevice);
|
||||
}
|
||||
}
|
||||
|
||||
public void disconnectAllDevice() {
|
||||
if (multipleBluetoothController != null) {
|
||||
multipleBluetoothController.disconnectAllDevice();
|
||||
}
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
if (multipleBluetoothController != null) {
|
||||
multipleBluetoothController.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,612 @@
|
||||
package com.clj.fastble.bluetooth;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.bluetooth.BluetoothGatt;
|
||||
import android.bluetooth.BluetoothGattCallback;
|
||||
import android.bluetooth.BluetoothGattCharacteristic;
|
||||
import android.bluetooth.BluetoothGattDescriptor;
|
||||
import android.bluetooth.BluetoothProfile;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
|
||||
import com.clj.fastble.BleManager;
|
||||
import com.clj.fastble.callback.BleGattCallback;
|
||||
import com.clj.fastble.callback.BleIndicateCallback;
|
||||
import com.clj.fastble.callback.BleMtuChangedCallback;
|
||||
import com.clj.fastble.callback.BleNotifyCallback;
|
||||
import com.clj.fastble.callback.BleReadCallback;
|
||||
import com.clj.fastble.callback.BleRssiCallback;
|
||||
import com.clj.fastble.callback.BleWriteCallback;
|
||||
import com.clj.fastble.data.BleConnectStateParameter;
|
||||
import com.clj.fastble.data.BleDevice;
|
||||
import com.clj.fastble.data.BleMsg;
|
||||
import com.clj.fastble.exception.ConnectException;
|
||||
import com.clj.fastble.exception.OtherException;
|
||||
import com.clj.fastble.exception.TimeoutException;
|
||||
import com.clj.fastble.utils.BleLog;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import static android.bluetooth.BluetoothDevice.TRANSPORT_LE;
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
|
||||
public class BleBluetooth {
|
||||
|
||||
private BleGattCallback bleGattCallback;
|
||||
private BleRssiCallback bleRssiCallback;
|
||||
private BleMtuChangedCallback bleMtuChangedCallback;
|
||||
private final HashMap<String, BleNotifyCallback> bleNotifyCallbackHashMap = new HashMap<>();
|
||||
private final HashMap<String, BleIndicateCallback> bleIndicateCallbackHashMap = new HashMap<>();
|
||||
private final HashMap<String, BleWriteCallback> bleWriteCallbackHashMap = new HashMap<>();
|
||||
private final HashMap<String, BleReadCallback> bleReadCallbackHashMap = new HashMap<>();
|
||||
|
||||
private LastState lastState;
|
||||
private boolean isActiveDisconnect = false;
|
||||
private final BleDevice bleDevice;
|
||||
private BluetoothGatt bluetoothGatt;
|
||||
private final MainHandler mainHandler = new MainHandler(Looper.getMainLooper());
|
||||
private int connectRetryCount = 0;
|
||||
|
||||
public BleBluetooth(BleDevice bleDevice) {
|
||||
this.bleDevice = bleDevice;
|
||||
}
|
||||
|
||||
public BleConnector newBleConnector() {
|
||||
return new BleConnector(this);
|
||||
}
|
||||
|
||||
public synchronized void addConnectGattCallback(BleGattCallback callback) {
|
||||
bleGattCallback = callback;
|
||||
}
|
||||
|
||||
public synchronized void removeConnectGattCallback() {
|
||||
bleGattCallback = null;
|
||||
}
|
||||
|
||||
public synchronized void addNotifyCallback(String uuid, BleNotifyCallback bleNotifyCallback) {
|
||||
bleNotifyCallbackHashMap.put(uuid, bleNotifyCallback);
|
||||
}
|
||||
|
||||
public synchronized void addIndicateCallback(String uuid, BleIndicateCallback bleIndicateCallback) {
|
||||
bleIndicateCallbackHashMap.put(uuid, bleIndicateCallback);
|
||||
}
|
||||
|
||||
public synchronized void addWriteCallback(String uuid, BleWriteCallback bleWriteCallback) {
|
||||
bleWriteCallbackHashMap.put(uuid, bleWriteCallback);
|
||||
}
|
||||
|
||||
public synchronized void addReadCallback(String uuid, BleReadCallback bleReadCallback) {
|
||||
bleReadCallbackHashMap.put(uuid, bleReadCallback);
|
||||
}
|
||||
|
||||
public synchronized void removeNotifyCallback(String uuid) {
|
||||
if (bleNotifyCallbackHashMap.containsKey(uuid))
|
||||
bleNotifyCallbackHashMap.remove(uuid);
|
||||
}
|
||||
|
||||
public synchronized void removeIndicateCallback(String uuid) {
|
||||
if (bleIndicateCallbackHashMap.containsKey(uuid))
|
||||
bleIndicateCallbackHashMap.remove(uuid);
|
||||
}
|
||||
|
||||
public synchronized void removeWriteCallback(String uuid) {
|
||||
if (bleWriteCallbackHashMap.containsKey(uuid))
|
||||
bleWriteCallbackHashMap.remove(uuid);
|
||||
}
|
||||
|
||||
public synchronized void removeReadCallback(String uuid) {
|
||||
if (bleReadCallbackHashMap.containsKey(uuid))
|
||||
bleReadCallbackHashMap.remove(uuid);
|
||||
}
|
||||
|
||||
public synchronized void clearCharacterCallback() {
|
||||
bleNotifyCallbackHashMap.clear();
|
||||
bleIndicateCallbackHashMap.clear();
|
||||
bleWriteCallbackHashMap.clear();
|
||||
bleReadCallbackHashMap.clear();
|
||||
}
|
||||
|
||||
public synchronized void addRssiCallback(BleRssiCallback callback) {
|
||||
bleRssiCallback = callback;
|
||||
}
|
||||
|
||||
public synchronized void removeRssiCallback() {
|
||||
bleRssiCallback = null;
|
||||
}
|
||||
|
||||
public synchronized void addMtuChangedCallback(BleMtuChangedCallback callback) {
|
||||
bleMtuChangedCallback = callback;
|
||||
}
|
||||
|
||||
public synchronized void removeMtuChangedCallback() {
|
||||
bleMtuChangedCallback = null;
|
||||
}
|
||||
|
||||
|
||||
public String getDeviceKey() {
|
||||
return bleDevice.getKey();
|
||||
}
|
||||
|
||||
public BleDevice getDevice() {
|
||||
return bleDevice;
|
||||
}
|
||||
|
||||
public BluetoothGatt getBluetoothGatt() {
|
||||
return bluetoothGatt;
|
||||
}
|
||||
|
||||
public synchronized BluetoothGatt connect(BleDevice bleDevice,
|
||||
boolean autoConnect,
|
||||
BleGattCallback callback) {
|
||||
return connect(bleDevice, autoConnect, callback, 0);
|
||||
}
|
||||
|
||||
public synchronized BluetoothGatt connect(BleDevice bleDevice,
|
||||
boolean autoConnect,
|
||||
BleGattCallback callback,
|
||||
int connectRetryCount) {
|
||||
BleLog.i("connect device: " + bleDevice.getName()
|
||||
+ "\nmac: " + bleDevice.getMac()
|
||||
+ "\nautoConnect: " + autoConnect
|
||||
+ "\ncurrentThread: " + Thread.currentThread().getId()
|
||||
+ "\nconnectCount:" + (connectRetryCount + 1));
|
||||
if (connectRetryCount == 0) {
|
||||
this.connectRetryCount = 0;
|
||||
}
|
||||
|
||||
addConnectGattCallback(callback);
|
||||
|
||||
lastState = LastState.CONNECT_CONNECTING;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
bluetoothGatt = bleDevice.getDevice().connectGatt(BleManager.getInstance().getContext(),
|
||||
autoConnect, coreGattCallback, TRANSPORT_LE);
|
||||
} else {
|
||||
bluetoothGatt = bleDevice.getDevice().connectGatt(BleManager.getInstance().getContext(),
|
||||
autoConnect, coreGattCallback);
|
||||
}
|
||||
if (bluetoothGatt != null) {
|
||||
if (bleGattCallback != null) {
|
||||
bleGattCallback.onStartConnect();
|
||||
}
|
||||
Message message = mainHandler.obtainMessage();
|
||||
message.what = BleMsg.MSG_CONNECT_OVER_TIME;
|
||||
mainHandler.sendMessageDelayed(message, BleManager.getInstance().getConnectOverTime());
|
||||
|
||||
} else {
|
||||
disconnectGatt();
|
||||
refreshDeviceCache();
|
||||
closeBluetoothGatt();
|
||||
lastState = LastState.CONNECT_FAILURE;
|
||||
BleManager.getInstance().getMultipleBluetoothController().removeConnectingBle(BleBluetooth.this);
|
||||
if (bleGattCallback != null)
|
||||
bleGattCallback.onConnectFail(bleDevice, new OtherException("GATT connect exception occurred!"));
|
||||
|
||||
}
|
||||
return bluetoothGatt;
|
||||
}
|
||||
|
||||
public synchronized void disconnect() {
|
||||
isActiveDisconnect = true;
|
||||
disconnectGatt();
|
||||
}
|
||||
|
||||
public synchronized void destroy() {
|
||||
lastState = LastState.CONNECT_IDLE;
|
||||
disconnectGatt();
|
||||
refreshDeviceCache();
|
||||
closeBluetoothGatt();
|
||||
removeConnectGattCallback();
|
||||
removeRssiCallback();
|
||||
removeMtuChangedCallback();
|
||||
clearCharacterCallback();
|
||||
mainHandler.removeCallbacksAndMessages(null);
|
||||
}
|
||||
|
||||
private synchronized void disconnectGatt() {
|
||||
if (bluetoothGatt != null) {
|
||||
bluetoothGatt.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void refreshDeviceCache() {
|
||||
try {
|
||||
final Method refresh = BluetoothGatt.class.getMethod("refresh");
|
||||
if (refresh != null && bluetoothGatt != null) {
|
||||
boolean success = (Boolean) refresh.invoke(bluetoothGatt);
|
||||
BleLog.i("refreshDeviceCache, is success: " + success);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
BleLog.i("exception occur while refreshing device: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void closeBluetoothGatt() {
|
||||
if (bluetoothGatt != null) {
|
||||
bluetoothGatt.close();
|
||||
}
|
||||
}
|
||||
|
||||
private final class MainHandler extends Handler {
|
||||
|
||||
MainHandler(Looper looper) {
|
||||
super(looper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case BleMsg.MSG_CONNECT_FAIL: {
|
||||
disconnectGatt();
|
||||
refreshDeviceCache();
|
||||
closeBluetoothGatt();
|
||||
|
||||
if (connectRetryCount < BleManager.getInstance().getReConnectCount()) {
|
||||
BleLog.e("Connect fail, try reconnect " + BleManager.getInstance().getReConnectInterval() + " millisecond later");
|
||||
++connectRetryCount;
|
||||
|
||||
Message message = mainHandler.obtainMessage();
|
||||
message.what = BleMsg.MSG_RECONNECT;
|
||||
mainHandler.sendMessageDelayed(message, BleManager.getInstance().getReConnectInterval());
|
||||
} else {
|
||||
lastState = LastState.CONNECT_FAILURE;
|
||||
BleManager.getInstance().getMultipleBluetoothController().removeConnectingBle(BleBluetooth.this);
|
||||
|
||||
BleConnectStateParameter para = (BleConnectStateParameter) msg.obj;
|
||||
int status = para.getStatus();
|
||||
if (bleGattCallback != null)
|
||||
bleGattCallback.onConnectFail(bleDevice, new ConnectException(bluetoothGatt, status));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BleMsg.MSG_DISCONNECTED: {
|
||||
lastState = LastState.CONNECT_DISCONNECT;
|
||||
BleManager.getInstance().getMultipleBluetoothController().removeBleBluetooth(BleBluetooth.this);
|
||||
|
||||
disconnect();
|
||||
refreshDeviceCache();
|
||||
closeBluetoothGatt();
|
||||
removeRssiCallback();
|
||||
removeMtuChangedCallback();
|
||||
clearCharacterCallback();
|
||||
mainHandler.removeCallbacksAndMessages(null);
|
||||
|
||||
BleConnectStateParameter para = (BleConnectStateParameter) msg.obj;
|
||||
boolean isActive = para.isActive();
|
||||
int status = para.getStatus();
|
||||
if (bleGattCallback != null)
|
||||
bleGattCallback.onDisConnected(isActive, bleDevice, bluetoothGatt, status);
|
||||
}
|
||||
break;
|
||||
|
||||
case BleMsg.MSG_RECONNECT: {
|
||||
connect(bleDevice, false, bleGattCallback, connectRetryCount);
|
||||
}
|
||||
break;
|
||||
|
||||
case BleMsg.MSG_CONNECT_OVER_TIME: {
|
||||
disconnectGatt();
|
||||
refreshDeviceCache();
|
||||
closeBluetoothGatt();
|
||||
|
||||
lastState = LastState.CONNECT_FAILURE;
|
||||
BleManager.getInstance().getMultipleBluetoothController().removeConnectingBle(BleBluetooth.this);
|
||||
|
||||
if (bleGattCallback != null)
|
||||
bleGattCallback.onConnectFail(bleDevice, new TimeoutException());
|
||||
}
|
||||
break;
|
||||
|
||||
case BleMsg.MSG_DISCOVER_SERVICES: {
|
||||
if (bluetoothGatt != null) {
|
||||
boolean discoverServiceResult = bluetoothGatt.discoverServices();
|
||||
if (!discoverServiceResult) {
|
||||
Message message = mainHandler.obtainMessage();
|
||||
message.what = BleMsg.MSG_DISCOVER_FAIL;
|
||||
mainHandler.sendMessage(message);
|
||||
}
|
||||
} else {
|
||||
Message message = mainHandler.obtainMessage();
|
||||
message.what = BleMsg.MSG_DISCOVER_FAIL;
|
||||
mainHandler.sendMessage(message);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BleMsg.MSG_DISCOVER_FAIL: {
|
||||
disconnectGatt();
|
||||
refreshDeviceCache();
|
||||
closeBluetoothGatt();
|
||||
|
||||
lastState = LastState.CONNECT_FAILURE;
|
||||
BleManager.getInstance().getMultipleBluetoothController().removeConnectingBle(BleBluetooth.this);
|
||||
|
||||
if (bleGattCallback != null)
|
||||
bleGattCallback.onConnectFail(bleDevice,
|
||||
new OtherException("GATT discover services exception occurred!"));
|
||||
}
|
||||
break;
|
||||
|
||||
case BleMsg.MSG_DISCOVER_SUCCESS: {
|
||||
lastState = LastState.CONNECT_CONNECTED;
|
||||
isActiveDisconnect = false;
|
||||
BleManager.getInstance().getMultipleBluetoothController().removeConnectingBle(BleBluetooth.this);
|
||||
BleManager.getInstance().getMultipleBluetoothController().addBleBluetooth(BleBluetooth.this);
|
||||
|
||||
BleConnectStateParameter para = (BleConnectStateParameter) msg.obj;
|
||||
int status = para.getStatus();
|
||||
if (bleGattCallback != null)
|
||||
bleGattCallback.onConnectSuccess(bleDevice, bluetoothGatt, status);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
super.handleMessage(msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private BluetoothGattCallback coreGattCallback = new BluetoothGattCallback() {
|
||||
|
||||
@Override
|
||||
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
|
||||
super.onConnectionStateChange(gatt, status, newState);
|
||||
BleLog.i("BluetoothGattCallback:onConnectionStateChange "
|
||||
+ '\n' + "status: " + status
|
||||
+ '\n' + "newState: " + newState
|
||||
+ '\n' + "currentThread: " + Thread.currentThread().getId());
|
||||
|
||||
bluetoothGatt = gatt;
|
||||
|
||||
mainHandler.removeMessages(BleMsg.MSG_CONNECT_OVER_TIME);
|
||||
|
||||
if (newState == BluetoothProfile.STATE_CONNECTED) {
|
||||
Message message = mainHandler.obtainMessage();
|
||||
message.what = BleMsg.MSG_DISCOVER_SERVICES;
|
||||
mainHandler.sendMessageDelayed(message, 500);
|
||||
|
||||
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
|
||||
if (lastState == LastState.CONNECT_CONNECTING) {
|
||||
Message message = mainHandler.obtainMessage();
|
||||
message.what = BleMsg.MSG_CONNECT_FAIL;
|
||||
message.obj = new BleConnectStateParameter(status);
|
||||
mainHandler.sendMessage(message);
|
||||
|
||||
} else if (lastState == LastState.CONNECT_CONNECTED) {
|
||||
Message message = mainHandler.obtainMessage();
|
||||
message.what = BleMsg.MSG_DISCONNECTED;
|
||||
BleConnectStateParameter para = new BleConnectStateParameter(status);
|
||||
para.setActive(isActiveDisconnect);
|
||||
message.obj = para;
|
||||
mainHandler.sendMessage(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
|
||||
super.onServicesDiscovered(gatt, status);
|
||||
BleLog.i("BluetoothGattCallback:onServicesDiscovered "
|
||||
+ '\n' + "status: " + status
|
||||
+ '\n' + "currentThread: " + Thread.currentThread().getId());
|
||||
|
||||
bluetoothGatt = gatt;
|
||||
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
Message message = mainHandler.obtainMessage();
|
||||
message.what = BleMsg.MSG_DISCOVER_SUCCESS;
|
||||
message.obj = new BleConnectStateParameter(status);
|
||||
mainHandler.sendMessage(message);
|
||||
|
||||
} else {
|
||||
Message message = mainHandler.obtainMessage();
|
||||
message.what = BleMsg.MSG_DISCOVER_FAIL;
|
||||
mainHandler.sendMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
|
||||
super.onCharacteristicChanged(gatt, characteristic);
|
||||
|
||||
Iterator iterator = bleNotifyCallbackHashMap.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry entry = (Map.Entry) iterator.next();
|
||||
Object callback = entry.getValue();
|
||||
if (callback instanceof BleNotifyCallback) {
|
||||
BleNotifyCallback bleNotifyCallback = (BleNotifyCallback) callback;
|
||||
if (characteristic.getUuid().toString().equalsIgnoreCase(bleNotifyCallback.getKey())) {
|
||||
Handler handler = bleNotifyCallback.getHandler();
|
||||
if (handler != null) {
|
||||
Message message = handler.obtainMessage();
|
||||
message.what = BleMsg.MSG_CHA_NOTIFY_DATA_CHANGE;
|
||||
message.obj = bleNotifyCallback;
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putByteArray(BleMsg.KEY_NOTIFY_BUNDLE_VALUE, characteristic.getValue());
|
||||
message.setData(bundle);
|
||||
handler.sendMessage(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iterator = bleIndicateCallbackHashMap.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry entry = (Map.Entry) iterator.next();
|
||||
Object callback = entry.getValue();
|
||||
if (callback instanceof BleIndicateCallback) {
|
||||
BleIndicateCallback bleIndicateCallback = (BleIndicateCallback) callback;
|
||||
if (characteristic.getUuid().toString().equalsIgnoreCase(bleIndicateCallback.getKey())) {
|
||||
Handler handler = bleIndicateCallback.getHandler();
|
||||
if (handler != null) {
|
||||
Message message = handler.obtainMessage();
|
||||
message.what = BleMsg.MSG_CHA_INDICATE_DATA_CHANGE;
|
||||
message.obj = bleIndicateCallback;
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putByteArray(BleMsg.KEY_INDICATE_BUNDLE_VALUE, characteristic.getValue());
|
||||
message.setData(bundle);
|
||||
handler.sendMessage(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
|
||||
super.onDescriptorWrite(gatt, descriptor, status);
|
||||
|
||||
Iterator iterator = bleNotifyCallbackHashMap.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry entry = (Map.Entry) iterator.next();
|
||||
Object callback = entry.getValue();
|
||||
if (callback instanceof BleNotifyCallback) {
|
||||
BleNotifyCallback bleNotifyCallback = (BleNotifyCallback) callback;
|
||||
if (descriptor.getCharacteristic().getUuid().toString().equalsIgnoreCase(bleNotifyCallback.getKey())) {
|
||||
Handler handler = bleNotifyCallback.getHandler();
|
||||
if (handler != null) {
|
||||
Message message = handler.obtainMessage();
|
||||
message.what = BleMsg.MSG_CHA_NOTIFY_RESULT;
|
||||
message.obj = bleNotifyCallback;
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt(BleMsg.KEY_NOTIFY_BUNDLE_STATUS, status);
|
||||
message.setData(bundle);
|
||||
handler.sendMessage(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iterator = bleIndicateCallbackHashMap.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry entry = (Map.Entry) iterator.next();
|
||||
Object callback = entry.getValue();
|
||||
if (callback instanceof BleIndicateCallback) {
|
||||
BleIndicateCallback bleIndicateCallback = (BleIndicateCallback) callback;
|
||||
if (descriptor.getCharacteristic().getUuid().toString().equalsIgnoreCase(bleIndicateCallback.getKey())) {
|
||||
Handler handler = bleIndicateCallback.getHandler();
|
||||
if (handler != null) {
|
||||
Message message = handler.obtainMessage();
|
||||
message.what = BleMsg.MSG_CHA_INDICATE_RESULT;
|
||||
message.obj = bleIndicateCallback;
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt(BleMsg.KEY_INDICATE_BUNDLE_STATUS, status);
|
||||
message.setData(bundle);
|
||||
handler.sendMessage(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
|
||||
super.onCharacteristicWrite(gatt, characteristic, status);
|
||||
|
||||
Iterator iterator = bleWriteCallbackHashMap.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry entry = (Map.Entry) iterator.next();
|
||||
Object callback = entry.getValue();
|
||||
if (callback instanceof BleWriteCallback) {
|
||||
BleWriteCallback bleWriteCallback = (BleWriteCallback) callback;
|
||||
if (characteristic.getUuid().toString().equalsIgnoreCase(bleWriteCallback.getKey())) {
|
||||
Handler handler = bleWriteCallback.getHandler();
|
||||
if (handler != null) {
|
||||
Message message = handler.obtainMessage();
|
||||
message.what = BleMsg.MSG_CHA_WRITE_RESULT;
|
||||
message.obj = bleWriteCallback;
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt(BleMsg.KEY_WRITE_BUNDLE_STATUS, status);
|
||||
bundle.putByteArray(BleMsg.KEY_WRITE_BUNDLE_VALUE, characteristic.getValue());
|
||||
message.setData(bundle);
|
||||
handler.sendMessage(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
|
||||
super.onCharacteristicRead(gatt, characteristic, status);
|
||||
|
||||
Iterator iterator = bleReadCallbackHashMap.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry entry = (Map.Entry) iterator.next();
|
||||
Object callback = entry.getValue();
|
||||
if (callback instanceof BleReadCallback) {
|
||||
BleReadCallback bleReadCallback = (BleReadCallback) callback;
|
||||
if (characteristic.getUuid().toString().equalsIgnoreCase(bleReadCallback.getKey())) {
|
||||
Handler handler = bleReadCallback.getHandler();
|
||||
if (handler != null) {
|
||||
Message message = handler.obtainMessage();
|
||||
message.what = BleMsg.MSG_CHA_READ_RESULT;
|
||||
message.obj = bleReadCallback;
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt(BleMsg.KEY_READ_BUNDLE_STATUS, status);
|
||||
bundle.putByteArray(BleMsg.KEY_READ_BUNDLE_VALUE, characteristic.getValue());
|
||||
message.setData(bundle);
|
||||
handler.sendMessage(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
|
||||
super.onReadRemoteRssi(gatt, rssi, status);
|
||||
|
||||
if (bleRssiCallback != null) {
|
||||
Handler handler = bleRssiCallback.getHandler();
|
||||
if (handler != null) {
|
||||
Message message = handler.obtainMessage();
|
||||
message.what = BleMsg.MSG_READ_RSSI_RESULT;
|
||||
message.obj = bleRssiCallback;
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt(BleMsg.KEY_READ_RSSI_BUNDLE_STATUS, status);
|
||||
bundle.putInt(BleMsg.KEY_READ_RSSI_BUNDLE_VALUE, rssi);
|
||||
message.setData(bundle);
|
||||
handler.sendMessage(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
|
||||
super.onMtuChanged(gatt, mtu, status);
|
||||
|
||||
if (bleMtuChangedCallback != null) {
|
||||
Handler handler = bleMtuChangedCallback.getHandler();
|
||||
if (handler != null) {
|
||||
Message message = handler.obtainMessage();
|
||||
message.what = BleMsg.MSG_SET_MTU_RESULT;
|
||||
message.obj = bleMtuChangedCallback;
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt(BleMsg.KEY_SET_MTU_BUNDLE_STATUS, status);
|
||||
bundle.putInt(BleMsg.KEY_SET_MTU_BUNDLE_VALUE, mtu);
|
||||
message.setData(bundle);
|
||||
handler.sendMessage(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
enum LastState {
|
||||
CONNECT_IDLE,
|
||||
CONNECT_CONNECTING,
|
||||
CONNECT_CONNECTED,
|
||||
CONNECT_FAILURE,
|
||||
CONNECT_DISCONNECT
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,608 @@
|
||||
|
||||
package com.clj.fastble.bluetooth;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.bluetooth.BluetoothGatt;
|
||||
import android.bluetooth.BluetoothGattCharacteristic;
|
||||
import android.bluetooth.BluetoothGattDescriptor;
|
||||
import android.bluetooth.BluetoothGattService;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
|
||||
import com.clj.fastble.BleManager;
|
||||
import com.clj.fastble.callback.BleIndicateCallback;
|
||||
import com.clj.fastble.callback.BleMtuChangedCallback;
|
||||
import com.clj.fastble.callback.BleNotifyCallback;
|
||||
import com.clj.fastble.callback.BleReadCallback;
|
||||
import com.clj.fastble.callback.BleRssiCallback;
|
||||
import com.clj.fastble.callback.BleWriteCallback;
|
||||
import com.clj.fastble.data.BleMsg;
|
||||
import com.clj.fastble.data.BleWriteState;
|
||||
import com.clj.fastble.exception.GattException;
|
||||
import com.clj.fastble.exception.OtherException;
|
||||
import com.clj.fastble.exception.TimeoutException;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
|
||||
public class BleConnector {
|
||||
|
||||
private static final String UUID_CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR = "00002902-0000-1000-8000-00805f9b34fb";
|
||||
|
||||
private BluetoothGatt mBluetoothGatt;
|
||||
private BluetoothGattService mGattService;
|
||||
private BluetoothGattCharacteristic mCharacteristic;
|
||||
private BleBluetooth mBleBluetooth;
|
||||
private Handler mHandler;
|
||||
|
||||
BleConnector(BleBluetooth bleBluetooth) {
|
||||
this.mBleBluetooth = bleBluetooth;
|
||||
this.mBluetoothGatt = bleBluetooth.getBluetoothGatt();
|
||||
this.mHandler = new Handler(Looper.getMainLooper()) {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
super.handleMessage(msg);
|
||||
switch (msg.what) {
|
||||
|
||||
case BleMsg.MSG_CHA_NOTIFY_START: {
|
||||
BleNotifyCallback notifyCallback = (BleNotifyCallback) msg.obj;
|
||||
if (notifyCallback != null)
|
||||
notifyCallback.onNotifyFailure(new TimeoutException());
|
||||
break;
|
||||
}
|
||||
|
||||
case BleMsg.MSG_CHA_NOTIFY_RESULT: {
|
||||
notifyMsgInit();
|
||||
|
||||
BleNotifyCallback notifyCallback = (BleNotifyCallback) msg.obj;
|
||||
Bundle bundle = msg.getData();
|
||||
int status = bundle.getInt(BleMsg.KEY_NOTIFY_BUNDLE_STATUS);
|
||||
if (notifyCallback != null) {
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
notifyCallback.onNotifySuccess();
|
||||
} else {
|
||||
notifyCallback.onNotifyFailure(new GattException(status));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BleMsg.MSG_CHA_NOTIFY_DATA_CHANGE: {
|
||||
BleNotifyCallback notifyCallback = (BleNotifyCallback) msg.obj;
|
||||
Bundle bundle = msg.getData();
|
||||
byte[] value = bundle.getByteArray(BleMsg.KEY_NOTIFY_BUNDLE_VALUE);
|
||||
if (notifyCallback != null) {
|
||||
notifyCallback.onCharacteristicChanged(value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BleMsg.MSG_CHA_INDICATE_START: {
|
||||
BleIndicateCallback indicateCallback = (BleIndicateCallback) msg.obj;
|
||||
if (indicateCallback != null)
|
||||
indicateCallback.onIndicateFailure(new TimeoutException());
|
||||
break;
|
||||
}
|
||||
|
||||
case BleMsg.MSG_CHA_INDICATE_RESULT: {
|
||||
indicateMsgInit();
|
||||
|
||||
BleIndicateCallback indicateCallback = (BleIndicateCallback) msg.obj;
|
||||
Bundle bundle = msg.getData();
|
||||
int status = bundle.getInt(BleMsg.KEY_INDICATE_BUNDLE_STATUS);
|
||||
if (indicateCallback != null) {
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
indicateCallback.onIndicateSuccess();
|
||||
} else {
|
||||
indicateCallback.onIndicateFailure(new GattException(status));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BleMsg.MSG_CHA_INDICATE_DATA_CHANGE: {
|
||||
BleIndicateCallback indicateCallback = (BleIndicateCallback) msg.obj;
|
||||
Bundle bundle = msg.getData();
|
||||
byte[] value = bundle.getByteArray(BleMsg.KEY_INDICATE_BUNDLE_VALUE);
|
||||
if (indicateCallback != null) {
|
||||
indicateCallback.onCharacteristicChanged(value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BleMsg.MSG_CHA_WRITE_START: {
|
||||
BleWriteCallback writeCallback = (BleWriteCallback) msg.obj;
|
||||
if (writeCallback != null) {
|
||||
writeCallback.onWriteFailure(new TimeoutException());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BleMsg.MSG_CHA_WRITE_RESULT: {
|
||||
writeMsgInit();
|
||||
|
||||
BleWriteCallback writeCallback = (BleWriteCallback) msg.obj;
|
||||
Bundle bundle = msg.getData();
|
||||
int status = bundle.getInt(BleMsg.KEY_WRITE_BUNDLE_STATUS);
|
||||
byte[] value = bundle.getByteArray(BleMsg.KEY_WRITE_BUNDLE_VALUE);
|
||||
if (writeCallback != null) {
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
writeCallback.onWriteSuccess(BleWriteState.DATA_WRITE_SINGLE, BleWriteState.DATA_WRITE_SINGLE, value);
|
||||
} else {
|
||||
writeCallback.onWriteFailure(new GattException(status));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BleMsg.MSG_CHA_READ_START: {
|
||||
BleReadCallback readCallback = (BleReadCallback) msg.obj;
|
||||
if (readCallback != null)
|
||||
readCallback.onReadFailure(new TimeoutException());
|
||||
break;
|
||||
}
|
||||
|
||||
case BleMsg.MSG_CHA_READ_RESULT: {
|
||||
readMsgInit();
|
||||
|
||||
BleReadCallback readCallback = (BleReadCallback) msg.obj;
|
||||
Bundle bundle = msg.getData();
|
||||
int status = bundle.getInt(BleMsg.KEY_READ_BUNDLE_STATUS);
|
||||
byte[] value = bundle.getByteArray(BleMsg.KEY_READ_BUNDLE_VALUE);
|
||||
if (readCallback != null) {
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
readCallback.onReadSuccess(value);
|
||||
} else {
|
||||
readCallback.onReadFailure(new GattException(status));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BleMsg.MSG_READ_RSSI_START: {
|
||||
BleRssiCallback rssiCallback = (BleRssiCallback) msg.obj;
|
||||
if (rssiCallback != null)
|
||||
rssiCallback.onRssiFailure(new TimeoutException());
|
||||
break;
|
||||
}
|
||||
|
||||
case BleMsg.MSG_READ_RSSI_RESULT: {
|
||||
rssiMsgInit();
|
||||
|
||||
BleRssiCallback rssiCallback = (BleRssiCallback) msg.obj;
|
||||
Bundle bundle = msg.getData();
|
||||
int status = bundle.getInt(BleMsg.KEY_READ_RSSI_BUNDLE_STATUS);
|
||||
int value = bundle.getInt(BleMsg.KEY_READ_RSSI_BUNDLE_VALUE);
|
||||
if (rssiCallback != null) {
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
rssiCallback.onRssiSuccess(value);
|
||||
} else {
|
||||
rssiCallback.onRssiFailure(new GattException(status));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BleMsg.MSG_SET_MTU_START: {
|
||||
BleMtuChangedCallback mtuChangedCallback = (BleMtuChangedCallback) msg.obj;
|
||||
if (mtuChangedCallback != null)
|
||||
mtuChangedCallback.onSetMTUFailure(new TimeoutException());
|
||||
break;
|
||||
}
|
||||
|
||||
case BleMsg.MSG_SET_MTU_RESULT: {
|
||||
mtuChangedMsgInit();
|
||||
|
||||
BleMtuChangedCallback mtuChangedCallback = (BleMtuChangedCallback) msg.obj;
|
||||
Bundle bundle = msg.getData();
|
||||
int status = bundle.getInt(BleMsg.KEY_SET_MTU_BUNDLE_STATUS);
|
||||
int value = bundle.getInt(BleMsg.KEY_SET_MTU_BUNDLE_VALUE);
|
||||
if (mtuChangedCallback != null) {
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
mtuChangedCallback.onMtuChanged(value);
|
||||
} else {
|
||||
mtuChangedCallback.onSetMTUFailure(new GattException(status));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
private BleConnector withUUID(UUID serviceUUID, UUID characteristicUUID) {
|
||||
if (serviceUUID != null && mBluetoothGatt != null) {
|
||||
mGattService = mBluetoothGatt.getService(serviceUUID);
|
||||
}
|
||||
if (mGattService != null && characteristicUUID != null) {
|
||||
mCharacteristic = mGattService.getCharacteristic(characteristicUUID);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public BleConnector withUUIDString(String serviceUUID, String characteristicUUID) {
|
||||
return withUUID(formUUID(serviceUUID), formUUID(characteristicUUID));
|
||||
}
|
||||
|
||||
private UUID formUUID(String uuid) {
|
||||
return uuid == null ? null : UUID.fromString(uuid);
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------- main operation ----------------------------------- */
|
||||
|
||||
|
||||
/**
|
||||
* notify
|
||||
*/
|
||||
public void enableCharacteristicNotify(BleNotifyCallback bleNotifyCallback, String uuid_notify,
|
||||
boolean userCharacteristicDescriptor) {
|
||||
if (mCharacteristic != null
|
||||
&& (mCharacteristic.getProperties() | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
|
||||
|
||||
handleCharacteristicNotifyCallback(bleNotifyCallback, uuid_notify);
|
||||
setCharacteristicNotification(mBluetoothGatt, mCharacteristic, userCharacteristicDescriptor, true, bleNotifyCallback);
|
||||
} else {
|
||||
if (bleNotifyCallback != null)
|
||||
bleNotifyCallback.onNotifyFailure(new OtherException("this characteristic not support notify!"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* stop notify
|
||||
*/
|
||||
public boolean disableCharacteristicNotify(boolean useCharacteristicDescriptor) {
|
||||
if (mCharacteristic != null
|
||||
&& (mCharacteristic.getProperties() | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
|
||||
return setCharacteristicNotification(mBluetoothGatt, mCharacteristic,
|
||||
useCharacteristicDescriptor, false, null);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* notify setting
|
||||
*/
|
||||
private boolean setCharacteristicNotification(BluetoothGatt gatt,
|
||||
BluetoothGattCharacteristic characteristic,
|
||||
boolean useCharacteristicDescriptor,
|
||||
boolean enable,
|
||||
BleNotifyCallback bleNotifyCallback) {
|
||||
if (gatt == null || characteristic == null) {
|
||||
notifyMsgInit();
|
||||
if (bleNotifyCallback != null)
|
||||
bleNotifyCallback.onNotifyFailure(new OtherException("gatt or characteristic equal null"));
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean success1 = gatt.setCharacteristicNotification(characteristic, enable);
|
||||
if (!success1) {
|
||||
notifyMsgInit();
|
||||
if (bleNotifyCallback != null)
|
||||
bleNotifyCallback.onNotifyFailure(new OtherException("gatt setCharacteristicNotification fail"));
|
||||
return false;
|
||||
}
|
||||
|
||||
BluetoothGattDescriptor descriptor;
|
||||
if (useCharacteristicDescriptor) {
|
||||
descriptor = characteristic.getDescriptor(characteristic.getUuid());
|
||||
} else {
|
||||
descriptor = characteristic.getDescriptor(formUUID(UUID_CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR));
|
||||
}
|
||||
if (descriptor == null) {
|
||||
notifyMsgInit();
|
||||
if (bleNotifyCallback != null)
|
||||
bleNotifyCallback.onNotifyFailure(new OtherException("descriptor equals null"));
|
||||
return false;
|
||||
} else {
|
||||
descriptor.setValue(enable ? BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE :
|
||||
BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
|
||||
boolean success2 = gatt.writeDescriptor(descriptor);
|
||||
if (!success2) {
|
||||
notifyMsgInit();
|
||||
if (bleNotifyCallback != null)
|
||||
bleNotifyCallback.onNotifyFailure(new OtherException("gatt writeDescriptor fail"));
|
||||
}
|
||||
return success2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* indicate
|
||||
*/
|
||||
public void enableCharacteristicIndicate(BleIndicateCallback bleIndicateCallback, String uuid_indicate,
|
||||
boolean useCharacteristicDescriptor) {
|
||||
if (mCharacteristic != null
|
||||
&& (mCharacteristic.getProperties() | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
|
||||
handleCharacteristicIndicateCallback(bleIndicateCallback, uuid_indicate);
|
||||
setCharacteristicIndication(mBluetoothGatt, mCharacteristic,
|
||||
useCharacteristicDescriptor, true, bleIndicateCallback);
|
||||
} else {
|
||||
if (bleIndicateCallback != null)
|
||||
bleIndicateCallback.onIndicateFailure(new OtherException("this characteristic not support indicate!"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* stop indicate
|
||||
*/
|
||||
public boolean disableCharacteristicIndicate(boolean userCharacteristicDescriptor) {
|
||||
if (mCharacteristic != null
|
||||
&& (mCharacteristic.getProperties() | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
|
||||
return setCharacteristicIndication(mBluetoothGatt, mCharacteristic,
|
||||
userCharacteristicDescriptor, false, null);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* indicate setting
|
||||
*/
|
||||
private boolean setCharacteristicIndication(BluetoothGatt gatt,
|
||||
BluetoothGattCharacteristic characteristic,
|
||||
boolean useCharacteristicDescriptor,
|
||||
boolean enable,
|
||||
BleIndicateCallback bleIndicateCallback) {
|
||||
if (gatt == null || characteristic == null) {
|
||||
indicateMsgInit();
|
||||
if (bleIndicateCallback != null)
|
||||
bleIndicateCallback.onIndicateFailure(new OtherException("gatt or characteristic equal null"));
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean success1 = gatt.setCharacteristicNotification(characteristic, enable);
|
||||
if (!success1) {
|
||||
indicateMsgInit();
|
||||
if (bleIndicateCallback != null)
|
||||
bleIndicateCallback.onIndicateFailure(new OtherException("gatt setCharacteristicNotification fail"));
|
||||
return false;
|
||||
}
|
||||
|
||||
BluetoothGattDescriptor descriptor;
|
||||
if (useCharacteristicDescriptor) {
|
||||
descriptor = characteristic.getDescriptor(characteristic.getUuid());
|
||||
} else {
|
||||
descriptor = characteristic.getDescriptor(formUUID(UUID_CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR));
|
||||
}
|
||||
if (descriptor == null) {
|
||||
indicateMsgInit();
|
||||
if (bleIndicateCallback != null)
|
||||
bleIndicateCallback.onIndicateFailure(new OtherException("descriptor equals null"));
|
||||
return false;
|
||||
} else {
|
||||
descriptor.setValue(enable ? BluetoothGattDescriptor.ENABLE_INDICATION_VALUE :
|
||||
BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
|
||||
boolean success2 = gatt.writeDescriptor(descriptor);
|
||||
if (!success2) {
|
||||
indicateMsgInit();
|
||||
if (bleIndicateCallback != null)
|
||||
bleIndicateCallback.onIndicateFailure(new OtherException("gatt writeDescriptor fail"));
|
||||
}
|
||||
return success2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* write
|
||||
*/
|
||||
public void writeCharacteristic(byte[] data, BleWriteCallback bleWriteCallback, String uuid_write) {
|
||||
if (data == null || data.length <= 0) {
|
||||
if (bleWriteCallback != null)
|
||||
bleWriteCallback.onWriteFailure(new OtherException("the data to be written is empty"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (mCharacteristic == null
|
||||
|| (mCharacteristic.getProperties() & (BluetoothGattCharacteristic.PROPERTY_WRITE | BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE)) == 0) {
|
||||
if (bleWriteCallback != null)
|
||||
bleWriteCallback.onWriteFailure(new OtherException("this characteristic not support write!"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (mCharacteristic.setValue(data)) {
|
||||
handleCharacteristicWriteCallback(bleWriteCallback, uuid_write);
|
||||
if (!mBluetoothGatt.writeCharacteristic(mCharacteristic)) {
|
||||
writeMsgInit();
|
||||
if (bleWriteCallback != null)
|
||||
bleWriteCallback.onWriteFailure(new OtherException("gatt writeCharacteristic fail"));
|
||||
}
|
||||
} else {
|
||||
if (bleWriteCallback != null)
|
||||
bleWriteCallback.onWriteFailure(new OtherException("Updates the locally stored value of this characteristic fail"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* read
|
||||
*/
|
||||
public void readCharacteristic(BleReadCallback bleReadCallback, String uuid_read) {
|
||||
if (mCharacteristic != null
|
||||
&& (mCharacteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_READ) > 0) {
|
||||
|
||||
handleCharacteristicReadCallback(bleReadCallback, uuid_read);
|
||||
if (!mBluetoothGatt.readCharacteristic(mCharacteristic)) {
|
||||
readMsgInit();
|
||||
if (bleReadCallback != null)
|
||||
bleReadCallback.onReadFailure(new OtherException("gatt readCharacteristic fail"));
|
||||
}
|
||||
} else {
|
||||
if (bleReadCallback != null)
|
||||
bleReadCallback.onReadFailure(new OtherException("this characteristic not support read!"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* rssi
|
||||
*/
|
||||
public void readRemoteRssi(BleRssiCallback bleRssiCallback) {
|
||||
handleRSSIReadCallback(bleRssiCallback);
|
||||
if (!mBluetoothGatt.readRemoteRssi()) {
|
||||
rssiMsgInit();
|
||||
if (bleRssiCallback != null)
|
||||
bleRssiCallback.onRssiFailure(new OtherException("gatt readRemoteRssi fail"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set mtu
|
||||
*/
|
||||
public void setMtu(int requiredMtu, BleMtuChangedCallback bleMtuChangedCallback) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
handleSetMtuCallback(bleMtuChangedCallback);
|
||||
if (!mBluetoothGatt.requestMtu(requiredMtu)) {
|
||||
mtuChangedMsgInit();
|
||||
if (bleMtuChangedCallback != null)
|
||||
bleMtuChangedCallback.onSetMTUFailure(new OtherException("gatt requestMtu fail"));
|
||||
}
|
||||
} else {
|
||||
if (bleMtuChangedCallback != null)
|
||||
bleMtuChangedCallback.onSetMTUFailure(new OtherException("API level lower than 21"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* requestConnectionPriority
|
||||
*
|
||||
* @param connectionPriority Request a specific connection priority. Must be one of
|
||||
* {@link BluetoothGatt#CONNECTION_PRIORITY_BALANCED},
|
||||
* {@link BluetoothGatt#CONNECTION_PRIORITY_HIGH}
|
||||
* or {@link BluetoothGatt#CONNECTION_PRIORITY_LOW_POWER}.
|
||||
* @throws IllegalArgumentException If the parameters are outside of their
|
||||
* specified range.
|
||||
*/
|
||||
public boolean requestConnectionPriority(int connectionPriority) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
return mBluetoothGatt.requestConnectionPriority(connectionPriority);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**************************************** Handle call back ******************************************/
|
||||
|
||||
/**
|
||||
* notify
|
||||
*/
|
||||
private void handleCharacteristicNotifyCallback(BleNotifyCallback bleNotifyCallback,
|
||||
String uuid_notify) {
|
||||
if (bleNotifyCallback != null) {
|
||||
notifyMsgInit();
|
||||
bleNotifyCallback.setKey(uuid_notify);
|
||||
bleNotifyCallback.setHandler(mHandler);
|
||||
mBleBluetooth.addNotifyCallback(uuid_notify, bleNotifyCallback);
|
||||
mHandler.sendMessageDelayed(
|
||||
mHandler.obtainMessage(BleMsg.MSG_CHA_NOTIFY_START, bleNotifyCallback),
|
||||
BleManager.getInstance().getOperateTimeout());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* indicate
|
||||
*/
|
||||
private void handleCharacteristicIndicateCallback(BleIndicateCallback bleIndicateCallback,
|
||||
String uuid_indicate) {
|
||||
if (bleIndicateCallback != null) {
|
||||
indicateMsgInit();
|
||||
bleIndicateCallback.setKey(uuid_indicate);
|
||||
bleIndicateCallback.setHandler(mHandler);
|
||||
mBleBluetooth.addIndicateCallback(uuid_indicate, bleIndicateCallback);
|
||||
mHandler.sendMessageDelayed(
|
||||
mHandler.obtainMessage(BleMsg.MSG_CHA_INDICATE_START, bleIndicateCallback),
|
||||
BleManager.getInstance().getOperateTimeout());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* write
|
||||
*/
|
||||
private void handleCharacteristicWriteCallback(BleWriteCallback bleWriteCallback,
|
||||
String uuid_write) {
|
||||
if (bleWriteCallback != null) {
|
||||
writeMsgInit();
|
||||
bleWriteCallback.setKey(uuid_write);
|
||||
bleWriteCallback.setHandler(mHandler);
|
||||
mBleBluetooth.addWriteCallback(uuid_write, bleWriteCallback);
|
||||
mHandler.sendMessageDelayed(
|
||||
mHandler.obtainMessage(BleMsg.MSG_CHA_WRITE_START, bleWriteCallback),
|
||||
BleManager.getInstance().getOperateTimeout());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* read
|
||||
*/
|
||||
private void handleCharacteristicReadCallback(BleReadCallback bleReadCallback,
|
||||
String uuid_read) {
|
||||
if (bleReadCallback != null) {
|
||||
readMsgInit();
|
||||
bleReadCallback.setKey(uuid_read);
|
||||
bleReadCallback.setHandler(mHandler);
|
||||
mBleBluetooth.addReadCallback(uuid_read, bleReadCallback);
|
||||
mHandler.sendMessageDelayed(
|
||||
mHandler.obtainMessage(BleMsg.MSG_CHA_READ_START, bleReadCallback),
|
||||
BleManager.getInstance().getOperateTimeout());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* rssi
|
||||
*/
|
||||
private void handleRSSIReadCallback(BleRssiCallback bleRssiCallback) {
|
||||
if (bleRssiCallback != null) {
|
||||
rssiMsgInit();
|
||||
bleRssiCallback.setHandler(mHandler);
|
||||
mBleBluetooth.addRssiCallback(bleRssiCallback);
|
||||
mHandler.sendMessageDelayed(
|
||||
mHandler.obtainMessage(BleMsg.MSG_READ_RSSI_START, bleRssiCallback),
|
||||
BleManager.getInstance().getOperateTimeout());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set mtu
|
||||
*/
|
||||
private void handleSetMtuCallback(BleMtuChangedCallback bleMtuChangedCallback) {
|
||||
if (bleMtuChangedCallback != null) {
|
||||
mtuChangedMsgInit();
|
||||
bleMtuChangedCallback.setHandler(mHandler);
|
||||
mBleBluetooth.addMtuChangedCallback(bleMtuChangedCallback);
|
||||
mHandler.sendMessageDelayed(
|
||||
mHandler.obtainMessage(BleMsg.MSG_SET_MTU_START, bleMtuChangedCallback),
|
||||
BleManager.getInstance().getOperateTimeout());
|
||||
}
|
||||
}
|
||||
|
||||
public void notifyMsgInit() {
|
||||
mHandler.removeMessages(BleMsg.MSG_CHA_NOTIFY_START);
|
||||
}
|
||||
|
||||
public void indicateMsgInit() {
|
||||
mHandler.removeMessages(BleMsg.MSG_CHA_INDICATE_START);
|
||||
}
|
||||
|
||||
public void writeMsgInit() {
|
||||
mHandler.removeMessages(BleMsg.MSG_CHA_WRITE_START);
|
||||
}
|
||||
|
||||
public void readMsgInit() {
|
||||
mHandler.removeMessages(BleMsg.MSG_CHA_READ_START);
|
||||
}
|
||||
|
||||
public void rssiMsgInit() {
|
||||
mHandler.removeMessages(BleMsg.MSG_READ_RSSI_START);
|
||||
}
|
||||
|
||||
public void mtuChangedMsgInit() {
|
||||
mHandler.removeMessages(BleMsg.MSG_SET_MTU_START);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
package com.clj.fastble.bluetooth;
|
||||
|
||||
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.os.Build;
|
||||
|
||||
import com.clj.fastble.BleManager;
|
||||
import com.clj.fastble.data.BleDevice;
|
||||
import com.clj.fastble.utils.BleLruHashMap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class MultipleBluetoothController {
|
||||
|
||||
private final BleLruHashMap<String, BleBluetooth> bleLruHashMap;
|
||||
private final HashMap<String, BleBluetooth> bleTempHashMap;
|
||||
|
||||
public MultipleBluetoothController() {
|
||||
bleLruHashMap = new BleLruHashMap<>(BleManager.getInstance().getMaxConnectCount());
|
||||
bleTempHashMap = new HashMap<>();
|
||||
}
|
||||
|
||||
public synchronized BleBluetooth buildConnectingBle(BleDevice bleDevice) {
|
||||
BleBluetooth bleBluetooth = new BleBluetooth(bleDevice);
|
||||
if (!bleTempHashMap.containsKey(bleBluetooth.getDeviceKey())) {
|
||||
bleTempHashMap.put(bleBluetooth.getDeviceKey(), bleBluetooth);
|
||||
}
|
||||
return bleBluetooth;
|
||||
}
|
||||
|
||||
public synchronized void removeConnectingBle(BleBluetooth bleBluetooth) {
|
||||
if (bleBluetooth == null) {
|
||||
return;
|
||||
}
|
||||
if (bleTempHashMap.containsKey(bleBluetooth.getDeviceKey())) {
|
||||
bleTempHashMap.remove(bleBluetooth.getDeviceKey());
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void addBleBluetooth(BleBluetooth bleBluetooth) {
|
||||
if (bleBluetooth == null) {
|
||||
return;
|
||||
}
|
||||
if (!bleLruHashMap.containsKey(bleBluetooth.getDeviceKey())) {
|
||||
bleLruHashMap.put(bleBluetooth.getDeviceKey(), bleBluetooth);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void removeBleBluetooth(BleBluetooth bleBluetooth) {
|
||||
if (bleBluetooth == null) {
|
||||
return;
|
||||
}
|
||||
if (bleLruHashMap.containsKey(bleBluetooth.getDeviceKey())) {
|
||||
bleLruHashMap.remove(bleBluetooth.getDeviceKey());
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized boolean isContainDevice(BleDevice bleDevice) {
|
||||
return bleDevice != null && bleLruHashMap.containsKey(bleDevice.getKey());
|
||||
}
|
||||
|
||||
public synchronized boolean isContainDevice(BluetoothDevice bluetoothDevice) {
|
||||
return bluetoothDevice != null && bleLruHashMap.containsKey(bluetoothDevice.getName() + bluetoothDevice.getAddress());
|
||||
}
|
||||
|
||||
public synchronized BleBluetooth getBleBluetooth(BleDevice bleDevice) {
|
||||
if (bleDevice != null) {
|
||||
if (bleLruHashMap.containsKey(bleDevice.getKey())) {
|
||||
return bleLruHashMap.get(bleDevice.getKey());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public synchronized void disconnect(BleDevice bleDevice) {
|
||||
if (isContainDevice(bleDevice)) {
|
||||
getBleBluetooth(bleDevice).disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void disconnectAllDevice() {
|
||||
for (Map.Entry<String, BleBluetooth> stringBleBluetoothEntry : bleLruHashMap.entrySet()) {
|
||||
stringBleBluetoothEntry.getValue().disconnect();
|
||||
}
|
||||
bleLruHashMap.clear();
|
||||
}
|
||||
|
||||
public synchronized void destroy() {
|
||||
for (Map.Entry<String, BleBluetooth> stringBleBluetoothEntry : bleLruHashMap.entrySet()) {
|
||||
stringBleBluetoothEntry.getValue().destroy();
|
||||
}
|
||||
bleLruHashMap.clear();
|
||||
for (Map.Entry<String, BleBluetooth> stringBleBluetoothEntry : bleTempHashMap.entrySet()) {
|
||||
stringBleBluetoothEntry.getValue().destroy();
|
||||
}
|
||||
bleTempHashMap.clear();
|
||||
}
|
||||
|
||||
public synchronized List<BleBluetooth> getBleBluetoothList() {
|
||||
List<BleBluetooth> bleBluetoothList = new ArrayList<>(bleLruHashMap.values());
|
||||
Collections.sort(bleBluetoothList, new Comparator<BleBluetooth>() {
|
||||
@Override
|
||||
public int compare(BleBluetooth lhs, BleBluetooth rhs) {
|
||||
return lhs.getDeviceKey().compareToIgnoreCase(rhs.getDeviceKey());
|
||||
}
|
||||
});
|
||||
return bleBluetoothList;
|
||||
}
|
||||
|
||||
public synchronized List<BleDevice> getDeviceList() {
|
||||
refreshConnectedDevice();
|
||||
List<BleDevice> deviceList = new ArrayList<>();
|
||||
for (BleBluetooth BleBluetooth : getBleBluetoothList()) {
|
||||
if (BleBluetooth != null) {
|
||||
deviceList.add(BleBluetooth.getDevice());
|
||||
}
|
||||
}
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
public void refreshConnectedDevice() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
List<BleBluetooth> bluetoothList = getBleBluetoothList();
|
||||
for (int i = 0; bluetoothList != null && i < bluetoothList.size(); i++) {
|
||||
BleBluetooth bleBluetooth = bluetoothList.get(i);
|
||||
if (!BleManager.getInstance().isConnected(bleBluetooth.getDevice())) {
|
||||
removeBleBluetooth(bleBluetooth);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
package com.clj.fastble.bluetooth;
|
||||
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Message;
|
||||
|
||||
import com.clj.fastble.BleManager;
|
||||
import com.clj.fastble.callback.BleWriteCallback;
|
||||
import com.clj.fastble.data.BleMsg;
|
||||
import com.clj.fastble.exception.BleException;
|
||||
import com.clj.fastble.exception.OtherException;
|
||||
import com.clj.fastble.utils.BleLog;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
|
||||
public class SplitWriter {
|
||||
|
||||
private HandlerThread mHandlerThread;
|
||||
private Handler mHandler;
|
||||
|
||||
private BleBluetooth mBleBluetooth;
|
||||
private String mUuid_service;
|
||||
private String mUuid_write;
|
||||
private byte[] mData;
|
||||
private int mCount;
|
||||
private boolean mSendNextWhenLastSuccess;
|
||||
private long mIntervalBetweenTwoPackage;
|
||||
private BleWriteCallback mCallback;
|
||||
private Queue<byte[]> mDataQueue;
|
||||
private int mTotalNum;
|
||||
|
||||
public SplitWriter() {
|
||||
mHandlerThread = new HandlerThread("splitWriter");
|
||||
mHandlerThread.start();
|
||||
|
||||
mHandler = new Handler(mHandlerThread.getLooper()) {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
super.handleMessage(msg);
|
||||
if (msg.what == BleMsg.MSG_SPLIT_WRITE_NEXT) {
|
||||
write();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void splitWrite(BleBluetooth bleBluetooth,
|
||||
String uuid_service,
|
||||
String uuid_write,
|
||||
byte[] data,
|
||||
boolean sendNextWhenLastSuccess,
|
||||
long intervalBetweenTwoPackage,
|
||||
BleWriteCallback callback) {
|
||||
mBleBluetooth = bleBluetooth;
|
||||
mUuid_service = uuid_service;
|
||||
mUuid_write = uuid_write;
|
||||
mData = data;
|
||||
mSendNextWhenLastSuccess = sendNextWhenLastSuccess;
|
||||
mIntervalBetweenTwoPackage = intervalBetweenTwoPackage;
|
||||
mCount = BleManager.getInstance().getSplitWriteNum();
|
||||
mCallback = callback;
|
||||
|
||||
splitWrite();
|
||||
}
|
||||
|
||||
private void splitWrite() {
|
||||
if (mData == null) {
|
||||
throw new IllegalArgumentException("data is Null!");
|
||||
}
|
||||
if (mCount < 1) {
|
||||
throw new IllegalArgumentException("split count should higher than 0!");
|
||||
}
|
||||
mDataQueue = splitByte(mData, mCount);
|
||||
mTotalNum = mDataQueue.size();
|
||||
write();
|
||||
}
|
||||
|
||||
private void write() {
|
||||
if (mDataQueue.peek() == null) {
|
||||
release();
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] data = mDataQueue.poll();
|
||||
mBleBluetooth.newBleConnector()
|
||||
.withUUIDString(mUuid_service, mUuid_write)
|
||||
.writeCharacteristic(
|
||||
data,
|
||||
new BleWriteCallback() {
|
||||
@Override
|
||||
public void onWriteSuccess(int current, int total, byte[] justWrite) {
|
||||
int position = mTotalNum - mDataQueue.size();
|
||||
if (mCallback != null) {
|
||||
mCallback.onWriteSuccess(position, mTotalNum, justWrite);
|
||||
}
|
||||
if (mSendNextWhenLastSuccess) {
|
||||
Message message = mHandler.obtainMessage(BleMsg.MSG_SPLIT_WRITE_NEXT);
|
||||
mHandler.sendMessageDelayed(message, mIntervalBetweenTwoPackage);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWriteFailure(BleException exception) {
|
||||
if (mCallback != null) {
|
||||
mCallback.onWriteFailure(new OtherException("exception occur while writing: " + exception.getDescription()));
|
||||
}
|
||||
if (mSendNextWhenLastSuccess) {
|
||||
Message message = mHandler.obtainMessage(BleMsg.MSG_SPLIT_WRITE_NEXT);
|
||||
mHandler.sendMessageDelayed(message, mIntervalBetweenTwoPackage);
|
||||
}
|
||||
}
|
||||
},
|
||||
mUuid_write);
|
||||
|
||||
if (!mSendNextWhenLastSuccess) {
|
||||
Message message = mHandler.obtainMessage(BleMsg.MSG_SPLIT_WRITE_NEXT);
|
||||
mHandler.sendMessageDelayed(message, mIntervalBetweenTwoPackage);
|
||||
}
|
||||
}
|
||||
|
||||
private void release() {
|
||||
mHandlerThread.quit();
|
||||
mHandler.removeCallbacksAndMessages(null);
|
||||
}
|
||||
|
||||
private static Queue<byte[]> splitByte(byte[] data, int count) {
|
||||
if (count > 20) {
|
||||
BleLog.w("Be careful: split count beyond 20! Ensure MTU higher than 23!");
|
||||
}
|
||||
Queue<byte[]> byteQueue = new LinkedList<>();
|
||||
int pkgCount;
|
||||
if (data.length % count == 0) {
|
||||
pkgCount = data.length / count;
|
||||
} else {
|
||||
pkgCount = Math.round(data.length / count + 1);
|
||||
}
|
||||
|
||||
if (pkgCount > 0) {
|
||||
for (int i = 0; i < pkgCount; i++) {
|
||||
byte[] dataPkg;
|
||||
int j;
|
||||
if (pkgCount == 1 || i == pkgCount - 1) {
|
||||
j = data.length % count == 0 ? count : data.length % count;
|
||||
System.arraycopy(data, i * count, dataPkg = new byte[j], 0, j);
|
||||
} else {
|
||||
System.arraycopy(data, i * count, dataPkg = new byte[count], 0, count);
|
||||
}
|
||||
byteQueue.offer(dataPkg);
|
||||
}
|
||||
}
|
||||
|
||||
return byteQueue;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.clj.fastble.callback;
|
||||
|
||||
|
||||
import android.os.Handler;
|
||||
|
||||
public abstract class BleBaseCallback {
|
||||
|
||||
private String key;
|
||||
private Handler handler;
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public Handler getHandler() {
|
||||
return handler;
|
||||
}
|
||||
|
||||
public void setHandler(Handler handler) {
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
package com.clj.fastble.callback;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.bluetooth.BluetoothGatt;
|
||||
import android.bluetooth.BluetoothGattCallback;
|
||||
import android.os.Build;
|
||||
|
||||
import com.clj.fastble.data.BleDevice;
|
||||
import com.clj.fastble.exception.BleException;
|
||||
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
|
||||
public abstract class BleGattCallback extends BluetoothGattCallback {
|
||||
|
||||
public abstract void onStartConnect();
|
||||
|
||||
public abstract void onConnectFail(BleDevice bleDevice, BleException exception);
|
||||
|
||||
public abstract void onConnectSuccess(BleDevice bleDevice, BluetoothGatt gatt, int status);
|
||||
|
||||
public abstract void onDisConnected(boolean isActiveDisConnected, BleDevice device, BluetoothGatt gatt, int status);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.clj.fastble.callback;
|
||||
|
||||
|
||||
import com.clj.fastble.exception.BleException;
|
||||
|
||||
public abstract class BleIndicateCallback extends BleBaseCallback{
|
||||
|
||||
public abstract void onIndicateSuccess();
|
||||
|
||||
public abstract void onIndicateFailure(BleException exception);
|
||||
|
||||
public abstract void onCharacteristicChanged(byte[] data);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.clj.fastble.callback;
|
||||
|
||||
|
||||
import com.clj.fastble.exception.BleException;
|
||||
|
||||
public abstract class BleMtuChangedCallback extends BleBaseCallback {
|
||||
|
||||
public abstract void onSetMTUFailure(BleException exception);
|
||||
|
||||
public abstract void onMtuChanged(int mtu);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.clj.fastble.callback;
|
||||
|
||||
|
||||
import com.clj.fastble.exception.BleException;
|
||||
|
||||
public abstract class BleNotifyCallback extends BleBaseCallback {
|
||||
|
||||
public abstract void onNotifySuccess();
|
||||
|
||||
public abstract void onNotifyFailure(BleException exception);
|
||||
|
||||
public abstract void onCharacteristicChanged(byte[] data);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.clj.fastble.callback;
|
||||
|
||||
|
||||
import com.clj.fastble.exception.BleException;
|
||||
|
||||
public abstract class BleReadCallback extends BleBaseCallback {
|
||||
|
||||
public abstract void onReadSuccess(byte[] data);
|
||||
|
||||
public abstract void onReadFailure(BleException exception);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.clj.fastble.callback;
|
||||
|
||||
|
||||
import com.clj.fastble.exception.BleException;
|
||||
|
||||
public abstract class BleRssiCallback extends BleBaseCallback{
|
||||
|
||||
public abstract void onRssiFailure(BleException exception);
|
||||
|
||||
public abstract void onRssiSuccess(int rssi);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.clj.fastble.callback;
|
||||
|
||||
|
||||
import com.clj.fastble.data.BleDevice;
|
||||
|
||||
public abstract class BleScanAndConnectCallback extends BleGattCallback implements BleScanPresenterImp {
|
||||
|
||||
public abstract void onScanFinished(BleDevice scanResult);
|
||||
|
||||
public void onLeScan(BleDevice bleDevice) {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.clj.fastble.callback;
|
||||
|
||||
|
||||
import com.clj.fastble.data.BleDevice;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class BleScanCallback implements BleScanPresenterImp {
|
||||
|
||||
public abstract void onScanFinished(List<BleDevice> scanResultList);
|
||||
|
||||
public void onLeScan(BleDevice bleDevice) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.clj.fastble.callback;
|
||||
|
||||
import com.clj.fastble.data.BleDevice;
|
||||
|
||||
public interface BleScanPresenterImp {
|
||||
|
||||
void onScanStarted(boolean success);
|
||||
|
||||
void onScanning(BleDevice bleDevice);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.clj.fastble.callback;
|
||||
|
||||
|
||||
import com.clj.fastble.exception.BleException;
|
||||
|
||||
public abstract class BleWriteCallback extends BleBaseCallback{
|
||||
|
||||
public abstract void onWriteSuccess(int current, int total, byte[] justWrite);
|
||||
|
||||
public abstract void onWriteFailure(BleException exception);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.clj.fastble.data;
|
||||
|
||||
|
||||
public class BleConnectStateParameter {
|
||||
|
||||
private int status;
|
||||
private boolean isActive;
|
||||
|
||||
public BleConnectStateParameter(int status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public int getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(int status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return isActive;
|
||||
}
|
||||
|
||||
public void setActive(boolean active) {
|
||||
isActive = active;
|
||||
}
|
||||
|
||||
}
|
||||
112
FastBleLib/src/main/java/com/clj/fastble/data/BleDevice.java
Normal file
112
FastBleLib/src/main/java/com/clj/fastble/data/BleDevice.java
Normal file
@@ -0,0 +1,112 @@
|
||||
package com.clj.fastble.data;
|
||||
|
||||
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
|
||||
public class BleDevice implements Parcelable {
|
||||
|
||||
private BluetoothDevice mDevice;
|
||||
private byte[] mScanRecord;
|
||||
private int mRssi;
|
||||
private long mTimestampNanos;
|
||||
|
||||
public BleDevice(BluetoothDevice device) {
|
||||
mDevice = device;
|
||||
}
|
||||
|
||||
public BleDevice(BluetoothDevice device, int rssi, byte[] scanRecord, long timestampNanos) {
|
||||
mDevice = device;
|
||||
mScanRecord = scanRecord;
|
||||
mRssi = rssi;
|
||||
mTimestampNanos = timestampNanos;
|
||||
}
|
||||
|
||||
protected BleDevice(Parcel in) {
|
||||
mDevice = in.readParcelable(BluetoothDevice.class.getClassLoader());
|
||||
mScanRecord = in.createByteArray();
|
||||
mRssi = in.readInt();
|
||||
mTimestampNanos = in.readLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeParcelable(mDevice, flags);
|
||||
dest.writeByteArray(mScanRecord);
|
||||
dest.writeInt(mRssi);
|
||||
dest.writeLong(mTimestampNanos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static final Creator<BleDevice> CREATOR = new Creator<BleDevice>() {
|
||||
@Override
|
||||
public BleDevice createFromParcel(Parcel in) {
|
||||
return new BleDevice(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BleDevice[] newArray(int size) {
|
||||
return new BleDevice[size];
|
||||
}
|
||||
};
|
||||
|
||||
public String getName() {
|
||||
if (mDevice != null) {
|
||||
return mDevice.getName();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getMac() {
|
||||
if (mDevice != null) {
|
||||
return mDevice.getAddress();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
if (mDevice != null) {
|
||||
return mDevice.getName() + mDevice.getAddress();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public BluetoothDevice getDevice() {
|
||||
return mDevice;
|
||||
}
|
||||
|
||||
public void setDevice(BluetoothDevice device) {
|
||||
this.mDevice = device;
|
||||
}
|
||||
|
||||
public byte[] getScanRecord() {
|
||||
return mScanRecord;
|
||||
}
|
||||
|
||||
public void setScanRecord(byte[] scanRecord) {
|
||||
this.mScanRecord = scanRecord;
|
||||
}
|
||||
|
||||
public int getRssi() {
|
||||
return mRssi;
|
||||
}
|
||||
|
||||
public void setRssi(int rssi) {
|
||||
this.mRssi = rssi;
|
||||
}
|
||||
|
||||
public long getTimestampNanos() {
|
||||
return mTimestampNanos;
|
||||
}
|
||||
|
||||
public void setTimestampNanos(long timestampNanos) {
|
||||
this.mTimestampNanos = timestampNanos;
|
||||
}
|
||||
|
||||
}
|
||||
60
FastBleLib/src/main/java/com/clj/fastble/data/BleMsg.java
Normal file
60
FastBleLib/src/main/java/com/clj/fastble/data/BleMsg.java
Normal file
@@ -0,0 +1,60 @@
|
||||
package com.clj.fastble.data;
|
||||
|
||||
|
||||
|
||||
public class BleMsg {
|
||||
|
||||
// Scan
|
||||
public static final int MSG_SCAN_DEVICE = 0X00;
|
||||
|
||||
// Connect
|
||||
public static final int MSG_CONNECT_FAIL = 0x01;
|
||||
public static final int MSG_DISCONNECTED = 0x02;
|
||||
public static final int MSG_RECONNECT = 0x03;
|
||||
public static final int MSG_DISCOVER_SERVICES = 0x04;
|
||||
public static final int MSG_DISCOVER_FAIL = 0x05;
|
||||
public static final int MSG_DISCOVER_SUCCESS = 0x06;
|
||||
public static final int MSG_CONNECT_OVER_TIME = 0x07;
|
||||
|
||||
// Notify
|
||||
public static final int MSG_CHA_NOTIFY_START = 0x11;
|
||||
public static final int MSG_CHA_NOTIFY_RESULT = 0x12;
|
||||
public static final int MSG_CHA_NOTIFY_DATA_CHANGE = 0x13;
|
||||
public static final String KEY_NOTIFY_BUNDLE_STATUS = "notify_status";
|
||||
public static final String KEY_NOTIFY_BUNDLE_VALUE = "notify_value";
|
||||
|
||||
// Indicate
|
||||
public static final int MSG_CHA_INDICATE_START = 0x21;
|
||||
public static final int MSG_CHA_INDICATE_RESULT = 0x22;
|
||||
public static final int MSG_CHA_INDICATE_DATA_CHANGE = 0x23;
|
||||
public static final String KEY_INDICATE_BUNDLE_STATUS = "indicate_status";
|
||||
public static final String KEY_INDICATE_BUNDLE_VALUE = "indicate_value";
|
||||
|
||||
// Write
|
||||
public static final int MSG_CHA_WRITE_START = 0x31;
|
||||
public static final int MSG_CHA_WRITE_RESULT = 0x32;
|
||||
public static final int MSG_SPLIT_WRITE_NEXT = 0x33;
|
||||
public static final String KEY_WRITE_BUNDLE_STATUS = "write_status";
|
||||
public static final String KEY_WRITE_BUNDLE_VALUE = "write_value";
|
||||
|
||||
// Read
|
||||
public static final int MSG_CHA_READ_START = 0x41;
|
||||
public static final int MSG_CHA_READ_RESULT = 0x42;
|
||||
public static final String KEY_READ_BUNDLE_STATUS = "read_status";
|
||||
public static final String KEY_READ_BUNDLE_VALUE = "read_value";
|
||||
|
||||
// Rssi
|
||||
public static final int MSG_READ_RSSI_START = 0x51;
|
||||
public static final int MSG_READ_RSSI_RESULT = 0x52;
|
||||
public static final String KEY_READ_RSSI_BUNDLE_STATUS = "rssi_status";
|
||||
public static final String KEY_READ_RSSI_BUNDLE_VALUE = "rssi_value";
|
||||
|
||||
// Mtu
|
||||
public static final int MSG_SET_MTU_START = 0x61;
|
||||
public static final int MSG_SET_MTU_RESULT = 0x62;
|
||||
public static final String KEY_SET_MTU_BUNDLE_STATUS = "mtu_status";
|
||||
public static final String KEY_SET_MTU_BUNDLE_VALUE = "mtu_value";
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.clj.fastble.data;
|
||||
|
||||
|
||||
public enum BleScanState {
|
||||
|
||||
STATE_IDLE(-1),
|
||||
STATE_SCANNING(0X01);
|
||||
|
||||
private int code;
|
||||
|
||||
BleScanState(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.clj.fastble.data;
|
||||
|
||||
|
||||
|
||||
public class BleWriteState {
|
||||
|
||||
public static final int DATA_WRITE_SINGLE = 1;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.clj.fastble.exception;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
public abstract class BleException implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 8004414918500865564L;
|
||||
|
||||
public static final int ERROR_CODE_TIMEOUT = 100;
|
||||
public static final int ERROR_CODE_GATT = 101;
|
||||
public static final int ERROR_CODE_OTHER = 102;
|
||||
|
||||
private int code;
|
||||
private String description;
|
||||
|
||||
public BleException(int code, String description) {
|
||||
this.code = code;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public BleException setCode(int code) {
|
||||
this.code = code;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public BleException setDescription(String description) {
|
||||
this.description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BleException { " +
|
||||
"code=" + code +
|
||||
", description='" + description + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.clj.fastble.exception;
|
||||
|
||||
import android.bluetooth.BluetoothGatt;
|
||||
|
||||
|
||||
public class ConnectException extends BleException {
|
||||
|
||||
private BluetoothGatt bluetoothGatt;
|
||||
private int gattStatus;
|
||||
|
||||
public ConnectException(BluetoothGatt bluetoothGatt, int gattStatus) {
|
||||
super(ERROR_CODE_GATT, "Gatt Exception Occurred! ");
|
||||
this.bluetoothGatt = bluetoothGatt;
|
||||
this.gattStatus = gattStatus;
|
||||
}
|
||||
|
||||
public int getGattStatus() {
|
||||
return gattStatus;
|
||||
}
|
||||
|
||||
public ConnectException setGattStatus(int gattStatus) {
|
||||
this.gattStatus = gattStatus;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BluetoothGatt getBluetoothGatt() {
|
||||
return bluetoothGatt;
|
||||
}
|
||||
|
||||
public ConnectException setBluetoothGatt(BluetoothGatt bluetoothGatt) {
|
||||
this.bluetoothGatt = bluetoothGatt;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ConnectException{" +
|
||||
"gattStatus=" + gattStatus +
|
||||
", bluetoothGatt=" + bluetoothGatt +
|
||||
"} " + super.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.clj.fastble.exception;
|
||||
|
||||
|
||||
public class GattException extends BleException {
|
||||
|
||||
private int gattStatus;
|
||||
|
||||
public GattException(int gattStatus) {
|
||||
super(ERROR_CODE_GATT, "Gatt Exception Occurred! ");
|
||||
this.gattStatus = gattStatus;
|
||||
}
|
||||
|
||||
public int getGattStatus() {
|
||||
return gattStatus;
|
||||
}
|
||||
|
||||
public GattException setGattStatus(int gattStatus) {
|
||||
this.gattStatus = gattStatus;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GattException{" +
|
||||
"gattStatus=" + gattStatus +
|
||||
"} " + super.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.clj.fastble.exception;
|
||||
|
||||
|
||||
public class OtherException extends BleException {
|
||||
|
||||
public OtherException(String description) {
|
||||
super(ERROR_CODE_OTHER, description);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.clj.fastble.exception;
|
||||
|
||||
|
||||
public class TimeoutException extends BleException {
|
||||
|
||||
public TimeoutException() {
|
||||
super(ERROR_CODE_TIMEOUT, "Timeout Exception Occurred!");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
package com.clj.fastble.scan;
|
||||
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.clj.fastble.callback.BleScanPresenterImp;
|
||||
import com.clj.fastble.data.BleDevice;
|
||||
import com.clj.fastble.data.BleMsg;
|
||||
import com.clj.fastble.utils.BleLog;
|
||||
import com.clj.fastble.utils.HexUtil;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
|
||||
public abstract class BleScanPresenter implements BluetoothAdapter.LeScanCallback {
|
||||
|
||||
private String[] mDeviceNames;
|
||||
private String mDeviceMac;
|
||||
private boolean mFuzzy;
|
||||
private boolean mNeedConnect;
|
||||
private long mScanTimeout;
|
||||
private BleScanPresenterImp mBleScanPresenterImp;
|
||||
|
||||
private final List<BleDevice> mBleDeviceList = new ArrayList<>();
|
||||
|
||||
private final Handler mMainHandler = new Handler(Looper.getMainLooper());
|
||||
private HandlerThread mHandlerThread;
|
||||
private Handler mHandler;
|
||||
private boolean mHandling;
|
||||
|
||||
private static final class ScanHandler extends Handler {
|
||||
|
||||
private final WeakReference<BleScanPresenter> mBleScanPresenter;
|
||||
|
||||
ScanHandler(Looper looper, BleScanPresenter bleScanPresenter) {
|
||||
super(looper);
|
||||
mBleScanPresenter = new WeakReference<>(bleScanPresenter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
BleScanPresenter bleScanPresenter = mBleScanPresenter.get();
|
||||
if (bleScanPresenter != null) {
|
||||
if (msg.what == BleMsg.MSG_SCAN_DEVICE) {
|
||||
final BleDevice bleDevice = (BleDevice) msg.obj;
|
||||
if (bleDevice != null) {
|
||||
bleScanPresenter.handleResult(bleDevice);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleResult(final BleDevice bleDevice) {
|
||||
mMainHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
onLeScan(bleDevice);
|
||||
}
|
||||
});
|
||||
checkDevice(bleDevice);
|
||||
}
|
||||
|
||||
public void prepare(String[] names, String mac, boolean fuzzy, boolean needConnect,
|
||||
long timeOut, BleScanPresenterImp bleScanPresenterImp) {
|
||||
mDeviceNames = names;
|
||||
mDeviceMac = mac;
|
||||
mFuzzy = fuzzy;
|
||||
mNeedConnect = needConnect;
|
||||
mScanTimeout = timeOut;
|
||||
mBleScanPresenterImp = bleScanPresenterImp;
|
||||
|
||||
mHandlerThread = new HandlerThread(BleScanPresenter.class.getSimpleName());
|
||||
mHandlerThread.start();
|
||||
mHandler = new ScanHandler(mHandlerThread.getLooper(), this);
|
||||
mHandling = true;
|
||||
}
|
||||
|
||||
public boolean ismNeedConnect() {
|
||||
return mNeedConnect;
|
||||
}
|
||||
|
||||
public BleScanPresenterImp getBleScanPresenterImp() {
|
||||
return mBleScanPresenterImp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
|
||||
if (device == null)
|
||||
return;
|
||||
|
||||
if (!mHandling)
|
||||
return;
|
||||
|
||||
Message message = mHandler.obtainMessage();
|
||||
message.what = BleMsg.MSG_SCAN_DEVICE;
|
||||
message.obj = new BleDevice(device, rssi, scanRecord, System.currentTimeMillis());
|
||||
mHandler.sendMessage(message);
|
||||
}
|
||||
|
||||
private void checkDevice(BleDevice bleDevice) {
|
||||
if (TextUtils.isEmpty(mDeviceMac) && (mDeviceNames == null || mDeviceNames.length < 1)) {
|
||||
correctDeviceAndNextStep(bleDevice);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(mDeviceMac)) {
|
||||
if (!mDeviceMac.equalsIgnoreCase(bleDevice.getMac()))
|
||||
return;
|
||||
}
|
||||
|
||||
if (mDeviceNames != null && mDeviceNames.length > 0) {
|
||||
AtomicBoolean equal = new AtomicBoolean(false);
|
||||
for (String name : mDeviceNames) {
|
||||
String remoteName = bleDevice.getName();
|
||||
if (remoteName == null)
|
||||
remoteName = "";
|
||||
if (mFuzzy ? remoteName.contains(name) : remoteName.equals(name)) {
|
||||
equal.set(true);
|
||||
}
|
||||
}
|
||||
if (!equal.get()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
correctDeviceAndNextStep(bleDevice);
|
||||
}
|
||||
|
||||
|
||||
private void correctDeviceAndNextStep(final BleDevice bleDevice) {
|
||||
if (mNeedConnect) {
|
||||
BleLog.i("devices detected ------"
|
||||
+ " name:" + bleDevice.getName()
|
||||
+ " mac:" + bleDevice.getMac()
|
||||
+ " Rssi:" + bleDevice.getRssi()
|
||||
+ " scanRecord:" + HexUtil.formatHexString(bleDevice.getScanRecord()));
|
||||
|
||||
mBleDeviceList.add(bleDevice);
|
||||
mMainHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
BleScanner.getInstance().stopLeScan();
|
||||
}
|
||||
});
|
||||
|
||||
} else {
|
||||
AtomicBoolean hasFound = new AtomicBoolean(false);
|
||||
for (BleDevice result : mBleDeviceList) {
|
||||
if (result.getDevice().equals(bleDevice.getDevice())) {
|
||||
hasFound.set(true);
|
||||
}
|
||||
}
|
||||
if (!hasFound.get()) {
|
||||
BleLog.i("device detected ------"
|
||||
+ " name: " + bleDevice.getName()
|
||||
+ " mac: " + bleDevice.getMac()
|
||||
+ " Rssi: " + bleDevice.getRssi()
|
||||
+ " scanRecord: " + HexUtil.formatHexString(bleDevice.getScanRecord(), true));
|
||||
|
||||
mBleDeviceList.add(bleDevice);
|
||||
mMainHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
onScanning(bleDevice);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final void notifyScanStarted(final boolean success) {
|
||||
mBleDeviceList.clear();
|
||||
|
||||
removeHandlerMsg();
|
||||
|
||||
if (success && mScanTimeout > 0) {
|
||||
mMainHandler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
BleScanner.getInstance().stopLeScan();
|
||||
}
|
||||
}, mScanTimeout);
|
||||
}
|
||||
|
||||
mMainHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
onScanStarted(success);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public final void notifyScanStopped() {
|
||||
mHandling = false;
|
||||
mHandlerThread.quit();
|
||||
removeHandlerMsg();
|
||||
mMainHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
onScanFinished(mBleDeviceList);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public final void removeHandlerMsg() {
|
||||
mMainHandler.removeCallbacksAndMessages(null);
|
||||
mHandler.removeCallbacksAndMessages(null);
|
||||
}
|
||||
|
||||
public abstract void onScanStarted(boolean success);
|
||||
|
||||
public abstract void onLeScan(BleDevice bleDevice);
|
||||
|
||||
public abstract void onScanning(BleDevice bleDevice);
|
||||
|
||||
public abstract void onScanFinished(List<BleDevice> bleDeviceList);
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package com.clj.fastble.scan;
|
||||
|
||||
|
||||
import com.clj.fastble.BleManager;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class BleScanRuleConfig {
|
||||
|
||||
private UUID[] mServiceUuids = null;
|
||||
private String[] mDeviceNames = null;
|
||||
private String mDeviceMac = null;
|
||||
private boolean mAutoConnect = false;
|
||||
private boolean mFuzzy = false;
|
||||
private long mScanTimeOut = BleManager.DEFAULT_SCAN_TIME;
|
||||
|
||||
public UUID[] getServiceUuids() {
|
||||
return mServiceUuids;
|
||||
}
|
||||
|
||||
public String[] getDeviceNames() {
|
||||
return mDeviceNames;
|
||||
}
|
||||
|
||||
public String getDeviceMac() {
|
||||
return mDeviceMac;
|
||||
}
|
||||
|
||||
public boolean isAutoConnect() {
|
||||
return mAutoConnect;
|
||||
}
|
||||
|
||||
public boolean isFuzzy() {
|
||||
return mFuzzy;
|
||||
}
|
||||
|
||||
public long getScanTimeOut() {
|
||||
return mScanTimeOut;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
private UUID[] mServiceUuids = null;
|
||||
private String[] mDeviceNames = null;
|
||||
private String mDeviceMac = null;
|
||||
private boolean mAutoConnect = false;
|
||||
private boolean mFuzzy = false;
|
||||
private long mTimeOut = BleManager.DEFAULT_SCAN_TIME;
|
||||
|
||||
public Builder setServiceUuids(UUID[] uuids) {
|
||||
this.mServiceUuids = uuids;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setDeviceName(boolean fuzzy, String... name) {
|
||||
this.mFuzzy = fuzzy;
|
||||
this.mDeviceNames = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setDeviceMac(String mac) {
|
||||
this.mDeviceMac = mac;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAutoConnect(boolean autoConnect) {
|
||||
this.mAutoConnect = autoConnect;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setScanTimeOut(long timeOut) {
|
||||
this.mTimeOut = timeOut;
|
||||
return this;
|
||||
}
|
||||
|
||||
void applyConfig(BleScanRuleConfig config) {
|
||||
config.mServiceUuids = this.mServiceUuids;
|
||||
config.mDeviceNames = this.mDeviceNames;
|
||||
config.mDeviceMac = this.mDeviceMac;
|
||||
config.mAutoConnect = this.mAutoConnect;
|
||||
config.mFuzzy = this.mFuzzy;
|
||||
config.mScanTimeOut = this.mTimeOut;
|
||||
}
|
||||
|
||||
public BleScanRuleConfig build() {
|
||||
BleScanRuleConfig config = new BleScanRuleConfig();
|
||||
applyConfig(config);
|
||||
return config;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
139
FastBleLib/src/main/java/com/clj/fastble/scan/BleScanner.java
Normal file
139
FastBleLib/src/main/java/com/clj/fastble/scan/BleScanner.java
Normal file
@@ -0,0 +1,139 @@
|
||||
package com.clj.fastble.scan;
|
||||
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
import com.clj.fastble.BleManager;
|
||||
import com.clj.fastble.callback.BleScanAndConnectCallback;
|
||||
import com.clj.fastble.callback.BleScanCallback;
|
||||
import com.clj.fastble.callback.BleScanPresenterImp;
|
||||
import com.clj.fastble.data.BleDevice;
|
||||
import com.clj.fastble.data.BleScanState;
|
||||
import com.clj.fastble.utils.BleLog;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
|
||||
public class BleScanner {
|
||||
|
||||
public static BleScanner getInstance() {
|
||||
return BleScannerHolder.sBleScanner;
|
||||
}
|
||||
|
||||
private static class BleScannerHolder {
|
||||
private static final BleScanner sBleScanner = new BleScanner();
|
||||
}
|
||||
|
||||
private BleScanState mBleScanState = BleScanState.STATE_IDLE;
|
||||
|
||||
private final BleScanPresenter mBleScanPresenter = new BleScanPresenter() {
|
||||
|
||||
@Override
|
||||
public void onScanStarted(boolean success) {
|
||||
BleScanPresenterImp callback = mBleScanPresenter.getBleScanPresenterImp();
|
||||
if (callback != null) {
|
||||
callback.onScanStarted(success);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLeScan(BleDevice bleDevice) {
|
||||
if (mBleScanPresenter.ismNeedConnect()) {
|
||||
BleScanAndConnectCallback callback = (BleScanAndConnectCallback)
|
||||
mBleScanPresenter.getBleScanPresenterImp();
|
||||
if (callback != null) {
|
||||
callback.onLeScan(bleDevice);
|
||||
}
|
||||
} else {
|
||||
BleScanCallback callback = (BleScanCallback) mBleScanPresenter.getBleScanPresenterImp();
|
||||
if (callback != null) {
|
||||
callback.onLeScan(bleDevice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScanning(BleDevice result) {
|
||||
BleScanPresenterImp callback = mBleScanPresenter.getBleScanPresenterImp();
|
||||
if (callback != null) {
|
||||
callback.onScanning(result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScanFinished(List<BleDevice> bleDeviceList) {
|
||||
if (mBleScanPresenter.ismNeedConnect()) {
|
||||
final BleScanAndConnectCallback callback = (BleScanAndConnectCallback)
|
||||
mBleScanPresenter.getBleScanPresenterImp();
|
||||
if (bleDeviceList == null || bleDeviceList.size() < 1) {
|
||||
if (callback != null) {
|
||||
callback.onScanFinished(null);
|
||||
}
|
||||
} else {
|
||||
if (callback != null) {
|
||||
callback.onScanFinished(bleDeviceList.get(0));
|
||||
}
|
||||
final List<BleDevice> list = bleDeviceList;
|
||||
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
BleManager.getInstance().connect(list.get(0), callback);
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
} else {
|
||||
BleScanCallback callback = (BleScanCallback) mBleScanPresenter.getBleScanPresenterImp();
|
||||
if (callback != null) {
|
||||
callback.onScanFinished(bleDeviceList);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public void scan(UUID[] serviceUuids, String[] names, String mac, boolean fuzzy,
|
||||
long timeOut, final BleScanCallback callback) {
|
||||
|
||||
startLeScan(serviceUuids, names, mac, fuzzy, false, timeOut, callback);
|
||||
}
|
||||
|
||||
public void scanAndConnect(UUID[] serviceUuids, String[] names, String mac, boolean fuzzy,
|
||||
long timeOut, BleScanAndConnectCallback callback) {
|
||||
|
||||
startLeScan(serviceUuids, names, mac, fuzzy, true, timeOut, callback);
|
||||
}
|
||||
|
||||
private synchronized void startLeScan(UUID[] serviceUuids, String[] names, String mac, boolean fuzzy,
|
||||
boolean needConnect, long timeOut, BleScanPresenterImp imp) {
|
||||
|
||||
if (mBleScanState != BleScanState.STATE_IDLE) {
|
||||
BleLog.w("scan action already exists, complete the previous scan action first");
|
||||
if (imp != null) {
|
||||
imp.onScanStarted(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
mBleScanPresenter.prepare(names, mac, fuzzy, needConnect, timeOut, imp);
|
||||
|
||||
boolean success = BleManager.getInstance().getBluetoothAdapter()
|
||||
.startLeScan(serviceUuids, mBleScanPresenter);
|
||||
mBleScanState = success ? BleScanState.STATE_SCANNING : BleScanState.STATE_IDLE;
|
||||
mBleScanPresenter.notifyScanStarted(success);
|
||||
}
|
||||
|
||||
public synchronized void stopLeScan() {
|
||||
BleManager.getInstance().getBluetoothAdapter().stopLeScan(mBleScanPresenter);
|
||||
mBleScanState = BleScanState.STATE_IDLE;
|
||||
mBleScanPresenter.notifyScanStopped();
|
||||
}
|
||||
|
||||
public BleScanState getScanState() {
|
||||
return mBleScanState;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
31
FastBleLib/src/main/java/com/clj/fastble/utils/BleLog.java
Normal file
31
FastBleLib/src/main/java/com/clj/fastble/utils/BleLog.java
Normal file
@@ -0,0 +1,31 @@
|
||||
package com.clj.fastble.utils;
|
||||
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
public final class BleLog {
|
||||
|
||||
public static boolean isPrint = true;
|
||||
private static final String defaultTag = "FastBle";
|
||||
|
||||
public static void d(String msg) {
|
||||
if (isPrint && msg != null)
|
||||
Log.d(defaultTag, msg);
|
||||
}
|
||||
|
||||
public static void i(String msg) {
|
||||
if (isPrint && msg != null)
|
||||
Log.i(defaultTag, msg);
|
||||
}
|
||||
|
||||
public static void w(String msg) {
|
||||
if (isPrint && msg != null)
|
||||
Log.w(defaultTag, msg);
|
||||
}
|
||||
|
||||
public static void e(String msg) {
|
||||
if (isPrint && msg != null)
|
||||
Log.e(defaultTag, msg);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.clj.fastble.utils;
|
||||
|
||||
|
||||
import com.clj.fastble.bluetooth.BleBluetooth;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
public class BleLruHashMap<K, V> extends LinkedHashMap<K, V> {
|
||||
|
||||
private final int MAX_SIZE;
|
||||
|
||||
public BleLruHashMap(int saveSize) {
|
||||
super((int) Math.ceil(saveSize / 0.75) + 1, 0.75f, true);
|
||||
MAX_SIZE = saveSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean removeEldestEntry(java.util.Map.Entry eldest) {
|
||||
if (size() > MAX_SIZE && eldest.getValue() instanceof BleBluetooth) {
|
||||
((BleBluetooth) eldest.getValue()).disconnect();
|
||||
}
|
||||
return size() > MAX_SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Entry<K, V> entry : entrySet()) {
|
||||
sb.append(String.format("%s:%s ", entry.getKey(), entry.getValue()));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
121
FastBleLib/src/main/java/com/clj/fastble/utils/HexUtil.java
Normal file
121
FastBleLib/src/main/java/com/clj/fastble/utils/HexUtil.java
Normal file
@@ -0,0 +1,121 @@
|
||||
package com.clj.fastble.utils;
|
||||
|
||||
public class HexUtil {
|
||||
|
||||
private static final char[] DIGITS_LOWER = {'0', '1', '2', '3', '4', '5',
|
||||
'6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
|
||||
private static final char[] DIGITS_UPPER = {'0', '1', '2', '3', '4', '5',
|
||||
'6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
||||
|
||||
public static char[] encodeHex(byte[] data) {
|
||||
return encodeHex(data, true);
|
||||
}
|
||||
|
||||
public static char[] encodeHex(byte[] data, boolean toLowerCase) {
|
||||
return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
|
||||
}
|
||||
|
||||
protected static char[] encodeHex(byte[] data, char[] toDigits) {
|
||||
if (data == null)
|
||||
return null;
|
||||
int l = data.length;
|
||||
char[] out = new char[l << 1];
|
||||
for (int i = 0, j = 0; i < l; i++) {
|
||||
out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
|
||||
out[j++] = toDigits[0x0F & data[i]];
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
public static String encodeHexStr(byte[] data) {
|
||||
return encodeHexStr(data, true);
|
||||
}
|
||||
|
||||
public static String encodeHexStr(byte[] data, boolean toLowerCase) {
|
||||
return encodeHexStr(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
|
||||
}
|
||||
|
||||
|
||||
protected static String encodeHexStr(byte[] data, char[] toDigits) {
|
||||
return new String(encodeHex(data, toDigits));
|
||||
}
|
||||
|
||||
public static String formatHexString(byte[] data) {
|
||||
return formatHexString(data, false);
|
||||
}
|
||||
|
||||
public static String formatHexString(byte[] data, boolean addSpace) {
|
||||
if (data == null || data.length < 1)
|
||||
return null;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
String hex = Integer.toHexString(data[i] & 0xFF);
|
||||
if (hex.length() == 1) {
|
||||
hex = '0' + hex;
|
||||
}
|
||||
sb.append(hex);
|
||||
if (addSpace)
|
||||
sb.append(" ");
|
||||
}
|
||||
return sb.toString().trim();
|
||||
}
|
||||
|
||||
public static byte[] decodeHex(char[] data) {
|
||||
int len = data.length;
|
||||
|
||||
if ((len & 0x01) != 0) {
|
||||
throw new RuntimeException("Odd number of characters.");
|
||||
}
|
||||
|
||||
byte[] out = new byte[len >> 1];
|
||||
|
||||
// two characters form the hex value.
|
||||
for (int i = 0, j = 0; j < len; i++) {
|
||||
int f = toDigit(data[j], j) << 4;
|
||||
j++;
|
||||
f = f | toDigit(data[j], j);
|
||||
j++;
|
||||
out[i] = (byte) (f & 0xFF);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
protected static int toDigit(char ch, int index) {
|
||||
int digit = Character.digit(ch, 16);
|
||||
if (digit == -1) {
|
||||
throw new RuntimeException("Illegal hexadecimal character " + ch
|
||||
+ " at index " + index);
|
||||
}
|
||||
return digit;
|
||||
}
|
||||
|
||||
|
||||
public static byte[] hexStringToBytes(String hexString) {
|
||||
if (hexString == null || hexString.equals("")) {
|
||||
return null;
|
||||
}
|
||||
hexString = hexString.trim();
|
||||
hexString = hexString.toUpperCase();
|
||||
int length = hexString.length() / 2;
|
||||
char[] hexChars = hexString.toCharArray();
|
||||
byte[] d = new byte[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
int pos = i * 2;
|
||||
d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
public static byte charToByte(char c) {
|
||||
return (byte) "0123456789ABCDEF".indexOf(c);
|
||||
}
|
||||
|
||||
public static String extractData(byte[] data, int position) {
|
||||
return HexUtil.formatHexString(new byte[]{data[position]});
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user