There is an issue to connected Bluetooth in foregroud sevice android - java

in this code its works in the background but not working in the foreground I want to add a foreground service that implements Bluetooth connectivity and GATT connection as well. please help me in this code
in this code its works in the background but not working in the foreground I want to add a foreground service that implements Bluetooth connectivity and GATT connection as well. please help me in this code
in this code its works in the background but not working in the foreground I want to add a foreground service that implements Bluetooth connectivity and GATT connection as well. please help me in this code
public static BluetoothGattCharacteristic colorCharacteristic;
private HashMap<String, BluetoothGatt> gattHash = new HashMap<String, BluetoothGatt>();
private BluetoothManager bluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private BluetoothGatt mGatt;
private boolean isConnected;
#Override
public IBinder onBind(Intent intent) {
initAdapter();
return kBinder;
}
#Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
private String address;
public void initBluetoothDevice(final String address, final Context context) {
this.address = address;
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if(isConnected())return;
if(null!=mGatt){
refreshDeviceCache(mGatt);
mGatt=null;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mGatt = device.connectGatt(context, false, bleGattCallback,BluetoothDevice.TRANSPORT_LE);
} else {
mGatt = device.connectGatt(context, false, bleGattCallback);
}
if (mGatt == null) {
System.out.println(device.getAddress() + "gatt is null");
}
// this.mContext=context;
// reconnect(true);
}
public String getDeviceAddress() {
return this.address;
}
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, final int rssi,
final byte[] scanRecord) {
if (device.getAddress().equals(address) && Math.abs(rssi) < 90) {
});
}
}
};
private void initAdapter() {
if (bluetoothManager == null) {
bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (bluetoothManager == null) {
return;
}
}
mBluetoothAdapter = bluetoothManager.getAdapter();
}
public void disconnect() {
NeedReconnect = false;
if (mGatt == null)
return;
mGatt.disconnect();
}
public void disconnect(String address) {
ArrayList<BluetoothGatt> gatts = new ArrayList<BluetoothGatt>();
for (BluetoothGatt gatt : arrayGatts) {
if (gatt != null && gatt.getDevice().getAddress().equals(address)) {
gatts.add(gatt);
// gatt.disconnect();
gatt.close();
// gatt = null;
}
}
arrayGatts.removeAll(gatts);
}
public class LocalBinder extends Binder {
public BleService getService() {
return BleService.this;
}
}
private int discoverCount;
private Object ob = new Object();
private BluetoothGattCallback bleGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
String action = null;
Log.i(TAG, "onConnectionStateChange: status"+ status+" newstate "+newState);
if (newState == BluetoothProfile.STATE_CONNECTED) {
if (status == 133) {
mGatt.close();
mGatt = null;
return;
}
action = ACTION_GATT_CONNECTED;
try {
gatt.discoverServices();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
isConnected=false;
Log.i(TAG, "onConnectionStateChange: "+ACTION_GATT_DISCONNECTED);
if (mGatt != null) {
mGatt.close();
mGatt = null;
}
queues.clear();
if(!NeedReconnect) {
action = ACTION_GATT_DISCONNECTED;
broadcastUpdate(action);
}
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
// if (mGatt == null)
// return;
if (status == BluetoothGatt.GATT_SUCCESS) {
String address = gatt.getDevice().getAddress();
String name = mBluetoothAdapter.getRemoteDevice(address)
.getName();
setCharacteristicNotification(true);
/* if (gatt != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
gatt.requestMtu(512);
}else{
setCharacteristicNotification(true);
}*/
discoverCount = 0;
} else {
// mGatt = null;
Log.w("servieDiscovered", "onServicesDiscovered received: "
+ status);
}
}
#Override
public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
super.onMtuChanged(gatt, mtu, status);
if (BluetoothGatt.GATT_SUCCESS == status) {
setCharacteristicNotification(true);
}else {
gatt.requestMtu(153);
}
}
public void onCharacteristicRead(BluetoothGatt gatt,
android.bluetooth.BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic, gatt
.getDevice().getAddress());
} else {
}
}
public void onDescriptorWrite(BluetoothGatt gatt,
BluetoothGattDescriptor descriptor, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
//MyLog.i("onDescriptorWrite");
// NeedReconnect = true;
isConnected=true;
// SharePreferenceUtils.setSpString(SharePreferenceUtils.KEY_ADDRESS,gatt.getDevice().getAddress());
broadcastUpdate(ACTION_GATT_onDescriptorWrite);
}else{
Log.i(TAG, "onDescriptorWrite: failed");
}
}
;
public void onCharacteristicChanged(BluetoothGatt gatt,
android.bluetooth.BluetoothGattCharacteristic characteristic) {
if (mGatt == null)
return;
Log.i(TAG, "onCharacteristicChanged: " + ResolveData.byte2Hex(characteristic.getValue()));
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic, gatt
.getDevice().getAddress());
// SendData.sendBus(ACTION_DATA_AVAILABLE, characteristic.getValue());
}
public void onCharacteristicWrite(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
nextQueue();
} else {
// MyLog.i("status" + status);
}
}
;
};
public boolean refreshDeviceCache(BluetoothGatt gatt) {
try {
BluetoothGatt localBluetoothGatt = gatt;
Method localMethod = localBluetoothGatt.getClass().getMethod(
"refresh", new Class[0]);
if (localMethod != null) {
boolean bool = ((Boolean) localMethod.invoke(
localBluetoothGatt, new Object[0])).booleanValue();
return bool;
}
} catch (Exception localException) {
Log.e("s", "An exception occured while refreshing device");
}
return false;
}
private void broadcastUpdate(String action) {
BleData bleData = new BleData();
bleData.setAction(action);
RxBus.getInstance().post(bleData);
//Intent intent = new Intent(action);
//sendBroadcast(intent);
}
private void broadcast update(String action,
BluetoothGattCharacteristic characteristic, String mac) {
// Intent intent = new Intent(action);
byte[] data = characteristic.getValue();
BleData bleData = new BleData();
bleData.setAction(action);
bleData.setValue(data);
RxBus.getInstance().post(bleData);
}
public void readValue(BluetoothGattCharacteristic characteristic) {
if (mGatt == null) return;
mGatt.readCharacteristic(characteristic);
}
public void writeValue(byte[] value) {
if (mGatt == null||value==null) return;
BluetoothGattService service = mGatt.getService(SERVICE_DATA);
if (service == null) return;
BluetoothGattCharacteristic characteristic = service.getCharacteristic(DATA_Characteristic);
if (characteristic == null) return;
if (value[0] ==(byte) 0x47) {
NeedReconnect = false;
}
characteristic.setValue(value);
Log.i(TAG, "writeValue: "+ ResolveData.byte2Hex(value));
mGatt.writeCharacteristic(characteristic);
}
public void setCharacteristicNotification(boolean enable) {
// TODO Auto-generated method stub
if (mGatt == null) return;
BluetoothGattService service = mGatt.getService(SERVICE_DATA);
if (service == null) return;
BluetoothGattCharacteristic characteristic = service.getCharacteristic(NOTIY_Characteristic);
if (characteristic == null) return;
mGatt.setCharacteristicNotification(characteristic, enable);
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
BluetoothGattDescriptor descriptor = characteristic
.getDescriptor(NOTIY);
if (descriptor == null) {
//MyLog.e("setCharacteristicNotification descriptor=null,所以不能发送使能数据");
return;
}
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
if (mGatt == null)
return;
mGatt.writeDescriptor(descriptor);
}
#Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
//MyLog.i("servicer destory");
}
Queue<byte[]> queues=new LinkedList<>();
public void offerValue(byte[]value) {
queues.offer(value);
}
public void nextQueue(){
final Queue<byte[]> requests=queues;
byte[]data=requests!=null?requests.poll():null;
writeValue(data);
}
public boolean isConnected(){
return this.isConnected;
}
}

