Skip to content

Instantly share code, notes, and snippets.

@Hackin7
Created July 22, 2023 16:46
Show Gist options
  • Save Hackin7/2c1adbb14f5d541d54de8541446e3c51 to your computer and use it in GitHub Desktop.
Save Hackin7/2c1adbb14f5d541d54de8541446e3c51 to your computer and use it in GitHub Desktop.
2023_07_22 Notes
// Make sure to set up your imports properly before this
public class BLEClient {
private final static String TAG = BLEClient.class.getSimpleName();
public Context context;
private String mDeviceName;
private String mDeviceAddress;
private BluetoothLeService bluetoothService;
private ArrayList<ArrayList<BluetoothGattCharacteristic>> mGattCharacteristics =
new ArrayList<ArrayList<BluetoothGattCharacteristic>>();
private boolean mConnected = false;
private BluetoothGattCharacteristic mNotifyCharacteristic;
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
bluetoothService = ((BluetoothLeService.LocalBinder) service).getService();
if (bluetoothService != null) {
// call functions on service to check connection and connect to devices
Log.v(TAG, "Service Retrieved");
if (!bluetoothService.initialize()) {
Log.e(TAG, "Unable to initialize Bluetooth");
//context.finish();
}
// perform device connection
if (!bluetoothService.connect(mDeviceAddress)){
Log.e(TAG, "Cannot Connect");
Toast.makeText(context, "Cannot Connect to Bluetooth Device", Toast.LENGTH_SHORT).show();
}else{
Log.v(TAG, "Connected to BLE");
Toast.makeText(context, "Connected to BLE", Toast.LENGTH_SHORT).show();
}
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
bluetoothService = null;
}
};
private final BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
// successfully connected to the GATT Server
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
// disconnected from the GATT Server
}
}
};
public BLEClient(Context context, String mDeviceAddress){
this.context = context;
this.mDeviceAddress = mDeviceAddress.toUpperCase(Locale.ROOT);
init();
}
void init(){
Intent gattServiceIntent = new Intent(context, BluetoothLeService.class);
context.bindService(gattServiceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
}
public List<BluetoothGattService> getServices(){
return bluetoothService.getSupportedGattServices();
}
public BluetoothGattCharacteristic getCharacteristic(String serviceUUIDString, int characteristicIndex){
return bluetoothService.getService(UUID.fromString(serviceUUIDString)).getCharacteristics().get(characteristicIndex);
}
public void read(BluetoothGattCharacteristic characteristic, Function<byte[], Void> readCharacteristicCallback){
bluetoothService.readCharacteristic(characteristic, readCharacteristicCallback);
}
public void writeInt(BluetoothGattCharacteristic characteristic, int i){
byte[] bytes = ByteBuffer.allocate(4).putInt(i).array();
bluetoothService.writeCharacteristic(characteristic, bytes);
}
}
// Make sure to set up your imports properly before this
public class BluetoothLeService extends Service {
private final static String TAG = BluetoothLeService.class.getSimpleName();
private Binder binder = new LocalBinder();
@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
class LocalBinder extends Binder {
public BluetoothLeService getService() {
return BluetoothLeService.this;
}
}
private BluetoothAdapter bluetoothAdapter;
public boolean initialize() {
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter == null) {
Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
return false;
}
return true;
}
private BluetoothGatt bluetoothGatt;
private Function<byte[], Void> readCharacteristicCallback;
private Function<Void, Void> disconnectedCallback;
private final BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() {
@SuppressLint("MissingPermission")
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
// successfully connected to the GATT Server
// Attempts to discover services after successful connection.
gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
// disconnected from the GATT Server
Log.v(TAG, "Disconnected");
//disconnectedCallback.apply(null);
}
}
@Override
public void onCharacteristicRead(
BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
byte[] data,
int status
) {
if (status == BluetoothGatt.GATT_SUCCESS) {
readCharacteristicCallback.apply(data);
}
}
@Override
public void onCharacteristicWrite(
BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status
) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.v(TAG, "Written "+ characteristic.toString());
}
Log.v(TAG, "Test Write "+ characteristic.toString()+" "+Integer.toString(status));
}
};
public boolean connect(final String address) {
if (bluetoothAdapter == null || address == null) {
Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
return false;
}
try {
final BluetoothDevice device = bluetoothAdapter.getRemoteDevice(address);
// connect to the GATT server on the device
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
Log.w(TAG, "No Permissions");
}
bluetoothGatt = device.connectGatt(this, false, bluetoothGattCallback);
return true;
} catch (IllegalArgumentException exception) {
Log.w(TAG, "Device not found with provided address. Unable to connect.");
return false;
}
}
public void setDisconnectedCallback(Function<Void, Void> disconnectedCallback){
this.disconnectedCallback = disconnectedCallback;
}
public List<BluetoothGattService> getSupportedGattServices() {
if (bluetoothGatt == null) return null;
return bluetoothGatt.getServices();
}
public BluetoothGattService getService(UUID uuid){
return bluetoothGatt.getService(uuid);
}
@SuppressLint("MissingPermission")
public void readCharacteristic(BluetoothGattCharacteristic characteristic, Function<byte[], Void> readCharacteristicCallback) {
if (bluetoothGatt == null) {
Log.w(TAG, "BluetoothGatt not initialized");
return;
}
this.readCharacteristicCallback = readCharacteristicCallback;
bluetoothGatt.readCharacteristic(characteristic);
}
// Broken
@SuppressLint("MissingPermission")
public void writeCharacteristic(BluetoothGattCharacteristic characteristic, byte[] value) {
Log.w(TAG, "Writing to characteristic");
characteristic.setValue(value);
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
bluetoothGatt.writeCharacteristic(characteristic);
}
}
// Make sure to set up your imports & classes properly before this
bleClient = new BLEClient("<ble_device_address>");
// Give it some time before getting services
List<BluetoothGattService> services = bleClient.getServices();
for (BluetoothGattService service : services){
Log.v("BLEClient", service.toString()+" "+service.getUuid().toString());
for (BluetoothGattCharacteristic characteristic : service.getCharacteristics()){
Log.v("BLEClient", " - " + characteristic.toString() + " " + characteristic.getUuid());
}
}
// Read
bleClient.read(
bleClient.getCharacteristic("<ble_device_address>", <index_of_characteristic>),
data -> {
Log.v("BLEClient", new BigInteger(1, data).toString(16));
return null;
}
);
// Write - Not fully tested
bleClient.writeInt(
bleClient.getCharacteristic(
"<ble_device_address>",
index_of_characteristic>
integer_data
)
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment