first commit

This commit is contained in:
yezhiqiu
2025-09-30 10:01:20 +08:00
commit 0214fb09ed
1862 changed files with 119528 additions and 0 deletions

View 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();
}
}
}

View File

@@ -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("BluetoothGattCallbackonConnectionStateChange "
+ '\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("BluetoothGattCallbackonServicesDiscovered "
+ '\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
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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) {
}
}

View File

@@ -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) {
}
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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;
}
}

View 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;
}
}

View 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";
}

View File

@@ -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;
}
}

View File

@@ -0,0 +1,8 @@
package com.clj.fastble.data;
public class BleWriteState {
public static final int DATA_WRITE_SINGLE = 1;
}

View File

@@ -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 + '\'' +
'}';
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -0,0 +1,10 @@
package com.clj.fastble.exception;
public class OtherException extends BleException {
public OtherException(String description) {
super(ERROR_CODE_OTHER, description);
}
}

View File

@@ -0,0 +1,10 @@
package com.clj.fastble.exception;
public class TimeoutException extends BleException {
public TimeoutException() {
super(ERROR_CODE_TIMEOUT, "Timeout Exception Occurred!");
}
}

View File

@@ -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);
}

View File

@@ -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;
}
}
}

View 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;
}
}

View 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);
}
}

View File

@@ -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();
}
}

View 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]});
}
}