Related

The ble Bluetooth connection does not work properly

I don't know what's the problem.
I'm sorry I can't speak English. Can you help me
Fixed with ble bluetooth connection. There is no room for change anymore.
The Raspberry Pi I am currently using is the Raspberry Pi 4 Model B.
#SuppressWarnings({"MissingPermission"})
private void connectSelectedDevice(String address) {
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
}
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#SuppressLint("MissingPermission")
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
if (newState == BluetoothProfile.STATE_CONNECTED) {
mConnectedBluetoothThread = new ConnectedBluetoothThread(gatt);
mConnectedBluetoothThread.start();
mTvBluetoothStatus.setText("Connected to device");
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
mConnectedBluetoothThread.cancel();
mConnectedBluetoothThread = null;
mTvBluetoothStatus.setText("Disconnected from device");
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
}
};
#SuppressLint("MissingPermission")
private BluetoothGatt connectGatt(BluetoothDevice device) {
return device.connectGatt(this, false, mGattCallback);
}
#SuppressWarnings({"MissingPermission"})
private class ConnectedBluetoothThread extends Thread {
private final BluetoothGatt mmGatt;
private BluetoothGattCharacteristic mCharacteristic;
public ConnectedBluetoothThread(BluetoothGatt gatt) {
mmGatt = gatt;
BluetoothGattService service = gatt.getService(BT_UUID);
if (service != null) {
mCharacteristic = service.getCharacteristic(BT_UUID);
if (mCharacteristic == null) {
List<BluetoothGattService> gattServices = gatt.getServices();
for (BluetoothGattService gattService : gattServices) {
if (gattService.getUuid().equals(BT_UUID)) {
List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
if (gattCharacteristic.getUuid().equals(BT_UUID)) {
mCharacteristic = gattCharacteristic;
break;
}
}
}
}
}
} else {
Log.e(TAG, "service is null");
}
}
public void run() {
BluetoothGattService service = mmGatt.getService(BT_UUID);
if (service == null) {
Log.e(TAG, "service is null");
return;
}
mCharacteristic = service.getCharacteristic(BT_UUID);
if (mCharacteristic == null) {
Log.e(TAG, "mCharacteristic is null");
List<BluetoothGattService> gattServices = mmGatt.getServices();
for (BluetoothGattService gattService : gattServices) {
if (gattService.getUuid().equals(BT_UUID)) {
List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
if (gattCharacteristic.getUuid().equals(BT_UUID)) {
mCharacteristic = gattCharacteristic;
break;
}
}
}
}
}
if (mCharacteristic == null) {
return;
}
mmGatt.setCharacteristicNotification(mCharacteristic, true);
BluetoothGattDescriptor descriptor = mCharacteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mmGatt.writeDescriptor(descriptor);
}
}
Please advice on how to fix it.
from bluetooth import *
server_socket= BluetoothSocket(RFCOMM)
port = 1
server_socket.bind(("", port))
server_socket.listen(1)
client_socket, address = server_socket.accept()
print("Accepted connection from ", address)
client_socket.send("bluetooth connected!")
while True:
data = client_socket.recv(1024)
print("Received: %s" %data)
if(data=="q"):
print("Quit")
break
client_socket.close()
server_socket.close()
This is python code.
I expected that if I tried to connect to ble Bluetooth using the gatt server, it would be connected, but it did not work.
Please help me.

Android - Bluetooth receiver not working on advertising device

This is my first app working with Bluetooth in Androind and I'm having a kinda unique problem: the bluetooth receiver isn't working on the device that is advertising the bluetooth service.
I have tested the application in 2 phones at the same time (I'll call them phone A and B to explain better). At first I start the advertising with the phone A, then I start the discovery with the phone B and finally I press the button in phone B to send data. This button should first start the Gatt connection and if it's working it should then broadcast a message that confirms the connection. To see it I have used a Log in the Broadcast receiver but the result I get is this messsagge appearing only in the logcat of the phone B but not on the one of phone A.
I have looked at a lot of examples and post on Stackoverflow but I can't seem to find the solution to this problem.
So I really can't find what the real problem here is. Maybe I'm just using badly the Bluetooth classes or I just lack knowledge. In any case, here there is all the code of the MainActivity as it is the only class of this simple project.
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private TextView mText;
private Button mAdvertiseButton;
private Button mDiscoverButton;
private Button mSendButton;
private String TAG = "INFOBLERESULTS";
private BluetoothLeScanner mBluetoothLeScanner;
private BluetoothDevice bluetoothDevice;
private Handler mHandler = new Handler();
private ScanCallback mScanCallback = new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
Log.d(TAG, result.getDevice().getAddress());
super.onScanResult(callbackType, result);
if( result == null
|| result.getDevice() == null
|| TextUtils.isEmpty(result.getDevice().getAddress()) )
return;
StringBuilder builder = new StringBuilder( result.getDevice().getAddress() );
builder.append("\n").append(result.getDevice().getName());
//builder.append("\n").append(new String(result.getScanRecord().getServiceData(result.getScanRecord().getServiceUuids().get(0)), Charset.forName("UTF-8")));
mText.setText(builder.toString());
bluetoothDevice = result.getDevice();
bluetoothLeService = new BluetoothLeService();
bluetoothLeService.setAddress(result.getDevice().getAddress());
}
#Override
public void onBatchScanResults(List<ScanResult> results) {
super.onBatchScanResults(results);
}
#Override
public void onScanFailed(int errorCode) {
Log.e( TAG, "Discovery onScanFailed: " + errorCode );
super.onScanFailed(errorCode);
}
};
private BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
private boolean connected = false;
//Inner classes
class BluetoothLeService extends Service {
public final static String ACTION_GATT_CONNECTED =
"com.example.bluetooth.le.ACTION_GATT_CONNECTED";
public final static String ACTION_GATT_DISCONNECTED =
"com.example.bluetooth.le.ACTION_GATT_DISCONNECTED";
public final static String ACTION_GATT_SERVICES_DISCOVERED =
"com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED";
public final static String ACTION_DATA_AVAILABLE =
"com.example.bluetooth.le.ACTION_DATA_AVAILABLE";
private static final int STATE_DISCONNECTED = 0;
private static final int STATE_CONNECTED = 2;
private int connectionState;
public Context ctx;
protected BluetoothGatt bluetoothGatt;
protected final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
Log.i(TAG, "GATT status = "+ status + " newState = " + newState);
if(status == BluetoothGatt.GATT_SUCCESS){
if (newState == BluetoothProfile.STATE_CONNECTED) {
// successfully connected to the GATT Server
connectionState = STATE_CONNECTED;
broadcastUpdate(ACTION_GATT_CONNECTED);
bluetoothGatt = gatt;
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
// disconnected from the GATT Server
connectionState = STATE_DISCONNECTED;
broadcastUpdate(ACTION_GATT_DISCONNECTED);
gatt.close();
}
}else{
gatt.close();
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
public void onCharacteristicRead(
BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status
) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
#Override
public void onCharacteristicChanged(
BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic
) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
};
private Binder binder = new LocalBinder();
private String address = "";
public void setAddress(String address) {
this.address = address;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return binder;
}
#Override
public boolean onUnbind(Intent intent) {
close();
return super.onUnbind(intent);
}
private void close() {
if (bluetoothGatt == null) {
return;
}
bluetoothGatt.close();
bluetoothGatt = null;
}
public boolean connect() {
if (bluetoothAdapter == null || this.address == null || this.address.equals("")) {
Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
return false;
}
try {
final BluetoothDevice device = bluetoothAdapter.getRemoteDevice(address);
bluetoothGatt = device.connectGatt(MainActivity.this.getApplicationContext(), false, gattCallback);
Log.d(TAG,"GATT "+ bluetoothGatt);
return true;
} catch (IllegalArgumentException exception) {
Log.w(TAG, "Device not found with provided address.");
return false;
}
}
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
Log.i(TAG, intent + "");
MainActivity.this.getApplicationContext().sendBroadcast(intent);
}
private void broadcastUpdate(final String action, BluetoothGattCharacteristic characteristic) {
final Intent intent = new Intent(action);
sendBroadcast(intent);
}
public List<BluetoothGattService> getSupportedGattServices() {
if (bluetoothGatt == null) return null;
return bluetoothGatt.getServices();
}
public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
if (bluetoothGatt == null) {
Log.w(TAG, "BluetoothGatt not initialized");
return;
}
bluetoothGatt.readCharacteristic(characteristic);
}
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,boolean enabled) {
if (bluetoothGatt == null) {
Log.w(TAG, "BluetoothGatt not initialized");
return;
}
bluetoothGatt.setCharacteristicNotification(characteristic, enabled);
}
class LocalBinder extends Binder {
public BluetoothLeService getService() {
return BluetoothLeService.this;
}
}
}
private BluetoothLeService bluetoothLeService = new BluetoothLeService();
private final ServiceConnection serviceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
bluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService();
if (bluetoothLeService != null) {
if (!bluetoothAdapter.isEnabled()) {
Log.e(TAG, "Unable to initialize Bluetooth");
}
else{
bluetoothLeService.connect();
Log.i(TAG, "Service connected");
}
}
}
#Override
public void onServiceDisconnected(ComponentName name) {
bluetoothLeService = null;
}
};
private final BroadcastReceiver gattUpdateReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
Log.d(TAG, "RECEIVED " + action);
if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {
connected = true;
//Log.d(TAG, "CONNECTED");
} else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
connected = false;
//Log.d(TAG, "DISCONNECTED");
}
}
};
private final ActivityResultLauncher<Intent> someActivityResultLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
#Override
public void onActivityResult(ActivityResult result) {
Log.i("RESULT", result.getResultCode() + "");
setup();
}
});
private void setup() {
bluetoothLeService.ctx = this.getApplicationContext();
Log.d("APPLICATIONCONTEXT", bluetoothLeService.ctx + "");
mDiscoverButton.setOnClickListener(this);
mAdvertiseButton.setOnClickListener(this);
mSendButton.setOnClickListener(this);
mBluetoothLeScanner = BluetoothAdapter.getDefaultAdapter().getBluetoothLeScanner();
if (!BluetoothAdapter.getDefaultAdapter().isMultipleAdvertisementSupported()) {
Toast.makeText(this, "Multiple advertisement not supported", Toast.LENGTH_SHORT).show();
mAdvertiseButton.setEnabled(false);
mDiscoverButton.setEnabled(false);
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull #org.jetbrains.annotations.NotNull String[] permissions, #NonNull #org.jetbrains.annotations.NotNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 2) {
final LocationManager manager = (LocationManager) getSystemService( Context.LOCATION_SERVICE );
if(!manager.isProviderEnabled(LocationManager.GPS_PROVIDER)){
Intent enableLocationIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
someActivityResultLauncher.launch(enableLocationIntent);
}
else{
setup();
}
}
}
#RequiresApi(api = Build.VERSION_CODES.M)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mText = (TextView) findViewById( R.id.text );
mDiscoverButton = (Button) findViewById( R.id.discover_btn );
mAdvertiseButton = (Button) findViewById( R.id.advertise_btn );
mSendButton = (Button) findViewById( R.id.send_btn );
this.requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, 2);
}
#Override
protected void onResume() {
super.onResume();
MainActivity.this.getApplicationContext().registerReceiver(gattUpdateReceiver, makeGattUpdateIntentFilter());
}
#Override
protected void onPause() {
super.onPause();
MainActivity.this.getApplicationContext().unregisterReceiver(gattUpdateReceiver);
}
#Override
public void onClick(View v) {
Log.d(TAG, getString( R.string.ble_uuid ));
if( v.getId() == R.id.discover_btn ) {
discover();
} else if( v.getId() == R.id.advertise_btn ) {
advertise();
//MainActivity.this.getApplicationContext().registerReceiver(gattUpdateReceiver, makeGattUpdateIntentFilter());
} else if (v.getId() == R.id.send_btn){
//MainActivity.this.getApplicationContext().unregisterReceiver(gattUpdateReceiver);
send();
}
}
public void advertise(){
BluetoothLeAdvertiser advertiser = BluetoothAdapter.getDefaultAdapter().getBluetoothLeAdvertiser();
AdvertiseSettings settings = new AdvertiseSettings.Builder().setTimeout(0)
.setAdvertiseMode( AdvertiseSettings.ADVERTISE_MODE_BALANCED )
.setTxPowerLevel( AdvertiseSettings.ADVERTISE_TX_POWER_HIGH )
.setConnectable( true )
.build();
ParcelUuid pUuid = ParcelUuid.fromString( getString( R.string.ble_uuid ) ) ;
AdvertiseData data = new AdvertiseData.Builder()
.addServiceUuid( pUuid ).setIncludeDeviceName(false)
.build();
AdvertiseCallback advertisingCallback = new AdvertiseCallback() {
#Override
public void onStartSuccess(AdvertiseSettings settingsInEffect) {
Log.d(TAG, "START ADVERTISING");
super.onStartSuccess(settingsInEffect);
}
#Override
public void onStartFailure(int errorCode) {
Log.e( TAG, "Advertising onStartFailure: " + errorCode );
super.onStartFailure(errorCode);
}
};
advertiser.startAdvertising( settings, data, advertisingCallback );
}
public void discover(){
ScanFilter filter = new ScanFilter.Builder()
.setServiceUuid( ParcelUuid.fromString( getString(R.string.ble_uuid ) ) )
.build();
List<ScanFilter> filters = new ArrayList<>();
filters.add( filter );
ScanSettings settings = new ScanSettings.Builder()
.setScanMode( ScanSettings.SCAN_MODE_BALANCED )
.build();
mBluetoothLeScanner.startScan(filters, settings, mScanCallback);
Log.d(TAG, "Discovery started");
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
Log.d(TAG, "Discovery stopped");
mBluetoothLeScanner.stopScan(mScanCallback);
}
}, 10000);
}
public void send(){
Log.d(TAG, "START CONNECTIONG GATT");
mBluetoothLeScanner.stopScan(mScanCallback);
//boundGatt();
connectGatt();
}
public void boundGatt(){
Intent gattServiceIntent = new Intent(MainActivity.this.getApplicationContext(), BluetoothLeService.class);
bindService(gattServiceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
}
public void connectGatt(){
bluetoothLeService.connect();
}
private static IntentFilter makeGattUpdateIntentFilter() {
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED);
intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED);
intentFilter.addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED);
intentFilter.addAction(BluetoothLeService.ACTION_DATA_AVAILABLE);
return intentFilter;
}
}
Your Peripheral (phone A) does only advertisement, but BluetoothGattServer is not set up. That could be a reason of the described behavior - advertisement & scanning work, but connection doesn't.
BluetoothGatt + BluetoothGattCallback are for Central role (you call it phone B).
BluetoothGattServer + BluetoothGattServerCallback are for Peripheral (phone A).
Notes:
Connection from Central side (phone B) looks good, because when advertised device found, you get it using bluetoothAdapter.getRemoteDevice(address), then you call device.connectGatt
To transfer some data, you will need to add BluetoothGattService with BluetoothGattCharacteristic to your BluetoothGattServer - example of setup in Kotlin
Example project on github: BLEProof - it's in Kotlin, 2 apps communicate with each other: Central and Peripheral, all code in MainActivity.kt

