I'm doing a programme to read data from a sensor. I'm having problems reading the characteristic. I've done the debbug and i checked that the method onCharacteristicRead() is never called, and i don't understand why.
Anyone can help me?
Thanks in advance!!
This is the class:
private Inter inter;
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";
private static final String TAG = BluetoothLeService.class.getSimpleName();
//Services
private BluetoothGattService heartService;
//Characteristics
private BluetoothGattCharacteristic heartCharact;
private BluetoothGatt bluetoothGatt;
private final BluetoothGattCallback gattCallBack = new BluetoothGattCallback() {
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
Log.d(TAG, "Entrei no onCharacteristicRead.");
if (characteristic.getUuid().equals(DeviceConstants.HEART_RATE_MEASUREMENT)) {
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));
getHeartRate(String.valueOf(heartRate));
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
Log.d(TAG, "Entrou no Método: onServicesDiscovered");
super.onServicesDiscovered(gatt, status);
//BluetoothGattCharacteristic characteristic;
if (status == BluetoothGatt.GATT_SUCCESS) {
for (int i = 0; i != bluetoothGatt.getServices().size(); i++) {
if (bluetoothGatt.getServices().get(i).getUuid().equals(DeviceConstants.HEART_RATE_SERVICE)) {
heartService = bluetoothGatt.getServices().get(i);
}
}
for (int j = 0; j != heartService.getCharacteristics().size(); j++) {
if (heartService.getCharacteristics().get(j).getUuid().equals(DeviceConstants.HEART_RATE_MEASUREMENT)) {
Log.d(TAG, "Entrou no if 2");
heartService = bluetoothGatt.getService(DeviceConstants.HEART_RATE_SERVICE);
heartCharact = heartService.getCharacteristic(DeviceConstants.HEART_RATE_MEASUREMENT);
//heartCharact.setValue(1, BluetoothGattCharacteristic.FORMAT_UINT8, 0);
//bluetoothGatt.writeCharacteristic(heartCharact);
//bluetoothGatt.readCharacteristic(heartCharact);
Log.d(TAG, "WOOOOOW: " + heartCharact);
}
}
}
bluetoothGatt.readCharacteristic(heartCharact);
}
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
if (newState == BluetoothProfile.STATE_CONNECTING) {
Log.d(TAG, "Connecting to " + gatt.getDevice().getName() + ", please wait...");
}
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.d(TAG, "Connected!!");
bluetoothGatt.discoverServices();
}
}
public void getHeartRate(String hr) {
inter.getHeartRate(hr);
}
private void broadcastUpdate(final String action, final BluetoothGattCharacteristic characteristic) {
final Intent intent = new Intent(action);
if (DeviceConstants.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 {
final byte[] data = characteristic.getValue();
if (data != null && data.length > 0) {
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());
}
}
sendBroadcast(intent);
}
};
private BluetoothDevice device;
private Context context;
public BluetoothLeService(BluetoothDevice device, Context context, Inter inter) {
this.device = device;
this.context = context;
this.inter = inter;
}
public void connect() {
bluetoothGatt = device.connectGatt(context, false, gattCallBack);
Log.d(TAG, "Entrou no Método: connect");
}
public void disconnect() {
bluetoothGatt.disconnect();
}
It's because some characteristic are not readable.
Have a look at this page: https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.service.heart_rate.xml
And you'll see this Property cannot be read: "Read Excluded".
You should register, then your onCharacteristicChanged callback will be called.
Related
I'm using two BLE peripheral sensors and 1 mobile phone (central). Each BLE peripheral device works well (tested individually).
I followed the <BluetoothLeGatt> example. My phone is HUAWEI Mate 10, which uses Android version 10 and supports BLE 4.2.
In my Android BLE App, after press the Connect Button on the 1st page, App will automatically connect to 2 BLE devices with the names "BC805M BLE ADC1" and "BC805M BLE ADC2".
It seems the App could connect with 2 BLE devices successfully. However, no data received (fail to subscribe characteristic notification). BluetoothGattCallback.onCharacteristicChanged() method is never fired. Therefore, the action never becomes "ACTION_DATA_AVAILABLE".
BLE App screenshot 1
BLE App screenshot 2
I understand the BLE communication is serial. Some people suggested using "onDescriptorWrite()" in BluetoothGattCallback(). However, I don't fully understand how to do it. I attached my Android Studio project here. It would be very appreciated if someone could find the issue.
public class DeviceControlActivity extends Activity {
private final static String TAG = DeviceControlActivity.class.getSimpleName();
public static final String EXTRAS_DEVICE_NAME = "DEVICE_NAME";
public static final String EXTRAS_DEVICE_ADDRESS = "DEVICE_ADDRESS";
public static final String NUMBER_OF_DEVICE = "NUMBER OF DEVICE";
public static final String EXTRAS_DEVICE_NAME_1 = "DEVICE_NAME1";
public static final String EXTRAS_DEVICE_ADDRESS_1 = "DEVICE_ADDRESS1";
public static final String NUMBER_OF_DEVICE_1 = "NUMBER OF DEVICE1";
private TextView mConnectionState;
private TextView mDataField;
private TextView mThumb;
private TextView mIndex;
private TextView mThumb1;
private TextView mIndex1;
private String mDeviceName;
private String mDeviceAddress;
private String mDeviceName1;
private String mDeviceAddress1;
private int DEVICE_NUMBER;
private int DEVICE_NUMBER1;
private int TOTAL_DEVICE;
private BluetoothLeService mBluetoothLeService;
private ArrayList<ArrayList<BluetoothGattCharacteristic>> mGattCharacteristics =
new ArrayList<ArrayList<BluetoothGattCharacteristic>>();
private ArrayList<ArrayList<BluetoothGattCharacteristic>> mGattCharacteristics1 =
new ArrayList<ArrayList<BluetoothGattCharacteristic>>();
private boolean mConnected = false;
private BluetoothGattCharacteristic mNotifyCharacteristic;
private BluetoothGattCharacteristic mNotifyCharacteristic1;
private final String ServiceUUID = "6e400001-b5a3-f393-e0a9-e50e24dcca9e";
private final String CharUUID = "6e400003-b5a3-f393-e0a9-e50e24dcca9e";
private final String LIST_NAME = "NAME";
private final String LIST_UUID = "UUID";
// Code to manage Service lifecycle.
private final ServiceConnection mServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
Log.d(TAG,"Service Connected Called");
mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService();
if (!mBluetoothLeService.initialize()) {
finish();
}
mBluetoothLeService.connect(mDeviceAddress,0);
mBluetoothLeService.connect(mDeviceAddress1, 1);
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
Log.d(TAG,"Service DISConnected Called");
mBluetoothLeService = null;
}
};
private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {
mConnected = true;
updateConnectionState(R.string.connected);
invalidateOptionsMenu();
Log.e(TAG,"ACTION_GATT_CONNECTED ");
} else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
Log.e(TAG,"WHEN IS ACTION GATT DISCONNECTED");
mConnected = false;
updateConnectionState(R.string.disconnected);
invalidateOptionsMenu();
Log.e(TAG,"ACTION_GATT_DISCONNECTED ");
clearUI();
} else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
Log.e(TAG,"ACTION_GATT_SERVICE_DISCOVERED ");
updateGattServices(mBluetoothLeService.getSupportedGattServices(0),0);
try {
Thread.sleep(700);
}catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
Log.e(TAG,"getSupportedGattServices() is done for device #0");
updateGattServices(mBluetoothLeService.getSupportedGattServices(1), 1);
try {
Thread.sleep(700);
}catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
Log.e(TAG,"getSupportedGattServices() is done for device #1");
updateDATA();
} else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
Log.d(TAG,"ACTION_DATA_AVAILABLE ");
mBluetoothLeService.readCharacteristic(mNotifyCharacteristic,0);
displayData(intent.getStringExtra(BluetoothLeService.EXTRA_DATA),0);
mBluetoothLeService.readCharacteristic(mNotifyCharacteristic1, 1);
displayData(intent.getStringExtra(BluetoothLeService.EXTRA_DATA1), 1);
}
}
};
private final boolean updateDATA(){
int servicePos = 0;
int charPos = 0;
if(mGattCharacteristics!=null&&mGattCharacteristics.size()!=0){
final BluetoothGattCharacteristic characteristic = mGattCharacteristics.get(servicePos).get(charPos);
final int charPro = characteristic.getProperties();
if((charPro|BluetoothGattCharacteristic.PROPERTY_READ)>0){
if(mNotifyCharacteristic!= null){
mBluetoothLeService.setCharacteristicNotification(mNotifyCharacteristic,false,0);
}
}
mBluetoothLeService.readCharacteristic(characteristic,0);
if ((charPro | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
Log.d(TAG, "PROPER_NOTIFY > 0");
Log.d(TAG, " ");
}
return true;
}
return false;
}
private void clearUI() {
mDataField.setText(R.string.no_data);
}
#Override
public void onCreate(Bundle savedInstanceState) {
Log.e(TAG,"2.2 onCreate() starts! ");
super.onCreate(savedInstanceState);
setContentView(R.layout.gatt_services_characteristics);
final Intent intent = getIntent();
mDeviceName = intent.getStringExtra(EXTRAS_DEVICE_NAME);
mDeviceAddress = intent.getStringExtra(EXTRAS_DEVICE_ADDRESS);
mDeviceName1 = intent.getStringExtra(EXTRAS_DEVICE_NAME_1);
mDeviceAddress1=intent.getStringExtra(EXTRAS_DEVICE_ADDRESS_1);
DEVICE_NUMBER=intent.getIntExtra(NUMBER_OF_DEVICE,0);
DEVICE_NUMBER1=intent.getIntExtra(NUMBER_OF_DEVICE_1,0);
((TextView) findViewById(R.id.device_address)).setText(mDeviceAddress+" AND "+mDeviceAddress1);
mConnectionState = (TextView) findViewById(R.id.connection_state);
mDataField = (TextView) findViewById(R.id.data_value);
mThumb = (TextView) findViewById(R.id.Thumb);
mIndex = (TextView) findViewById(R.id.Index);
mThumb1 = (TextView) findViewById(R.id.Thumb1);
mIndex1 = (TextView) findViewById(R.id.Index1);
Log.d(TAG,"MY DEVICE NAME "+mDeviceName);
Log.d(TAG,"MY DEVICE ADDRESS "+mDeviceAddress);
Log.d(TAG,"MY DEVICE NUMBER "+DEVICE_NUMBER);
Log.d(TAG,"MY DEVICE NAME1 "+mDeviceName1);
Log.d(TAG,"MY DEVICE ADDRESS1 "+mDeviceAddress1);
Log.d(TAG,"MY DEVICE NUMBER1 "+DEVICE_NUMBER1);
getActionBar().setTitle(mDeviceName+" "+mDeviceName1);
getActionBar().setDisplayHomeAsUpEnabled(true);
Intent gattServiceIntent = new Intent(this, BluetoothLeService.class);
bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
}
#Override
protected void onResume() {
Log.e(TAG,"2.2 onResume is Called");
super.onResume();
registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
if (mBluetoothLeService != null) {
boolean result = mBluetoothLeService.connect(mDeviceAddress,0);
boolean result1 = mBluetoothLeService.connect(mDeviceAddress1, 1);
Log.d(TAG, "Connect request result = " + result+" "+result1);
}
}
#Override
protected void onPause() {
Log.d(TAG,"onPause is called");
super.onPause();
unregisterReceiver(mGattUpdateReceiver);
}
#Override
protected void onDestroy() {
Log.d(TAG,"onDestroy is Called");
super.onDestroy();
unbindService(mServiceConnection);
mBluetoothLeService = null;
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.gatt_services, menu);
if (mConnected) {
menu.findItem(R.id.menu_connect).setVisible(false);
menu.findItem(R.id.menu_disconnect).setVisible(true);
} else {
menu.findItem(R.id.menu_connect).setVisible(true);
menu.findItem(R.id.menu_disconnect).setVisible(false);
}
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()) {
case R.id.menu_connect:
mBluetoothLeService.connect(mDeviceAddress,0);
mBluetoothLeService.connect(mDeviceAddress1, 1);
return true;
case R.id.menu_disconnect:
Log.d(TAG,"FIRST DEVICE"+DEVICE_NUMBER);
mBluetoothLeService.disconnect();
return true;
case android.R.id.home:
Log.d(TAG,"HOME IS PRESSED");
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
private void updateConnectionState(final int resourceId) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mConnectionState.setText(resourceId);
}
});
}
private void displayData(String data,int device) {
if (data != null && device ==0) {
mThumb1.setText(data.substring(1, 4));
mIndex1.setText(data.substring(5, 8));
}
else if(data != null && device == 1) {
mThumb.setText(data.substring(1, 4));
mIndex.setText(data.substring(5, 8));
}
}
private void updateGattServices(List<BluetoothGattService> gattServices,int device) {
if (gattServices == null) return;
String uuid = null;
String unknownServiceString = getResources().getString(R.string.unknown_service);
String unknownCharaString = getResources().getString(R.string.unknown_characteristic);
ArrayList<HashMap<String, String>> gattServiceData = new ArrayList<HashMap<String, String>>();
if(device ==0) {
mGattCharacteristics = new ArrayList<ArrayList<BluetoothGattCharacteristic>>();
Log.e(TAG,"mGattCharacteristics is created for device #0");
}
else if(device ==1) {
mGattCharacteristics1 = new ArrayList<ArrayList<BluetoothGattCharacteristic>>();
Log.e(TAG,"mGattCharacteristics is created for device #1");
}
int i=0;
int j=0;
// Loops through available GATT Services.
Log.e(TAG,"Start For Loop");
for (BluetoothGattService gattService : gattServices) {
Log.e(TAG,"Service index = " + i);
HashMap<String, String> currentServiceData = new HashMap<String, String>();
uuid = gattService.getUuid().toString();
if(uuid.equals(ServiceUUID)) {
Log.e(TAG,"Selected Service index = " + i);
currentServiceData.put(LIST_NAME, SampleGattAttributes.lookup(uuid, unknownServiceString));
currentServiceData.put(LIST_UUID, "");
gattServiceData.add(currentServiceData);
ArrayList<HashMap<String, String>> gattCharacteristicGroupData = new ArrayList<HashMap<String, String>>();
List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
ArrayList<BluetoothGattCharacteristic> charas = new ArrayList<BluetoothGattCharacteristic>();
// Loops through available Characteristics.
for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
Log.e(TAG,"Characteristic index = " + j);
charas.add(gattCharacteristic);
HashMap<String, String> currentCharaData = new HashMap<String, String>();
uuid = gattCharacteristic.getUuid().toString();
if(uuid.equals(CharUUID)) {
Log.e(TAG,"Selected Characteristic index = " + j);
currentCharaData.put(
LIST_NAME, SampleGattAttributes.lookup(uuid, unknownCharaString));
currentCharaData.put(LIST_UUID, "");
gattCharacteristicGroupData.add(currentCharaData);
if(device ==0){
mNotifyCharacteristic=gattCharacteristic;
}
else if(device ==1){
mNotifyCharacteristic1=gattCharacteristic;
}
}
j = j +1;
}
if(device ==0){
mGattCharacteristics.add(charas);
}
else if(device ==1){
mGattCharacteristics1.add(charas);
}
}
i = i + 1 ;
}
}
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;
}
}
public class BluetoothLeService extends Service {
private final static String TAG = BluetoothLeService.class.getSimpleName();
private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private String mBluetoothDeviceAddress;
private String mBluetoothDeviceAddress1;
private BluetoothGatt mBluetoothGatt;
private BluetoothGatt mBluetoothGatt1;
private int mConnectionState = STATE_DISCONNECTED;
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 String EXTRA_DATA1 =
"com.example.bluetooth.le.EXTRA_DATA1";
public final static UUID ServiceUUID2 = UUID.fromString("6e400001-b5a3-f393-e0a9-e50e24dcca9e");
public final static UUID CharUUID2 = UUID.fromString("6e400003-b5a3-f393-e0a9-e50e24dcca9e");
// 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.e(TAG, "Connected to GATT server.");
// Attempts to discover services after successful connection.
Log.e(TAG, "Attempting to start service discovery:" + mBluetoothGatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mConnectionState = STATE_DISCONNECTED;
Log.e(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.e(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic,0);
}
Log.e(TAG,"onCHAR READ");
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic,0);
Log.e(TAG,"onCharacteristicChanged #0 = ACTION_DATA_AVAILABLE, Done! ");
}
#Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorWrite(gatt, descriptor, status);
Log.e(TAG,"onDescriptorWrite #0, Done! ");
}
};
private final BluetoothGattCallback mGattCallback1 = 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.e(TAG, "Connected to GATT server.");
Log.e(TAG, "Attempting to start service discovery:" +
mBluetoothGatt1.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mConnectionState = STATE_DISCONNECTED;
Log.e(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.e(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic,1);
}
Log.e(TAG,"onCHAR READ in callback 1");
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic,1);
Log.e(TAG,"onCharacteristicChanged #0 = ACTION_DATA_AVAILABLE, Done! ");
}
#Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
Log.e(TAG,"onDescriptorWrite starts");
if (descriptor.getUuid().equals(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG)) {
BluetoothGattCharacteristic characteristic = gatt
.getService(ServiceUUID2)
.getCharacteristic(CharUUID2);
gatt.readCharacteristic(characteristic);
}
Log.e(TAG,"onDescriptorWrite #1, Done!");
}
};
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
sendBroadcast(intent);
}
private void broadcastUpdate(final String action,
final BluetoothGattCharacteristic characteristic,int device) {
final Intent intent = new Intent(action);
final byte[] data = characteristic.getValue();
if (data != null && data.length > 0&&device ==0) {
final StringBuilder stringBuilder = new StringBuilder(data.length);
for(byte byteChar : data)
stringBuilder.append(String.format("%02X ", byteChar));
String DATA = stringBuilder.toString();
Log.d(TAG,"MY DATA IN HEX " + DATA);
String DecData =HexAsciiConverter.HexAscii2Decimal(DATA);
Log.d(TAG,"MY DATA IN DECIMAL "+ DecData);
intent.putExtra(EXTRA_DATA, " " + DecData);
}
else if( data != null && data.length > 0 && device ==1 ){
final StringBuilder stringBuilder = new StringBuilder(data.length);
for(byte byteChar : data)
stringBuilder.append(String.format("%02X ", byteChar));
String DATA = stringBuilder.toString();
Log.d(TAG,"MY DATA IN HEX " + DATA);
String DecData =HexAsciiConverter.HexAscii2Decimal(DATA);
Log.d(TAG,"MY DATA IN DECIMAL "+ DecData);
intent.putExtra(EXTRA_DATA1, " " + DecData);
}
sendBroadcast(intent);
}
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() {
// For API level 18 and above, get a reference to BluetoothAdapter through
// BluetoothManager.
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,int devicenum) {
if (mBluetoothAdapter == null || address == null) {
Log.e(TAG, "BluetoothAdapter not initialized or unspecified address.");
return false;
}
// Previously connected device. Try to reconnect.
if ((mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress))
|| (mBluetoothDeviceAddress1!=null && address.equals(mBluetoothDeviceAddress1))) {
Log.e(TAG, "Trying to use an existing mBluetoothGatt for connection.");
if (devicenum==0&&mBluetoothGatt.connect()) {
mConnectionState = STATE_CONNECTING;
return true;
}
else if(devicenum==1 && mBluetoothGatt1.connect()) {
mConnectionState = STATE_CONNECTING;
return true;
}
else{
return false;
}
}
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
Log.e(TAG, "Device not found. Unable to connect.");
return false;
}
if(devicenum==0){
mBluetoothGatt1 = device.connectGatt(this,false,mGattCallback);
mBluetoothDeviceAddress= address;
mConnectionState = STATE_CONNECTING;
Log.e(TAG,"GATT CALLBACK #0 ! "+address);
}
else if(devicenum ==1){
mBluetoothGatt = device.connectGatt(this, false, mGattCallback1);
mBluetoothDeviceAddress1=address;
mConnectionState = STATE_CONNECTING;
Log.e(TAG,"GATT CALLBACK #1 ! "+address);
}
Log.e(TAG, "Trying to create a new connection.");
return true;
}
public void disconnect() {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.e(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.disconnect();
if(mBluetoothGatt1!=null){
mBluetoothGatt1.disconnect();
}
}
public void close() {
if (mBluetoothGatt == null) {
return;
}
mBluetoothGatt.close();
mBluetoothGatt1.close();
mBluetoothGatt1 = null;
mBluetoothGatt = null;
}
public void readCharacteristic(BluetoothGattCharacteristic characteristic,int device) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.e(TAG, "BluetoothAdapter not initialized");
return;
}
if (device == 0) {
mBluetoothGatt.readCharacteristic(characteristic);
}
else if(device ==1){
mBluetoothGatt1.readCharacteristic(characteristic);
}
}
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled,int device) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.e(TAG, "BluetoothAdapter not initialized");
return;
}
if(device == 0) {
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.e(TAG,"Device #0 is done for notification!");
}
else if(device == 1){
mBluetoothGatt1.setCharacteristicNotification(characteristic,enabled);
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.e(TAG,"Device #1 is done for notification!");
}
}
public List<BluetoothGattService> getSupportedGattServices(int device) {
if (mBluetoothGatt == null) return null;
if(device ==0) {
return mBluetoothGatt.getServices();
}
else {
return mBluetoothGatt1.getServices();
}
}
}
I am trying to get data from a glucose meter and I am not able to find good resources regarding the implementation on internet. Here is what I have been able to implement till now:
I am scanning the devices using BluetoothAdapter.LeScanCallback Interface:
#Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
if ((device.getName() != null) && !bleDevices.contains(device)) {
bleDevices.add(device);
}
}
After getting the devices I am connecting to device using:
device.connectGatt(MainActivity.this, true, bleGattCallBack);
In BluetoothGattCallback class I am able to get the status connected in:
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
connectionState = STATE_CONNECTED;
gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
connectionState = STATE_DISCONNECTED;
gatt.close();
}
}
After that onServicesDiscovered gets called
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
List<BluetoothGattService> gattServices = gatt.getServices();
for (BluetoothGattService gattService : gattServices) {
String serviceUUID = gattService.getUuid().toString();
if (serviceUUID.equals("00001808-0000-1000-8000-00805f9b34fb")) {
List<BluetoothGattCharacteristic> characteristics = gattService.getCharacteristics();
for (BluetoothGattCharacteristic characteristic : characteristics) {
if (characteristic.getUuid().equals(UUID.fromString("00002a18-0000-1000-8000-00805f9b34fb"))) {
BluetoothGattCharacteristic charGM =
gatt.getService(UUID.fromString("00001808-0000-1000-8000-00805f9b34fb"))
.getCharacteristic(UUID.fromString("00002a18-0000-1000-8000-00805f9b34fb"));
gatt.setCharacteristicNotification(charGM, true);
glucoseCharacteristic = characteristic;
BluetoothGattDescriptor descGM = charGM.getDescriptor(UUID.fromString(BleUuid.CHAR_CLIENT_CHARACTERISTIC_CONFIG_STRING));
descGM.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(descGM);
} else if (characteristic.getUuid().equals(UUID.fromString("00002a52-0000-1000-8000-00805f9b34fb"))) {
BluetoothGattCharacteristic charRACP =
gatt.getService(UUID.fromString("00001808-0000-1000-8000-00805f9b34fb"))
.getCharacteristic(UUID.fromString("00002a52-0000-1000-8000-00805f9b34fb"));
gatt.setCharacteristicNotification(charRACP, true);
BluetoothGattDescriptor descRACP = charRACP.getDescriptor(UUID.fromString(BleUuid.CHAR_CLIENT_CHARACTERISTIC_CONFIG_STRING));
descRACP.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
gatt.writeDescriptor(descRACP);
}
}
}
} else {
}
}
After this onDescriptorWrite gets called:
#Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorWrite(gatt, descriptor, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.d(TAG, "onDescriptorWrite: GATT_SUCCESS");
BluetoothGattCharacteristic writeRACPchar =
gatt.getService(UUID.fromString("00001808-0000-1000-8000-00805f9b34fb"))
.getCharacteristic(UUID.fromString("00002a52-0000-1000-8000-00805f9b34fb"));
byte[] data = new byte[2];
data[0] = 0x01; // Report Stored records
data[1] = 0x01; // All records
writeRACPchar.setValue(data);
gatt.writeCharacteristic(writeRACPchar);
} else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_NONE) {
Log.d(TAG, "onDescriptorWrite: GATT_INSUFFICIENT_AUTHENTICATION");
}
} else {
Log.d(TAG, "onDescriptorWrite: GATT_INSUFFICIENT_AUTHENTICATION");
}
}
and then onCharacteristicWrite
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
final byte[] data = characteristic.getValue();
if (data != null && data.length > 0) {
final StringBuilder stringBuilder = new StringBuilder(data.length);
for (byte byteChar : data)
stringBuilder.append(String.format("%02X ", byteChar));
Log.d(TAG, "onCharacteristicWrite: " + status + "\n" + characteristic.getUuid() + "\n" + stringBuilder.toString() + "\n" + characteristic.getValue().length);
}
}
Now, how do I proceed further? I know that I will get the data in onCharacteristicRead but that is never called.
The task is to transfer information from a chip with BLE 4.0 to an Android device at high speed (at least 24 kbps). Bluetooth specification allows it. We used two methods: write / read (we write the request into one characteristic, the answer is read from the other) and notify (the chip constantly transmitted packets with a frequency of 50 ms). In the case of write / read, the time for rewriting and reading a packet varies in the region of 100 ms. When using notify, the time was set to 50 ms, but Android was losing packets. Instead, he received the old values of the packets, or missed and read the next one twice, although the chip accurately sent notifications with new values. How can I solve or work around this problem?
private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {
mConnected = true;
updateConnectionState(R.string.connected);
invalidateOptionsMenu();
} else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
mConnected = false;
updateConnectionState(R.string.disconnected);
invalidateOptionsMenu();
clearUI();
} else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
// Show all the supported services and characteristics on the user interface.
//displayGattServices(mBluetoothLeService.getSupportedGattServices());
} else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
stopT =System.currentTimeMillis();
//double td=stopT-startT;
time1.add(stopT - startT);
//double td = Math;
double sum = 0;
for(int i =0;i<time1.size();i++) sum+= time1.get(i);
double td = sum/time1.size();
TextView textView3 = (TextView) findViewById(R.id.textView3);
textView3.setText(String.valueOf(td));
displayData(intent.getStringExtra(BluetoothLeService.EXTRA_DATA));
//for (int i = 0; i < BluetoothLeService.byteArray.length; i++) time.add(Double.valueOf(BluetoothLeService.byteArray[i]));
float[] floatArray = new float[BluetoothLeService.byteArray.length];
for (int i = 0; i < BluetoothLeService.byteArray.length; i++) floatArray[i] = (float)BluetoothLeService.byteArray[i];
float[] tmp = new float[time2.length + floatArray.length];
System.arraycopy(time2, 0, tmp, 0, time2.length);
System.arraycopy(floatArray, 0, tmp, time2.length, floatArray.length);
time2 = tmp;
if (cnt1 < 51) {
Matr[cnt1]=floatArray;
cnt1++;
}
if (flag == 1) {
startT = System.currentTimeMillis();
//mBluetoothLeService.readCustomCharacteristic();
mBluetoothLeService.writeCustomCharacteristic(hex);
}
if(flag_notify == 1)startT = System.currentTimeMillis();
} else if (BluetoothLeService.ACTION_CHARACTERISTIC_WRITE.equals(action)) {
mBluetoothLeService.readCustomCharacteristic();
}
}
};
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();
byteArray =data;
if (data != null && data.length > 0) {
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());
}
}
sendBroadcast(intent);
}
BluetoothGattCallback:
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;
//gatt.requestMtu(512);
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 onCharacteristicWrite(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_CHARACTERISTIC_WRITE, characteristic);
} else {
Log.w(TAG, "onCharacteristicWrite received: " + status);
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
};
Upd.: Changes in Callback function.
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
StopT = System.currentTimeMillis();
if (cnt1 < kolvo) {
save[cnt1]=characteristic.getValue();
td1 [cnt1] = StopT - StartT;
StartT = System.currentTimeMillis();
cnt1++;
}
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
I'm trying to read GATT characteristic values from a Bluetooth LE device (a Heart Rate bracelet). Its specs are:
Services
Characteristics
I have not yet figured out how to "read" the specifications and "translate" them into code.
I need to show on my app the heartbeats detected by the device. What is the way to read the GATT values? A code example would be much appreciated :)
Follow my actual source code.
SETUP THE BLUETOOT CONNECTION
private BluetoothAdapter mBluetoothAdapter;
private BluetoothGatt mBluetoothGatt;
private Handler mHandler;
private static final int REQUEST_ENABLE_BT = 1;
private static final long SCAN_PERIOD = 10000;
// ...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bluetooth);
mHandler = new Handler();
// BLE is supported?
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, "Bluetooth Low Energy non supportato", Toast.LENGTH_SHORT).show();
finish();
}
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
// Bluetooth is supported?
if (mBluetoothAdapter == null) {
Toast.makeText(this, "Bluetooth non supportato", Toast.LENGTH_SHORT).show();
finish();
}
}
#Override
protected void onResume() {
super.onResume();
// Bluetooth is enabled?
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
scanLeDevice(true);
}
#Override
protected void onPause() {
super.onPause();
if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) {
scanLeDevice(false);
}
}
DISCOVER BLE DEVICES AND CONNECT WITH HEART RATE MONITOR
// Device scan callback.
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Log.i(TAG, "Name: " + device.getName() + " (" + device.getAddress() + ")");
String deviceAddress = device.getAddress();
if (deviceAddress.equals("C0:19:37:54:9F:30")) {
connectToDevice(device);
}
}
});
}
};
public void connectToDevice(BluetoothDevice device) {
if (mBluetoothGatt == null) {
Log.i(TAG, "Attempting to connect to device " + device.getName() + " (" + device.getAddress() + ")");
mBluetoothGatt = device.connectGatt(this, true, gattCallback);
scanLeDevice(false);// will stop after first device detection
}
}
private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
Log.i(TAG, "Status: " + status);
switch (newState) {
case BluetoothProfile.STATE_CONNECTED:
Log.i(TAG, "STATE_CONNECTED");
//BluetoothDevice device = gatt.getDevice(); // Get device
gatt.discoverServices();
break;
case BluetoothProfile.STATE_DISCONNECTED:
Log.e(TAG, "STATE_DISCONNECTED");
break;
default:
Log.e(TAG, "STATE_OTHER");
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
List<BluetoothGattService> services = gatt.getServices();
Log.i(TAG, "Services: " + services.toString());
BluetoothGattCharacteristic bpm = services.get(2).getCharacteristics().get(0);
gatt.readCharacteristic(services.get(0).getCharacteristics().get(0));
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
// my attempt to read and print characteristics
byte[] charValue = characteristic.getValue();
byte flag = charValue[0];
Log.i(TAG, "Characteristic: " + flag);
//gatt.disconnect();
}
};
try with this inside gattCallback:
#Override
public synchronized void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
final byte[] dataInput = characteristic.getValue();
}
EDIT
And I think you are going to receive a byte with the hear rate data, use this function to get the int value:
public int unsignedByteToInt(byte b) {
return b & 0xFF;
}
And call it inside onCharacteristicChanged():
final byte[] dataInput = characteristic.getValue();
int hearRate = unsignedByteToInt(dataInput);
EDIT 2
Create a notification listener for the heart rate:
public void setHeartRateNotification(boolean enable){
String uuidHRCharacteristic = "YOUR CHARACTERISTIC";
BluetoothGattService mBluetoothLeService = null;
BluetoothGattCharacteristic mBluetoothGattCharacteristic = null;
for (BluetoothGattService service : mBluetoothGatt.getServices()) {
if ((service == null) || (service.getUuid() == null)) {
continue;
}
if (uuidAccelService.equalsIgnoreCase(service.getUuid().toString())) {
mBluetoothLeService = service;
}
}
if(mBluetoothLeService!=null) {
mBluetoothGattCharacteristic =
mBluetoothLeService.getCharacteristic(UUID.fromString(uuidHRCharacteristic));
}
else{
Log.i("Test","mBluetoothLeService is null");
}
if(mBluetoothGattCharacteristic!=null) {
setCharacteristicNotification(mBluetoothGattCharacteristic, enable);
Log.i("Test","setCharacteristicNotification:"+true);
}
else{
Log.i("Test","mBluetoothGattCharacteristic is null");
}
}
And set it onServiceDiscover inside gattCallback:
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
Log.i("Test", "onServicesDiscovered received: " + status);
setHeartRateNotification(true);
}
My goal in this question is push the rssilevel from one .java file to the other.
I tried to push from class 1 to class 2, as well as pulling data dfrom class 1 to class 2 and i have always had my app crash.
I tried
ProximityManager temp = new ProximityManager();
int temp = temp.rssilevel;
The above code is in a class in the same package, but different .java file and class. They are linked.
and it would not work, any other ideas please!
EDIT: Also how would i call the function playSound() in another class?
i would normaly do something like Public ProximityManager mProximityManager;
then call mProximityManager.playSound(); but i get an app crash when i do this.
public class ProximityManager implements BleManager<ProximityManagerCallbacks> {
private final String TAG = "ProximityManager";
private ProximityManagerCallbacks mCallbacks;
private BluetoothGattServer mBluetoothGattServer;
private BluetoothGatt mBluetoothGatt;
private BluetoothDevice mDeviceToConnect;
private Context mContext;
private Handler mHandler;
private LogSession mLogSession;
private Ringtone mRingtoneNotification;
private Ringtone mRingtoneAlarm;
public int rssilevel;
public final static UUID IMMEIDIATE_ALERT_SERVICE_UUID = UUID.fromString("00001802-0000-1000-8000-00805f9b34fb");
public final static UUID LINKLOSS_SERVICE_UUID = UUID.fromString("00001803-0000-1000-8000-00805f9b34fb");
private static final UUID ALERT_LEVEL_CHARACTERISTIC_UUID = UUID.fromString("00002A06-0000-1000-8000-00805f9b34fb");
private final static UUID BATTERY_SERVICE_UUID = UUID.fromString("0000180F-0000-1000-8000-00805f9b34fb");
private final static UUID BATTERY_LEVEL_CHARACTERISTIC_UUID = UUID.fromString("00002A19-0000-1000-8000-00805f9b34fb");
private final static UUID TX_POWER_UUID = UUID.fromString("00001804-0000-1000-8000-00805f9b34fb");
private final static String ERROR_CONNECTION_STATE_CHANGE = "Error on connection state change";
private final static String ERROR_DISCOVERY_SERVICE = "Error on discovering services";
private final static String ERROR_AUTH_ERROR_WHILE_BONDED = "Phone has lost bonding information";
private final static String ERROR_WRITE_CHARACTERISTIC = "Error on writing characteristic";
private final static String ERROR_READ_CHARACTERISTIC = "Error on reading characteristic";
private final static int HIGH_ALERT = 2;
private final static int MID_ALERT = 1;
private final static int NO_ALERT = 0;
private BluetoothGattCharacteristic mAlertLevelCharacteristic, mLinklossCharacteristic, mBatteryCharacteristic;
private boolean userDisconnectedFlag = false;
public void getrssi( int rssilevel) {
this.rssilevel = rssilevel;
}
public ProximityManager(Context context) {
initializeAlarm(context);
mHandler = new Handler();
// Register bonding broadcast receiver
final IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
context.registerReceiver(mBondingBroadcastReceiver, filter);
}
private void openGattServer(Context context, BluetoothManager manager) {
mBluetoothGattServer = manager.openGattServer(context, mGattServerCallbacks);
}
private void closeGattServer() {
if (mBluetoothGattServer != null) {
// mBluetoothGattServer.cancelConnection(mBluetoothGatt.getDevice()); // FIXME this method does not cancel the connection
mBluetoothGattServer.close(); // FIXME This method does not cause BluetoothGattServerCallback#onConnectionStateChange(newState=DISCONNECTED) to be called on Nexus phones.
mBluetoothGattServer = null;
}
}
private void addImmediateAlertService() {
/*
* This method must be called in UI thread. It works fine on Nexus devices but if called from other thread (f.e. from onServiceAdded in gatt server callback) it hangs the app.
*/
BluetoothGattCharacteristic alertLevel = new BluetoothGattCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID, BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE,
BluetoothGattCharacteristic.PERMISSION_WRITE);
alertLevel.setValue(HIGH_ALERT, BluetoothGattCharacteristic.FORMAT_UINT8, 0);
BluetoothGattService immediateAlertService = new BluetoothGattService(IMMEIDIATE_ALERT_SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY);
immediateAlertService.addCharacteristic(alertLevel);
mBluetoothGattServer.addService(immediateAlertService);
}
private void addLinklossService() {
/*
* This method must be called in UI thread. It works fine on Nexus devices but if called from other thread (f.e. from onServiceAdded in gatt server callback) it hangs the app.
*/
BluetoothGattCharacteristic linklossAlertLevel = new BluetoothGattCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID, BluetoothGattCharacteristic.PROPERTY_WRITE
| BluetoothGattCharacteristic.PROPERTY_READ, BluetoothGattCharacteristic.PERMISSION_WRITE);
linklossAlertLevel.setValue(HIGH_ALERT, BluetoothGattCharacteristic.FORMAT_UINT8, 0);
BluetoothGattService linklossService = new BluetoothGattService(LINKLOSS_SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY);
linklossService.addCharacteristic(linklossAlertLevel);
mBluetoothGattServer.addService(linklossService);
}
private BluetoothGattServerCallback mGattServerCallbacks = new BluetoothGattServerCallback() {
#Override
public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {
DebugLogger.d(TAG, "[Proximity Server] onCharacteristicReadRequest " + device.getName());
}
#Override
public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset,
byte[] value) {
DebugLogger.d(TAG, "[Proximity Server] onCharacteristicWriteRequest " + device.getName());
final int receivedValue = value[0];
if (receivedValue != NO_ALERT) {
Logger.i(mLogSession, "[Proximity Server] Immediate alarm request received: ON");
playAlarm();
} else {
Logger.i(mLogSession, "[Proximity Server] Immediate alarm request received: OFF");
stopAlarm();
}
}
#Override
public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
DebugLogger.d(TAG, "[Proximity Server] onConnectionStateChange " + device.getName() + " status: " + status + " new state: " + newState);
}
#Override
public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) {
DebugLogger.d(TAG, "[Proximity Server] onDescriptorReadRequest " + device.getName());
}
#Override
public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
DebugLogger.d(TAG, "[Proximity Server] onDescriptorWriteRequest " + device.getName());
}
#Override
public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) {
DebugLogger.d(TAG, "[Proximity Server] onExecuteWrite " + device.getName());
}
#Override
public void onServiceAdded(final int status, final BluetoothGattService service) {
DebugLogger.d(TAG, "[Proximity Server] onServiceAdded " + service.getUuid());
mHandler.post(new Runnable() {
#Override
public void run() {
// adding another service from callback thread fails on Samsung S4 with Android 4.3
if (IMMEIDIATE_ALERT_SERVICE_UUID.equals(service.getUuid()))
addLinklossService();
else {
DebugLogger.d(TAG, "[Proximity Server] Gatt server started");
Logger.i(mLogSession, "[Proximity Server] Gatt server started");
if (mBluetoothGatt == null) {
mBluetoothGatt = mDeviceToConnect.connectGatt(mContext, false, mGattCallback);
mDeviceToConnect = null;
} else {
mBluetoothGatt.connect();
}
}
}
});
}
};
/**
* Callbacks for activity {HTSActivity} that implements HTSManagerCallbacks interface activity use this method to register itself for receiving callbacks
*/
#Override
public void setGattCallbacks(ProximityManagerCallbacks callbacks) {
mCallbacks = callbacks;
}
/**
* Sets the log session that can be used to log events
*
* #param logSession
*/
public void setLogger(LogSession logSession) {
mLogSession = logSession;
}
#Override
public void connect(Context context, BluetoothDevice device) {
mContext = context;
// save the device that we want to connect to
mDeviceToConnect = device;
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
if (preferences.getBoolean(ProximityActivity.PREFS_GATT_SERVER_ENABLED, true)) {
final BluetoothManager bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
try {
DebugLogger.d(TAG, "[Proximity Server] Starting Gatt server...");
Logger.v(mLogSession, "[Proximity Server] Starting Gatt server...");
openGattServer(context, bluetoothManager);
addImmediateAlertService();
// the BluetoothGattServerCallback#onServiceAdded callback will proceed further operations
} catch (final Exception e) {
// On Nexus 4&7 with Android 4.4 (build KRT16S) sometimes creating Gatt Server fails. There is a Null Pointer Exception thrown from addCharacteristic method.
Logger.e(mLogSession, "[Proximity Server] Gatt server failed to start");
Log.e(TAG, "Creating Gatt Server failed", e);
}
} else {
if (mBluetoothGatt == null) {
mBluetoothGatt = mDeviceToConnect.connectGatt(context, false, mGattCallback);
mDeviceToConnect = null;
} else {
mBluetoothGatt.connect();
}
}
}
#Override
public void disconnect() {
if (mBluetoothGatt != null) {
userDisconnectedFlag = true;
mBluetoothGatt.disconnect();
stopAlarm();
closeGattServer();
}
}
private void initializeAlarm(Context context) {
final Uri alarmUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
mRingtoneAlarm = RingtoneManager.getRingtone(context, alarmUri);
mRingtoneAlarm.setStreamType(AudioManager.STREAM_ALARM);
final Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
mRingtoneNotification = RingtoneManager.getRingtone(context, notification);
}
private void playNotification() {
DebugLogger.d(TAG, "playNotification");
mRingtoneNotification.play();
}
private void playAlarm() {
DebugLogger.d(TAG, "playAlarm");
final AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
am.setStreamVolume(AudioManager.STREAM_ALARM, am.getStreamMaxVolume(AudioManager.STREAM_ALARM), AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
mRingtoneAlarm.play();
}
private void stopAlarm() {
DebugLogger.d(TAG, "stopAlarm");
mRingtoneAlarm.stop();
}
/**
* BluetoothGatt callbacks for connection/disconnection, service discovery, receiving indication, etc
*/
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (status == BluetoothGatt.GATT_SUCCESS) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
DebugLogger.d(TAG, "Device connected");
mBluetoothGatt.discoverServices();
//This will send callback to ProximityActivity when device get connected
mCallbacks.onDeviceConnected();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
DebugLogger.d(TAG, "Device disconnected");
if (userDisconnectedFlag) {
mCallbacks.onDeviceDisconnected();
userDisconnectedFlag = false;
} else {
playNotification();
mCallbacks.onLinklossOccur();
}
}
} else {
mCallbacks.onError(ERROR_CONNECTION_STATE_CHANGE, status);
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
final List<BluetoothGattService> services = gatt.getServices();
for (BluetoothGattService service : services) {
if (service.getUuid().equals(IMMEIDIATE_ALERT_SERVICE_UUID)) {
DebugLogger.d(TAG, "Immediate Alert service is found");
mAlertLevelCharacteristic = service.getCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID);
} else if (service.getUuid().equals(LINKLOSS_SERVICE_UUID)) {
DebugLogger.d(TAG, "Linkloss service is found");
mLinklossCharacteristic = service.getCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID);
} else if (service.getUuid().equals(BATTERY_SERVICE_UUID)) {
DebugLogger.d(TAG, "Battery service is found");
mBatteryCharacteristic = service.getCharacteristic(BATTERY_LEVEL_CHARACTERISTIC_UUID);
}
}
if (mLinklossCharacteristic == null) {
mCallbacks.onDeviceNotSupported();
gatt.disconnect();
} else {
mCallbacks.onServicesDiscovered(mAlertLevelCharacteristic != null);
writeLinklossAlertLevel(HIGH_ALERT);
}
} else {
mCallbacks.onError(ERROR_DISCOVERY_SERVICE, status);
}
mBluetoothGatt.readRemoteRssi();
DebugLogger.d(TAG, "Finished READING THE RSSI");
}
#Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
if (rssi != 0) {
rssilevel = rssi; }
else {
rssilevel = 0; }
DebugLogger.d(TAG, "READING THE RSSI");
}
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
if (characteristic.getUuid().equals(BATTERY_LEVEL_CHARACTERISTIC_UUID)) {
int batteryValue = characteristic.getValue()[0];
mCallbacks.onBatteryValueReceived(batteryValue);
}
} else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_NONE) {
DebugLogger.w(TAG, ERROR_AUTH_ERROR_WHILE_BONDED);
mCallbacks.onError(ERROR_AUTH_ERROR_WHILE_BONDED, status);
}
} else {
mCallbacks.onError(ERROR_READ_CHARACTERISTIC, status);
}
}
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
if (characteristic.getUuid().equals(ALERT_LEVEL_CHARACTERISTIC_UUID)) {
if (mBatteryCharacteristic != null) {
readBatteryLevel();
}
}
} else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_NONE) {
DebugLogger.w(TAG, ERROR_AUTH_ERROR_WHILE_BONDED);
mCallbacks.onError(ERROR_AUTH_ERROR_WHILE_BONDED, status);
}
} else {
mCallbacks.onError(ERROR_WRITE_CHARACTERISTIC, status);
}
}
};
private BroadcastReceiver mBondingBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(final Context context, final Intent intent) {
final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
final int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1);
final int previousBondState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, -1);
// skip other devices
if (!device.getAddress().equals(mBluetoothGatt.getDevice().getAddress()))
return;
DebugLogger.i(TAG, "Bond state changed for: " + device.getName() + " new state: " + bondState + " previous: " + previousBondState);
if (bondState == BluetoothDevice.BOND_BONDING) {
mCallbacks.onBondingRequired();
return;
}
if (bondState == BluetoothDevice.BOND_BONDED) {
if (mLinklossCharacteristic != null) {
writeLinklossAlertLevel(HIGH_ALERT);
}
mCallbacks.onBonded();
}
}
};
private void readBatteryLevel() {
if (mBatteryCharacteristic != null) {
DebugLogger.d(TAG, "reading battery characteristic");
mBluetoothGatt.readCharacteristic(mBatteryCharacteristic);
} else {
DebugLogger.w(TAG, "Battery Level Characteristic is null");
}
}
#SuppressWarnings("unused")
private void readLinklossAlertLevel() {
if (mLinklossCharacteristic != null) {
DebugLogger.d(TAG, "reading linkloss alert level characteristic");
mBluetoothGatt.readCharacteristic(mLinklossCharacteristic);
} else {
DebugLogger.w(TAG, "Linkloss Alert Level Characteristic is null");
}
}
private void writeLinklossAlertLevel(int alertLevel) {
if (mLinklossCharacteristic != null) {
DebugLogger.d(TAG, "writing linkloss alert level characteristic");
mLinklossCharacteristic.setValue(alertLevel, BluetoothGattCharacteristic.FORMAT_UINT8, 0);
mBluetoothGatt.writeCharacteristic(mLinklossCharacteristic);
} else {
DebugLogger.w(TAG, "Linkloss Alert Level Characteristic is not found");
}
}
public void writeImmediateAlertOn() {
if (mAlertLevelCharacteristic != null) {
DebugLogger.d(TAG, "writing Immediate alert characteristic On");
mAlertLevelCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
mAlertLevelCharacteristic.setValue(HIGH_ALERT, BluetoothGattCharacteristic.FORMAT_UINT8, 0);
mBluetoothGatt.writeCharacteristic(mAlertLevelCharacteristic);
} else {
DebugLogger.w(TAG, "Immediate Alert Level Characteristic is not found");
}
}
public void writeImmediateAlertOff() {
if (mAlertLevelCharacteristic != null) {
DebugLogger.d(TAG, "writing Immediate alert characteristic Off");
mAlertLevelCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
mAlertLevelCharacteristic.setValue(NO_ALERT, BluetoothGattCharacteristic.FORMAT_UINT8, 0);
mBluetoothGatt.writeCharacteristic(mAlertLevelCharacteristic);
} else {
DebugLogger.w(TAG, "Immediate Alert Level Characteristic is not found");
}
}
#Override
public void closeBluetoothGatt() {
try {
mContext.unregisterReceiver(mBondingBroadcastReceiver);
} catch (Exception e) {
// the receiver must have been not registered or unregistered before
}
if (mBluetoothGatt != null) {
mBluetoothGatt.close();
mBluetoothGatt = null;
}
if (mBluetoothGattServer != null) {
mBluetoothGattServer.close();
mBluetoothGattServer = null;
}
mCallbacks = null;
mLogSession = null;
mRingtoneAlarm = mRingtoneNotification = null;
}
}