package com.clj.fastble.bluetooth; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCallback; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattDescriptor; import android.bluetooth.BluetoothManager; import android.content.Context; import android.os.Handler; import android.os.Looper; import android.text.TextUtils; import android.util.Log; import com.clj.fastble.conn.BleConnector; import com.clj.fastble.conn.BleGattCallback; import com.clj.fastble.data.ScanResult; import com.clj.fastble.exception.BleException; import com.clj.fastble.exception.ConnectException; import com.clj.fastble.exception.NotFoundDeviceException; import com.clj.fastble.exception.ScanFailedException; import com.clj.fastble.scan.MacScanCallback; import com.clj.fastble.scan.NameScanCallback; import com.clj.fastble.scan.PeriodScanCallback; import com.clj.fastble.utils.BleLog; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Iterator; import java.util.Map; public class BleBluetooth { private static final String CONNECT_CALLBACK_KEY = "connect_key"; public static final String READ_RSSI_KEY = "rssi_key"; private static final int STATE_DISCONNECTED = 0; private static final int STATE_SCANNING = 1; private static final int STATE_CONNECTING = 2; private static final int STATE_CONNECTED = 3; private static final int STATE_SERVICES_DISCOVERED = 4; private int connectionState = STATE_DISCONNECTED; private Context context; private BluetoothAdapter bluetoothAdapter; private BluetoothGatt bluetoothGatt; private int mtu = 20; private Handler handler = new Handler(Looper.getMainLooper()); private HashMap callbackHashMap = new HashMap<>(); private PeriodScanCallback periodScanCallback; public BleBluetooth(Context context) { this.context = context = context.getApplicationContext(); BluetoothManager bluetoothManager = (BluetoothManager) context .getSystemService(Context.BLUETOOTH_SERVICE); bluetoothAdapter = bluetoothManager.getAdapter(); } public void setMtu(int mtu) { this.mtu = mtu; } public BleConnector newBleConnector() { return new BleConnector(this); } public boolean isInScanning() { return connectionState == STATE_SCANNING; } public boolean isConnectingOrConnected() { return connectionState >= STATE_CONNECTING; } public boolean isConnected() { return connectionState >= STATE_CONNECTED; } public boolean isServiceDiscovered() { return connectionState == STATE_SERVICES_DISCOVERED; } private void addConnectGattCallback(BleGattCallback callback) { callbackHashMap.put(CONNECT_CALLBACK_KEY, callback); } public void addGattCallback(String uuid, BluetoothGattCallback callback) { callbackHashMap.put(uuid, callback); } public void removeConnectGattCallback() { callbackHashMap.remove(CONNECT_CALLBACK_KEY); } public void removeGattCallback(String key) { callbackHashMap.remove(key); } public void clearCallback() { callbackHashMap.clear(); } public BluetoothGattCallback getGattCallback(String uuid) { if (TextUtils.isEmpty(uuid)) return null; return callbackHashMap.get(uuid); } public boolean startLeScan(PeriodScanCallback callback) { this.periodScanCallback = callback; callback.setBleBluetooth(this).notifyScanStarted(); boolean success = bluetoothAdapter.startLeScan(callback); if (success) { connectionState = STATE_SCANNING; } else { callback.removeHandlerMsg(); } return success; } public void cancelScan() { if (periodScanCallback != null && connectionState == STATE_SCANNING) periodScanCallback.notifyScanCancel(); } public void stopScan(BluetoothAdapter.LeScanCallback callback) { if (callback instanceof PeriodScanCallback) { ((PeriodScanCallback) callback).removeHandlerMsg(); } bluetoothAdapter.stopLeScan(callback); if (connectionState == STATE_SCANNING) { connectionState = STATE_DISCONNECTED; } } public synchronized BluetoothGatt connect(ScanResult scanResult, boolean autoConnect, BleGattCallback callback) { BleLog.i("connect name: " + scanResult.getDevice().getName() + "\nmac: " + scanResult.getDevice().getAddress() + "\nautoConnect: " + autoConnect); addConnectGattCallback(callback); bluetoothGatt = scanResult.getDevice().connectGatt(context, autoConnect, coreGattCallback); return bluetoothGatt; } public void scanNameAndConnect(String name, long time_out, final boolean autoConnect, final BleGattCallback callback) { scanNameAndConnect(name, time_out, autoConnect, false, callback); } public void scanNameAndConnect(String name, long time_out, final boolean autoConnect, boolean fuzzy, final BleGattCallback callback) { if (TextUtils.isEmpty(name)) { if (callback != null) { callback.onConnectError(new NotFoundDeviceException()); } return; } boolean success = startLeScan(new NameScanCallback(name, time_out, fuzzy) { @Override public void onDeviceFound(final ScanResult scanResult) { runOnMainThread(new Runnable() { @Override public void run() { if (callback != null) { callback.onFoundDevice(scanResult); } connect(scanResult, autoConnect, callback); } }); } @Override public void onDeviceNotFound() { runOnMainThread(new Runnable() { @Override public void run() { if (callback != null) { callback.onConnectError(new NotFoundDeviceException()); } } }); } }); if (!success && callback != null) { callback.onConnectError(new ScanFailedException()); } } public void scanNameAndConnect(String[] names, long time_out, final boolean autoConnect, final BleGattCallback callback) { scanNameAndConnect(names, time_out, autoConnect, false, callback); } public void scanNameAndConnect(String[] names, long time_out, final boolean autoConnect, boolean fuzzy, final BleGattCallback callback) { if (names == null || names.length < 1) { if (callback != null) { callback.onConnectError(new NotFoundDeviceException()); } return; } boolean success = startLeScan(new NameScanCallback(names, time_out, fuzzy) { @Override public void onDeviceFound(final ScanResult scanResult) { runOnMainThread(new Runnable() { @Override public void run() { if (callback != null) { callback.onFoundDevice(scanResult); } connect(scanResult, autoConnect, callback); } }); } @Override public void onDeviceNotFound() { runOnMainThread(new Runnable() { @Override public void run() { if (callback != null) { callback.onConnectError(new NotFoundDeviceException()); } } }); } }); if (!success && callback != null) { callback.onConnectError(new ScanFailedException()); } } public void scanMacAndConnect(String mac, long time_out, final boolean autoConnect, final BleGattCallback callback) { if (TextUtils.isEmpty(mac)) { if (callback != null) { callback.onConnectError(new NotFoundDeviceException()); } return; } boolean success = startLeScan(new MacScanCallback(mac, time_out) { @Override public void onDeviceFound(final ScanResult scanResult) { runOnMainThread(new Runnable() { @Override public void run() { if (callback != null) { callback.onFoundDevice(scanResult); } connect(scanResult, autoConnect, callback); } }); } @Override public void onDeviceNotFound() { runOnMainThread(new Runnable() { @Override public void run() { if (callback != null) { callback.onConnectError(new NotFoundDeviceException()); } } }); } }); if (!success && callback != null) { callback.onConnectError(new ScanFailedException()); } } public boolean refreshDeviceCache() { try { final Method refresh = BluetoothGatt.class.getMethod("refresh"); if (refresh != null) { boolean success = (Boolean) refresh.invoke(getBluetoothGatt()); BleLog.i("refreshDeviceCache, is success: " + success); return success; } } catch (Exception e) { BleLog.i("exception occur while refreshing device: " + e.getMessage()); e.printStackTrace(); } return false; } public void closeBluetoothGatt() { if (bluetoothGatt != null) { bluetoothGatt.disconnect(); } if (bluetoothGatt != null) { refreshDeviceCache(); } if (bluetoothGatt != null) { bluetoothGatt.close(); } } public void enableBluetoothIfDisabled() { if (!isBlueEnable()) { enableBluetooth(); } } public boolean isBlueEnable() { return bluetoothAdapter.isEnabled(); } public void enableBluetooth() { bluetoothAdapter.enable(); } public void disableBluetooth() { bluetoothAdapter.disable(); } private void runOnMainThread(Runnable runnable) { if (Looper.myLooper() == Looper.getMainLooper()) { runnable.run(); } else { handler.post(runnable); } } public Context getContext() { return context; } public BluetoothAdapter getBluetoothAdapter() { return bluetoothAdapter; } public BluetoothGatt getBluetoothGatt() { return bluetoothGatt; } public int getConnectionState() { return connectionState; } public static String dumpHex(byte[] src) { String num = "0123456789ABCDEF"; StringBuilder sb = new StringBuilder(); sb.append("[ "); for (byte aSrc : src) { int high = aSrc >> 4 & 0x0f; int low = aSrc & 0x0f; sb.append(num.charAt(high)).append(num.charAt(low)).append(" "); } sb.append(" ]"); return sb.toString(); } private BleGattCallback coreGattCallback = new BleGattCallback() { @Override public void onFoundDevice(ScanResult scanResult) { BleLog.i("BleGattCallback:onFoundDevice "); } @Override public void onConnecting(BluetoothGatt gatt, int status) { BleLog.i("BleGattCallback:onConnecting "); bluetoothGatt = gatt; Iterator iterator = callbackHashMap.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); Object call = entry.getValue(); if (call instanceof BleGattCallback) { ((BleGattCallback) call).onConnecting(gatt, status); } } } @Override public void onConnectSuccess(BluetoothGatt gatt, int status) { BleLog.i("BleGattCallback:onConnectSuccess "); bluetoothGatt = gatt; Iterator iterator = callbackHashMap.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); Object call = entry.getValue(); if (call instanceof BleGattCallback) { ((BleGattCallback) call).onConnectSuccess(gatt, status); gatt.discoverServices(); } } } @Override public void onDisConnected(BluetoothGatt gatt, int status, BleException exception) { BleLog.i("BleGattCallback:onConnectFailure "); closeBluetoothGatt(); bluetoothGatt = null; Iterator iterator = callbackHashMap.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); Object call = entry.getValue(); if (call instanceof BleGattCallback) { ((BleGattCallback) call).onDisConnected(gatt, status, exception); } } } @Override public void onConnectError(BleException exception) { BleLog.i("BleGattCallback:onConnectError "); } @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { BleLog.i("BleGattCallback:onConnectionStateChange " + '\n' + "status: " + status + '\n' + "newState: " + newState + '\n' + "currentThread: " + Thread.currentThread().getId()); if (newState == BluetoothGatt.STATE_CONNECTED) { connectionState = STATE_CONNECTED; onConnectSuccess(gatt, status); } else if (newState == BluetoothGatt.STATE_DISCONNECTED) { connectionState = STATE_DISCONNECTED; onDisConnected(gatt, status, new ConnectException(gatt, status)); } else if (newState == BluetoothGatt.STATE_CONNECTING) { connectionState = STATE_CONNECTING; onConnecting(gatt, status); } Iterator iterator = callbackHashMap.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); Object call = entry.getValue(); if (call instanceof BluetoothGattCallback) { ((BluetoothGattCallback) call).onConnectionStateChange(gatt, status, newState); } } } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { BleLog.i("BleGattCallback:onServicesDiscovered "); bluetoothGatt.requestMtu(mtu); connectionState = STATE_SERVICES_DISCOVERED; Iterator iterator = callbackHashMap.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); Object call = entry.getValue(); if (call instanceof BluetoothGattCallback) { ((BluetoothGattCallback) call).onServicesDiscovered(gatt, status); } } } @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { BleLog.i("BleGattCallback:onCharacteristicRead "); Iterator iterator = callbackHashMap.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); Object call = entry.getValue(); if (call instanceof BluetoothGattCallback) { ((BluetoothGattCallback) call).onCharacteristicRead(gatt, characteristic, status); } } } @Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { BleLog.i("BleGattCallback:onCharacteristicWrite "); Iterator iterator = callbackHashMap.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); Object call = entry.getValue(); if (call instanceof BluetoothGattCallback) { ((BluetoothGattCallback) call).onCharacteristicWrite(gatt, characteristic, status); } } } @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { BleLog.i("BleGattCallback:onCharacteristicChanged "); Iterator iterator = callbackHashMap.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); Object call = entry.getValue(); if (call instanceof BluetoothGattCallback) { ((BluetoothGattCallback) call).onCharacteristicChanged(gatt, characteristic); } } } @Override public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { BleLog.i("BleGattCallback:onDescriptorRead "); Iterator iterator = callbackHashMap.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); Object call = entry.getValue(); if (call instanceof BluetoothGattCallback) { ((BluetoothGattCallback) call).onDescriptorRead(gatt, descriptor, status); } } } @Override public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { BleLog.i("BleGattCallback:onDescriptorWrite "); Iterator iterator = callbackHashMap.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); Object call = entry.getValue(); if (call instanceof BluetoothGattCallback) { ((BluetoothGattCallback) call).onDescriptorWrite(gatt, descriptor, status); } } } @Override public void onReliableWriteCompleted(BluetoothGatt gatt, int status) { BleLog.i("BleGattCallback:onReliableWriteCompleted "); Iterator iterator = callbackHashMap.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); Object call = entry.getValue(); if (call instanceof BluetoothGattCallback) { ((BluetoothGattCallback) call).onReliableWriteCompleted(gatt, status); } } } @Override public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { BleLog.i("BleGattCallback:onReadRemoteRssi "); Iterator iterator = callbackHashMap.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); Object call = entry.getValue(); if (call instanceof BluetoothGattCallback) { ((BluetoothGattCallback) call).onReadRemoteRssi(gatt, rssi, status); } } } @Override public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) { super.onMtuChanged(gatt, mtu, status); Log.d("BLE", "onMtuChanged mtu=" + mtu + ",status=" + status); System.out.println("onMtuChanged-------------------->size:" + mtu); if (status == 0) { System.out.println("onMtuChanged-------------------->设置成功"); } } }; }