Service and Thread

I want to build an application that start a Service. This Service can run also if the APP is closed.
So I'm building this code on the OnCreate method of my BLEActivity.java:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ble);
startService(new Intent(this, BlePowerService.class));
}
Now I want that this service shoudl to start every 5 minutes also if the APP is closed.
The correct way to do this, is to create a Thread into BlePowerService ?
So I'm building this:
public class BlePowerService extends Service {
public DbLayer db;
Setting settingApp;
List<ScanFilter> filters;
String[] stringSequence = new String[] {CHARACTERISTIC_FORZA_STRING};
BluetoothAdapter mBluetoothAdapter;
BluetoothGatt mGatt;
BluetoothDevice currDevice;
static final long SCAN_PERIOD = 1000;
BluetoothLeScanner mLEScanner;
Handler mHandler;
int ReadQueueIndex;
List<BluetoothGattCharacteristic> ReadQueue;
ScanSettings settings;
int id = 1000;
boolean valore;
//String UuID = "f0001132-0451-4000-b000-000000000000";
String LOG_CODE = "NOTIFSRV";
int NOTIFICATION_GREEN = 1;
int NOTIFICATION_RED = 2;
int START_HOUR = 7;
int RANGE_HOURS_WEIGHT = 13;
int START_NOTIFY = 9;
int END_NOTIFY = 21;
public static String PAR_NOTIFICATION_EXERCISEID = "parNotificationExerciseId";
String NEW_ACTIVITY_START = "NAS";
String OPEN_ACTIVITY_START = "OAS";
public BlePowerService() {
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
//throw new UnsupportedOperationException("Not yet implemented");
return null;
}
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
#Override
public void onCreate() {
super.onCreate();
mHandler = new Handler();
Context sharedContext = null;
try {
sharedContext = this.createPackageContext(
"com.eresult.diabesitycare.devicesensor",
Context.CONTEXT_INCLUDE_CODE);
if (sharedContext == null) {
return;
}
db=new DbLayer(sharedContext);
db.open();
} catch (Exception e) {
String error = e.getMessage();
// Log.d(LOG_CODE,"DB error : " + error);
return;
}
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
try {
//RECUPERO LE IMPOSTAZIONI SETTATE DALL'UTENTE
settingApp = db.fetchSetting();
mTimer = new Timer();
mTimer.schedule(timerTask, 2500, 1 * 60 * 1000);
} catch (Exception e) {
// Log.e("POWER_SERVICE", e.getMessage());
}
return super.onStartCommand(intent, flags, startId);
}
private Timer mTimer;
TimerTask timerTask = new TimerTask() {
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
#Override
public void run() {
//LEGGO TUTTI I DATI DAL SENSORE FINCHE CI SONO VALORI
valore = true;
int conta = 0;
while(valore){
conta++;
Log.v("CICLO WHILE", conta+"");
if (currDevice != null) {
GattClientCallback gattClientCallback = new GattClientCallback();
mGatt = currDevice.connectGatt(getBaseContext(), false, gattClientCallback);
scanLeDevice(false);// will stop after first device detection
}else{
//provo a ricollegarmi al dispositivo probabile, abbia perso la connessione con esso
scanLeDevice(true);
}
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public void connectToDevice(BluetoothDevice device) {
//VERIFICO SE IL DEVICE è QUELLO CHE VOGLIO IO
if (mGatt == null && settingApp != null
&& device.getAddress().equals(settingApp.getAddressBleSX())) {
currDevice = device;
GattClientCallback gattClientCallback = new GattClientCallback();
mGatt = currDevice.connectGatt(getBaseContext(), false, gattClientCallback);
scanLeDevice(false);// will stop after first device detection
}
}
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi,
byte[] scanRecord) {
Handler h = new Handler(getApplicationContext().getMainLooper());
// Although you need to pass an appropriate context
//TO DO
}
};
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
private void scanLeDevice(final boolean enable) {
//TO DO
}
private ScanCallback mScanCallback = new ScanCallback() {
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
#Override
public void onScanResult(int callbackType, ScanResult result) {
//TODO
}
};
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
private class GattClientCallback extends BluetoothGattCallback {
#SuppressLint("LongLogTag")
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
try{
//TODO
}catch(Exception e){
Log.e("ON_CONNECTION_STATE_CHANGE", e.getMessage());
}
}
public void disconnectGattServer() {
valore = false;
if (mGatt != null) {
mGatt.disconnect();
mGatt.close();
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
//TODO
}
private void ReadCharacteristics(int index) {
mGatt.readCharacteristic(ReadQueue.get(index));
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
// Log.i("INFO", "Characteristic changed, " + characteristic.getUuid().toString());
readCharacteristic(characteristic);
}
private void enableCharacteristicNotification(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
//TODO
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
//TODO
}
}
}

Android BLE onCharacteristicChanged() using notify not triggered

I made an app that communicates with an device via BLE. I wrote everything that was required for it's communication. The device receives the sent value via characteristic.setValue() , but doesn't return feedback in the method onCharacteristicChanged as is supposed to, in despite that has the descriptor set for notification. For instance i send "GTN" and should get "GTN deviceId" (like on iOS), but it calls just onCharacteristicWrite(). Checked also what properties the characteristic does support. It supports PROPERTY_NOTIFY & PROPERTY_WRITE_NO_RESPONSE. I ran out of ideas why it doesn't want to get that callback message. Can someone check and try to tell me if I made some big mistakes while sending/subscribing ??
MainActivity.java
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_LOCATION_PERMISSION = 1;
private static final int REQUEST_ENABLE_BLUETOOTH = 2;
private static final int REQUEST_ENABLE_LOCATION = 3;
private static final int BLUETOOTH_ENABLED = -1;
private static final int LOCATION_ENABLED = -1;
private static final int MANUFACTURER_ID = xxxxx;
private static final UUID SERVICE =xxxxxxxxxxxxx;
private static final UUID CHARACTERISTIC =xxxxxxxxxxxxxxxxx;
private static final UUID DESCRIPTOR = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
private final static String TAG = "BLE";
private byte[] mfrData;
private BluetoothManager bluetoothManager;
private BluetoothAdapter bluetoothAdapter;
private BluetoothGatt bluetoothGatt;
private BluetoothLeScanner bluetoothLeScanner;
private BluetoothGattService customService;
private BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
if (newState == BluetoothProfile.STATE_CONNECTED) {
gatt.discoverServices();
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
BluetoothGattService service = gatt.getService(SERVICE);
BluetoothGattCharacteristic characteristic = service.getCharacteristic(CHARACTERISTIC);
gatt.setCharacteristicNotification(characteristic, true);
enableDataNotifications(gatt, characteristic);
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
Log.d(TAG, "onCharacteristicRead: ");
}
#Override
public void onCharacteristicWrite(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
Log.d(TAG, "onCharacteristicWrite: ");
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
Log.d(TAG, "onCharacteristicChanged: ");
}
#Override
public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorRead(gatt, descriptor, status);
Log.d(TAG, "onDescriptorRead: ");
}
#Override
public void onDescriptorWrite(final BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorWrite(gatt, descriptor, status);
Log.d(TAG, "onDescriptorWrite: ");
checkCharacteristicProperties(gatt.getService(SERVICE).getCharacteristic(CHARACTERISTIC));
new Thread(new Runnable() {
#Override
public void run() {
writeDataToCharCommand("GTN", gatt);
}
}).start();
}
#Override
public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
super.onReliableWriteCompleted(gatt, status);
Log.d(TAG, "onReliableWriteCompleted: ");
}
#Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
super.onReadRemoteRssi(gatt, rssi, status);
Log.d(TAG, "onReadRemoteRssi: ");
}
#Override
public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
super.onMtuChanged(gatt, mtu, status);
Log.d(TAG, "onMtuChanged: ");
}
};
private ScanCallback scanCallback = new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
if (result.getScanRecord() != null && result.getScanRecord().getManufacturerSpecificData(MANUFACTURER_ID) != null) {
Log.d(TAG, "onScanResult: found device");
bluetoothLeScanner.stopScan(scanCallback);
boolean isBonded = result.getDevice().createBond();
if (isBonded) {
bluetoothGatt = result.getDevice().connectGatt(MainActivity.this, false, bluetoothGattCallback, BluetoothDevice.TRANSPORT_LE);
}
}
}
#Override
public void onBatchScanResults(List<ScanResult> results) {
super.onBatchScanResults(results);
Log.d(TAG, "onBatchScanResults: ");
}
#Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
Log.d(TAG, "onScanFailed: ");
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setupBluetoothData();
checkIfSupportedBluetooth();
checkLocationPermission();
}
private void checkCharacteristicProperties(BluetoothGattCharacteristic pChar) {
Log.d(TAG, "checkCharacteristicProperties: PROPERTY_READ " + ((pChar.getProperties() & BluetoothGattCharacteristic.PROPERTY_READ) != 0));
Log.d(TAG, "checkCharacteristicProperties: PROPERTY_NOTIFY " + ((pChar.getProperties() & BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0));
Log.d(TAG, "checkCharacteristicProperties: PROPERTY_BROADCAST " + ((pChar.getProperties() & BluetoothGattCharacteristic.PROPERTY_BROADCAST) != 0));
Log.d(TAG, "checkCharacteristicProperties: PROPERTY_EXTENDED_PROPS " + ((pChar.getProperties() & BluetoothGattCharacteristic.PROPERTY_EXTENDED_PROPS) != 0));
Log.d(TAG, "checkCharacteristicProperties: PROPERTY_INDICATE " + ((pChar.getProperties() & BluetoothGattCharacteristic.PROPERTY_INDICATE) != 0));
Log.d(TAG, "checkCharacteristicProperties: PROPERTY_SIGNED_WRITE " + ((pChar.getProperties() & BluetoothGattCharacteristic.PROPERTY_SIGNED_WRITE) != 0));
Log.d(TAG, "checkCharacteristicProperties: PROPERTY_WRITE " + ((pChar.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) != 0));
Log.d(TAG, "checkCharacteristicProperties: PROPERTY_WRITE_NO_RESPONSE " + ((pChar.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) != 0));
}
private void setupBluetoothData() {
bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
bluetoothAdapter = bluetoothManager.getAdapter();
}
private void checkIfSupportedBluetooth() {
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
finish();
}
if (bluetoothAdapter == null) {
Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();
finish();
}
}
private void checkLocationPermission() {
if (!hasGrantedLocationPermission()) {
requestLocationPermission();
} else {
checkIfBluetoothEnabled();
}
}
private boolean hasGrantedLocationPermission() {
int result = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION);
return result == PackageManager.PERMISSION_GRANTED;
}
private void requestLocationPermission() {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_LOCATION_PERMISSION);
}
private void checkIfBluetoothEnabled() {
if (!bluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BLUETOOTH);
} else {
displayLocationSettingsRequest();
}
}
private void displayLocationSettingsRequest() {
GoogleApiClient googleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API).build();
googleApiClient.connect();
LocationRequest locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(10000);
locationRequest.setFastestInterval(10000 / 2);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(locationRequest);
builder.setAlwaysShow(true);
PendingResult<LocationSettingsResult> result = LocationServices.SettingsApi.checkLocationSettings(googleApiClient, builder.build());
result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
#Override
public void onResult(#NonNull LocationSettingsResult locationSettingsResult) {
final Status status = locationSettingsResult.getStatus();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.SUCCESS: {
scanForDevices();
break;
}
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED: {
try {
status.startResolutionForResult(MainActivity.this, REQUEST_ENABLE_LOCATION);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
break;
}
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE: {
break;
}
}
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case REQUEST_ENABLE_BLUETOOTH: {
if (resultCode == BLUETOOTH_ENABLED) {
displayLocationSettingsRequest();
} else {
Toast.makeText(this, "Restart app", Toast.LENGTH_SHORT).show();
}
break;
}
case REQUEST_ENABLE_LOCATION: {
if (resultCode == LOCATION_ENABLED) {
scanForDevices();
} else {
Toast.makeText(this, "Restart app", Toast.LENGTH_SHORT).show();
}
break;
}
default: {
break;
}
}
}
private void scanForDevices() {
Log.d(TAG, "scanForDevices: ");
Toast.makeText(this, "Scanning", Toast.LENGTH_SHORT).show();
ScanSettings scanSettings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.build();
ScanFilter scanFilter = new ScanFilter.Builder()
.setManufacturerData(0x0361, mfrData)
.build();
bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
bluetoothLeScanner.startScan(Collections.singletonList(scanFilter),
scanSettings, scanCallback);
}
private String translate(byte[] value) throws UnsupportedEncodingException {
return new String(value, StandardCharsets.UTF_8);
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case REQUEST_LOCATION_PERMISSION: {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
checkIfBluetoothEnabled();
} else {
Toast.makeText(this, "Restart app", Toast.LENGTH_SHORT).show();
}
break;
}
default: {
break;
}
}
}
private void writeDataToCharCommand(String data, BluetoothGatt gatt) {
Log.d(TAG, "writeDataToCharCommand: ");
gatt.getService(SERVICE).getCharacteristic(CHARACTERISTIC).setValue(data);
gatt.writeCharacteristic(gatt.getService(SERVICE).getCharacteristic(CHARACTERISTIC));
}
private void enableDataNotifications(BluetoothGatt gatt, BluetoothGattCharacteristic gattCharacteristic) {
Log.d(TAG, "enableDataNotifications: ");
boolean enabled = gatt.setCharacteristicNotification(gattCharacteristic, true);
if (enabled) {
BluetoothGattDescriptor descriptor = gattCharacteristic.getDescriptor(DESCRIPTOR);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(descriptor);
}
}
}
i have notification work flawlessly with BLE.
i created this method to mark a characteristics notification enabled.
public void markCharForNotification(BluetoothGattCharacteristic readableChar) {
mBluetoothGatt.setCharacteristicNotification(readableChar, true);
List<BluetoothGattDescriptor> listDescr = readableChar.getDescriptors();
BluetoothGattDescriptor descriptor = listDescr.get(0);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
}
hope it helps
You might want to run the checkCharacteristicProperties on the notify characteristic also.
Anyway, the correct way to enable notifications is to check the properties first and enable notify or indicate, based on those properties:
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID);
int properties = characteristic.getProperties();
if (descriptor != null) {
if ((properties & BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
} else if ((properties & BluetoothGattCharacteristic.PROPERTY_INDICATE) > 0) {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
}
gatt.writeDescriptor(descriptor);
Hope this helps.

OnCharacteristicRead doesn't get called (Android tablet BLE communication)

My app communicates with a BLE module (High-flyer) connected to an Arduino Mega, upon connection I press a button which sends an array to the Mega which in return sends back 4 numbers.
The problem is some times I start the app & connection, send the data to the Mega but can't read anything in return. I can see that the Mega receives the first array being sent and also transmits the 4 numbers back, but nothing happens on the application side.
This bug comes and goes, sometimes everything works perfectly and sometimes it gets stuck, when it does I try to restart the app or reinstall it but apart from that I couldn't find any way to handle or solve it.
Any help will be greatly appreciated.
BluetoothLeService.java:
public class BluetoothLeService extends Service {
private final static String TAG = BluetoothLeService.class.getSimpleName();
private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private String mBluetoothDeviceAddress;
private BluetoothGatt mBluetoothGatt;
private int mConnectionState = STATE_DISCONNECTED;
public boolean BLEfree = true;
private static final int STATE_DISCONNECTED = 0;
private static final int STATE_CONNECTING = 1;
private static final int STATE_CONNECTED = 2;
public final static String ACTION_GATT_CONNECTED =
"com.example.bluetooth.le.ACTION_GATT_CONNECTED";
public final static String ACTION_GATT_DISCONNECTED =
"com.example.bluetooth.le.ACTION_GATT_DISCONNECTED";
public final static String ACTION_GATT_SERVICES_DISCOVERED =
"com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED";
public final static String ACTION_DATA_AVAILABLE =
"com.example.bluetooth.le.ACTION_DATA_AVAILABLE";
public final static String EXTRA_DATA =
"com.example.bluetooth.le.EXTRA_DATA";
public final static UUID UUID_HEART_RATE_MEASUREMENT =
UUID.fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT);
public static int currentPointer = 0,lastPointer =0;
public static byte[][] receivedArray = new byte[250][2];
// Implements callback methods for GATT events that the app cares about. For example,
// connection change and services discovered.
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
String intentAction;
if (newState == BluetoothProfile.STATE_CONNECTED) {
intentAction = ACTION_GATT_CONNECTED;
mConnectionState = STATE_CONNECTED;
broadcastUpdate(intentAction);
Log.i(TAG, "Connected to GATT server.");
// Attempts to discover services after successful connection.
Log.i(TAG, "Attempting to start service discovery:" +
mBluetoothGatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mConnectionState = STATE_DISCONNECTED;
Log.i(TAG, "Disconnected from GATT server.");
broadcastUpdate(intentAction);
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
};
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
sendBroadcast(intent);
}
private void broadcastUpdate(final String action,
final BluetoothGattCharacteristic characteristic) {
final Intent intent = new Intent(action);
// This is special handling for the Heart Rate Measurement profile. Data parsing is
// carried out as per profile specifications:
// http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml
if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
int flag = characteristic.getProperties();
int format = -1;
if ((flag & 0x01) != 0) {
format = BluetoothGattCharacteristic.FORMAT_UINT16;
Log.d(TAG, "Heart rate format UINT16.");
} else {
format = BluetoothGattCharacteristic.FORMAT_UINT8;
Log.d(TAG, "Heart rate format UINT8.");
}
final int heartRate = characteristic.getIntValue(format, 1);
Log.d(TAG, String.format("Received heart rate: %d", heartRate));
intent.putExtra(EXTRA_DATA, String.valueOf(heartRate));
} else {
// For all other profiles, writes the data formatted in HEX.
final byte[] data = characteristic.getValue();
//sendFunction(data);
//Log.d(TAG, "******Received: " + characteristic.getValue());
//Log.d(TAG, " DATA: " + data);
if (data != null && data.length > 0) { // ******* broadcastUpdate
final StringBuilder stringBuilder = new StringBuilder(data.length);
for(byte byteChar : data)
// stringBuilder.append(String.format("%02X ", byteChar));
//intent.putExtra(EXTRA_DATA, new String(data) + "\n" + stringBuilder.toString());
intent.putExtra(EXTRA_DATA, new String(data) + "\n");
//send(data);
for(int j=0;j<data.length;j++){
byteArrayAppand(data[j]);
//Log.d(TAG,"Data - "+data[j]);
}
/*try{
Thread.sleep(5);
}catch (InterruptedException e){
}*/
//intent.putExtra("dataArray", data); // Data passing between activities
//createByteArray(data);
}
}
sendBroadcast(intent);
}
public void byteArrayAppand(byte data){
receivedArray[lastPointer][0] = data;
receivedArray[lastPointer][1] = 1;
//Log.d(TAG,"Byte Array index - " + lastPointer + " With value of - "+receivedArray[lastPointer][0]);
lastPointer++;
if(lastPointer==250) {
lastPointer = 0;
}
}
public class LocalBinder extends Binder {
BluetoothLeService getService() {
return BluetoothLeService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public boolean onUnbind(Intent intent) {
close();
return super.onUnbind(intent);
}
private final IBinder mBinder = new LocalBinder();
public boolean initialize() {
if (mBluetoothManager == null) {
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (mBluetoothManager == null) {
Log.e(TAG, "Unable to initialize BluetoothManager.");
return false;
}
}
mBluetoothAdapter = mBluetoothManager.getAdapter();
if (mBluetoothAdapter == null) {
Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
return false;
}
return true;
}
public boolean connect(final String address) {
if (mBluetoothAdapter == null || address == null) {
Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
return false;
}
if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress)
&& mBluetoothGatt != null) {
Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");
if (mBluetoothGatt.connect()) {
mConnectionState = STATE_CONNECTING;
return true;
} else {
return false;
}
}
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
Log.w(TAG, "Device not found. Unable to connect.");
return false;
}
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
Log.d(TAG, "Trying to create a new connection.");
mBluetoothDeviceAddress = address;
mConnectionState = STATE_CONNECTING;
return true;
}
public void disconnect() {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.disconnect();
}
public void close() {
if (mBluetoothGatt == null) {
return;
}
mBluetoothGatt.close();
mBluetoothGatt = null;
}
public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.readCharacteristic(characteristic);
}
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
boolean enabled) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
// This is specific to Heart Rate Measurement.
if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
}
}
public List<BluetoothGattService> getSupportedGattServices() {
if (mBluetoothGatt == null) return null;
return mBluetoothGatt.getServices();
}
public byte[] readCustomCharacteristic() {
BLEfree = false;
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return null;
}
BluetoothGattService mCustomService = mBluetoothGatt.getService(UUID.fromString("00002b00-0000-1000-8000-00805f9b34fb"));
if(mCustomService == null){
Log.w(TAG, "Custom BLE Service not found");
return null;
}
BluetoothGattCharacteristic mReadCharacteristic = mCustomService.getCharacteristic(UUID.fromString("00002b10-0000-1000-8000-00805f9b34fb"));
UUID uuid = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
BluetoothGattDescriptor descriptor = mReadCharacteristic.getDescriptor(uuid);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
//To receive notification in Android is mandatory to set characteristic notification to true
mBluetoothGatt.setCharacteristicNotification(mReadCharacteristic, true);
/*get the read characteristic from the service*/
if(mBluetoothGatt.readCharacteristic(mReadCharacteristic) == false){
Log.w(TAG, "Failed to read characteristic from read");
}
BLEfree = true;
return mReadCharacteristic.getValue();
}
private void msg(String s)
{
Toast.makeText(getApplicationContext(),s,Toast.LENGTH_LONG).show();
}
public boolean send(byte[] data) {
BLEfree = false;
BluetoothGattService mCustomService = mBluetoothGatt.getService(UUID.fromString("00002b00-0000-1000-8000-00805f9b34fb"));
if(mCustomService == null){
Log.w(TAG, "Custom BLE Service not found on write");
return false;
}
if (mBluetoothGatt == null || mCustomService == null) {
Log.w(TAG, "BluetoothGatt not initialized");
return false;
}
BluetoothGattCharacteristic characteristic =
mCustomService.getCharacteristic(UUID.fromString("00002b11-0000-1000-8000-00805f9b34fb"));
if (characteristic == null) {
Log.w(TAG, "Send characteristic not found");
return false;
}
characteristic.setValue(data);
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
boolean returnVal = mBluetoothGatt.writeCharacteristic(characteristic);
BLEfree = true;
return returnVal;
}
}

Categories