Please anyone help me, I already tried many ways.
BluetoothGatt mBluetoothGatt
mBluetoothGatt.writeCharacteristic(mWriteCharacteristic)
return true
but readCharacteristic(BluetoothGattCharacteristic characteristic) return false.I could not find correct manuals for this,but tried many ways there was no clear sample for BEL android.`
package com.example.android.bluetoothlegatt;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.List;
import java.util.UUID;
import static com.example.android.bluetoothlegatt.DeviceControlActivity.hexArray;
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;
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);
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.");
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) {
Log.i(TAG,"onCharacteristicRead::"+status);
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
Log.i(TAG,"onCharacteristicChanged::"+characteristic);
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
#Override
public void onCharacteristicWrite(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
byte[] data = characteristic.getValue();
Log.i(TAG,"onCharacteristicWrite Response::"+bytesToHex(data));
}
};
public static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for ( int j = 0; j < bytes.length; j++ ) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
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);
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 {
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);
}
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);
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 void readCustomCharacteristic() {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
BluetoothGattService mCustomService = mBluetoothGatt.getService(UUID.fromString("0000bc01-0000-1000-8000-00805f9b34fb"));
if(mCustomService == null){
Log.w(TAG, "Custom BLE Service not found");
return;
}
BluetoothGattCharacteristic mReadCharacteristic = mCustomService.getCharacteristic(UUID.fromString("0000bd01-0000-1000-8000-00805f9b34fb"));
UUID uuid = UUID.fromString("00002901-0000-1000-8000-00805f9b34fb");
Log.i(TAG,"BluetoothGattCharacteristic Des::"+mReadCharacteristic.getDescriptor(uuid));
BluetoothGattDescriptor descriptor = mReadCharacteristic.getDescriptor(uuid);
Log.i(TAG,"BluetoothGattDescriptor is::"+descriptor.getUuid());
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
mBluetoothGatt.setCharacteristicNotification(mReadCharacteristic, true);
mReadCharacteristic = mCustomService.getCharacteristic(UUID.fromString("0000bd01-0000-1000-8000-00805f9b34fb"));
byte[] data = mReadCharacteristic.getValue();
Log.i(TAG,"onCharacteristicWrite Response::"+bytesToHex(data));
if(mBluetoothGatt.readCharacteristic(mReadCharacteristic) == false) {
Log.w(TAG, "Failed to read characteristic");
}
else{
Log.w(TAG, "Suucess to read characteristic");
mBluetoothGatt.notify();
}
}
public void writeCustomCharacteristic(byte value[]) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
BluetoothGattService mCustomService = mBluetoothGatt.getService(UUID.fromString("0000bc01-0000-1000-8000-00805f9b34fb"));
if(mCustomService == null){
Log.w(TAG, "Custom BLE Service not found");
return;
}
BluetoothGattCharacteristic mWriteCharacteristic = mCustomService.getCharacteristic(UUID.fromString("0000bd01-0000-1000-8000-00805f9b34fb"));
try {
byte [] message = new byte [6];
message[0] = (byte) 0x1B;
message[1] = (byte) 0x00;
message[2] = (byte) 0x02;
message[3] = (byte) 0x25;
message[4] = (byte) 0x27;
message[5] = (byte) 0x1b;
mWriteCharacteristic.setValue(message);
if(mBluetoothGatt.writeCharacteristic(mWriteCharacteristic)==true){
Log.w(TAG, "Write Char Success");
}
else{
Log.w(TAG, "Write Char Faile");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
`
After you call mBluetoothGatt.writeDescriptor(descriptor); you need to wait for the corresponding callback until you can execute the read command.
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 getting this error sometimes while trying to scan BLE in android studio, usually after a while of using my app but cerntainly not all the time.
I am using a class especially for BT connection, this is what's inside:
package com.omri.goniometer;
import android.app.Application;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.HandlerThread;
import android.util.Log;
import android.widget.Toast;
import android.os.Handler;
import java.util.List;
import java.util.UUID;
public class Bluetooth {
private final Context mContext;
private final MainActivity mActivity;
final String devcAddress = "D8:A0:1D:47:49:82";
// private static final UUID ServiceUUID = UUID.fromString("0000183B-0000-1000-8000-00805F9B34FB");
// private static final UUID CharUUID = UUID.fromString("00002A08-0000-1000-8000-00805F9B34FB");
private static final UUID ServiceUUID = UUID.fromString("da3a95de-467b-11ea-b77f-2e728ce88125");
private static final UUID CharUUID = UUID.fromString("da3a9836-467b-11ea-b77f-2e728ce88125");
private String scanDevcAddress = null;
private BluetoothAdapter mBTAdapter;
private boolean mScanning;
private static final long SCAN_PERIOD = 5000;
private BluetoothLeScanner mBluetoothLeScanner;
private BluetoothDevice BTdevice;
private BluetoothGatt mBTGatt;
private BluetoothGattCharacteristic mGattChar;
private int mConnectionState = STATE_DISCONNECTED;
private Short rollInt = 0;
private Short pitchInt = 0;
String rollString = "0";
String pitchString = "0";
private static final int STATE_DISCONNECTED = 0;
private static final int STATE_CONNECTING = 1;
private static final int STATE_CONNECTED = 2;
private static final int WAVE = 3;
private static final int BATTERY_UPDATE = 4;
String[] stringArray;
Handler mHandler;
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";
Bluetooth(Context context, MainActivity activity) {
this.mContext = context;
this.mActivity = activity;
mHandler = new Handler();
disconnect();
close();
// Initializes Bluetooth adapter.
final BluetoothManager bluetoothManager =
(BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
mBTAdapter = bluetoothManager.getAdapter();
mBluetoothLeScanner = mBTAdapter.getBluetoothLeScanner();
if (mBTAdapter == null) {
// Device does not support Bluetooth
Toast.makeText(mContext, "Bluetooth device not found!", Toast.LENGTH_SHORT).show();
} else {
if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(mContext, "no BLE feature in phone", Toast.LENGTH_SHORT).show();
}
searchDevice();
//connect();
}
}
public void searchDevice() {
if (mBTAdapter.isEnabled()) {
Log.d("ADebugTag", "After check if BTAdapter is enabled");
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
scanLeDevice(true);
}
}, 5000);
} else {
Toast.makeText(mContext, "To begin please turn on bluetooth", Toast.LENGTH_SHORT).show();
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
mActivity.startActivityForResult(enableBtIntent, MainActivity.REQUEST_ENABLE_BT);
}
}
private void scanLeDevice(final boolean enable) {
if (enable) {
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
mScanning = false;
mBluetoothLeScanner.stopScan(leScanCallback);
}
}, SCAN_PERIOD);
mScanning = true;
Log.d("ADebugTag", "Just before scan");
mBluetoothLeScanner.startScan(leScanCallback);
} else {
mScanning = false;
mBluetoothLeScanner.stopScan(leScanCallback);
}
}
// Device scan callback.
private ScanCallback leScanCallback = new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
Log.d("ADebugTag", "Inside scan callback scan");
BTdevice = result.getDevice();
scanDevcAddress = result.getDevice().getAddress();
Log.d("ADebugTag", "scanned address: " + scanDevcAddress);
if (scanDevcAddress.equals(devcAddress)) {
mActivity.updatesStatus(MainActivity.DEVICE_FOUND,"","");
//Intent deviceFoundIntent = new Intent(mActivity,MainActivity.class);
scanLeDevice(false);
//Toast.makeText(mContext, "Scanning stopped", Toast.LENGTH_SHORT).show();
}
}
};
public boolean connect() {
mActivity.updatesStatus(MainActivity.STATE_CONNECTING,"","");
BTdevice = mBTAdapter.getRemoteDevice(devcAddress);
mBTGatt = BTdevice.connectGatt(mContext, false, mGattCallback);
if (mBTGatt == null){
Log.d("ADebugTag", "mBTGatt is null");
return false;
}
else {
try {
mGattChar = mBTGatt.getService(ServiceUUID).getCharacteristic(CharUUID);
}
catch (NullPointerException e){
Log.d("ADebugTag", "mGattChar is null\n" + e);
}
//setCharacteristicNotification(mGattChar, true);
return true;
}
}
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);
mActivity.updatesStatus(MainActivity.STATE_CONNECTED,"","");
Log.d("ADebugTag", "Connected to GATT server.");
// Attempts to discover services after successful connection.
Log.d("ADebugTag", "Attempting to start service discovery:" + mBTGatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
mConnectionState = STATE_DISCONNECTED;
mActivity.updatesStatus(MainActivity.STATE_DISCONNECTED,"","");
Log.d("ADebugTag", "Disconnected from GATT server.");
broadcastUpdate(intentAction);
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
if (mBTGatt ==null){
return;
}
else {
List<BluetoothGattService> services = getSupportedGattServices();
for (BluetoothGattService service : services) {
if (!service.getUuid().equals(ServiceUUID))
continue;
List<BluetoothGattCharacteristic> gattCharacteristics =
service.getCharacteristics();
// Loops through available Characteristics.
for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
if (!gattCharacteristic.getUuid().equals(CharUUID))
continue;
final int charaProp = gattCharacteristic.getProperties();
if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
setCharacteristicNotification(gattCharacteristic, true);
} else {
Log.d("ADebugTag", "Characteristic does not support notify");
}
}
}
}
} else {
Log.d("ADebugTag", "onServicesDiscovered received:" + status);
}
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
final byte[] dataInput = characteristic.getValue();
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
final byte[] dataInput = characteristic.getValue();
//Log.d("ADebugTag", "Data on changed: " + dataInput);
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
};
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
mContext.sendBroadcast(intent);
}
private void broadcastUpdate(final String action,
final BluetoothGattCharacteristic characteristic) {
final Intent intent = new Intent(action);
// For all other profiles, writes the data formatted in HEX.
if (characteristic == null) {
Log.d("ADebugTag", "characteristic is null in broadcastUpdate");
}
else {
final byte[] data = characteristic.getValue();
//Log.d("ADebugTag", "Data broadcast update: " + data);
if (data != null && data.length > 0) {
final StringBuilder stringBuilder = new StringBuilder(data.length);
for (byte byteChar : data)
stringBuilder.append(String.format("%X ", byteChar));
//stringBuilder.append(String.format("%d ", byteChar));
String ds = stringBuilder.toString();
intent.putExtra(EXTRA_DATA, new String(data) + "\n" + ds);
Log.d("ADebugTag", "Data complete string: " + ds);
stringArray = ds.split(" ");
rollInt = (short) Integer.parseInt(stringArray[3]+stringArray[2],16);
pitchInt = (short) Integer.parseInt(stringArray[1]+stringArray[0],16);
Log.d("ADebugTag", "Roll received:" + rollInt);
Log.d("ADebugTag", "Pitch received:" + pitchInt);
rollString = rollInt.toString();
pitchString = pitchInt.toString();
mActivity.updatesStatus(MainActivity.DATA_RECEIVED,rollString,pitchString);
//deciBattery = Integer.parseInt(bateryStringArray[0],16);
//updatesStatus(BATTERY_UPDATE);
}
mContext.sendBroadcast(intent);
}
}
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
boolean enabled) {
if (mBTAdapter == null || mBTGatt == null) {
Log.d("ADebugTag", "BluetoothAdapter not initialized in set char");
return;
}
else {
//mGattChar = mBTGatt.getService()
mBTGatt.setCharacteristicNotification(characteristic, enabled);
// BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CharUUID);
// descriptor.setValue(descriptor.ENABLE_NOTIFICATION_VALUE);
// mBTGatt.writeDescriptor(descriptor);
}
}
/**
* Disconnects an existing connection or cancel a pending connection. The disconnection result
* is reported asynchronously through the
* {#code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
* callback.
*/
public void disconnect() {
if (mBTAdapter == null || mBTGatt == null) {
Log.d("ADebugTag", "BluetoothAdapter not initialized");
return;
}
mBTGatt.disconnect();
}
public List<BluetoothGattService> getSupportedGattServices() {
if (mBTGatt == null) return null;
return mBTGatt.getServices();
}
/**
* After using a given BLE device, the app must call this method to ensure resources are
* released properly.
*/
public void close() {
if (mBTGatt == null) {
return;
}
mBTGatt.close();
mBTGatt = null;
}
}
Why is it not scanning? found a place that says you have to wait 5 seconds between D/BluetoothAdapter: STATE_ON and start scan but couldn't catch it and don't know if it's the issue at all.
Thanks.
I want to get every value of the array messageBytes in onCharacteristicChanged method but the logcat message is a bit messy. I have made my values in bold style. Any solution to get every single array value? Thanks.
05-05 17:57:15.763 14107-14119/com.example.android.bluetoothlegatt E/BluetoothLeService: Puck:[J[ 18, 30, 2.86,
05-05 17:57:15.800 14107-14119/com.example.android.bluetoothlegatt I/BluetoothLeService: onCharacteristicChanged
05-05 17:57:15.800 14107-14119/com.example.android.bluetoothlegatt E/BluetoothLeService: Puck:
"normal"
]
package com.example.android.bluetoothlegatt;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.List;
/**
* Service for managing connection and data communication with a GATT server hosted on a
* given Bluetooth LE device.
*/
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;
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";
// Implements callback methods for GATT events that the app cares about. For example,
// connection change and services discovered.
private final BluetoothGattCallback mGattCallback;
{
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);
setPuckCharacteristicNotification();
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.i(TAG, "onCharacteristicRead");
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
Log.i(TAG, "onCharacteristicChanged");
byte[] messageBytes = characteristic.getValue();
String messageString = null;
try {
messageString = new String(messageBytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
Log.e(TAG, "Unable to convert message bytes to string");
}
Log.e(TAG, "Puck:" + messageString);
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
Log.i(TAG, "onCharacteristicWrite");
}
#Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
Log.i(TAG, "onDescriptorWrite");
BluetoothGattService service = gatt.getService(G.PUCK_SERVICE_UUID);
if (service != null) {
BluetoothGattCharacteristic characteristic =
service.getCharacteristic(G.PUCK_TX_UUID);
if (characteristic != null) {
Log.i(TAG, "Writing to characteristic " + characteristic.getUuid());
//String msg = "E.getTemperature()\n";
//byte[] data = msg.getBytes();
//characteristic.setValue(data);
if (gatt.writeCharacteristic(characteristic)) {
Log.i(TAG, "writeCharacteristic OK");
} else {
Log.i(TAG, "writeCharacteristic FAIL");
}
}
}
}
};
}
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 (G.PUCK_RX_UUID.equals(characteristic.getUuid())) {
int flag = characteristic.getProperties();
int format = -1;
/*if ((flag & 0x01) != 0) {
format = BluetoothGattCharacteristic.FORMAT_UINT16;
Log.i(TAG, "Heart rate format UINT16.");
} else {
format = BluetoothGattCharacteristic.FORMAT_UINT8;
Log.i(TAG, "Heart rate format UINT8.");
}*/
//final int heartRate = characteristic.getIntValue(format, 1);
//Log.i(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();
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);
}
public class LocalBinder extends Binder {
BluetoothLeService getService() {
return BluetoothLeService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public boolean onUnbind(Intent intent) {
// After using a given device, you should make sure that BluetoothGatt.close() is called
// such that resources are cleaned up properly. In this particular example, close() is
// invoked when the UI is disconnected from the Service.
close();
return super.onUnbind(intent);
}
private final IBinder mBinder = new LocalBinder();
/**
* Initializes a reference to the local Bluetooth adapter.
*
* #return Return true if the initialization is successful.
*/
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;
}
/**
* Connects to the GATT server hosted on the Bluetooth LE device.
*
* #param address The device address of the destination device.
* #return Return true if the connection is initiated successfully. The connection result
* is reported asynchronously through the
* {#code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
* callback.
*/
public boolean connect(final String address) {
if (mBluetoothAdapter == null || address == null) {
Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
return false;
}
// Previously connected device. Try to reconnect.
if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress)
&& mBluetoothGatt != null) {
Log.i(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;
}
// We want to directly connect to the device, so we are setting the autoConnect
// parameter to false.
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
Log.i(TAG, "Trying to create a new connection.");
mBluetoothDeviceAddress = address;
mConnectionState = STATE_CONNECTING;
return true;
}
/**
* Disconnects an existing connection or cancel a pending connection. The disconnection result
* is reported asynchronously through the
* {#code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
* callback.
*/
public void disconnect() {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.disconnect();
}
/**
* After using a given BLE device, the app must call this method to ensure resources are
* released properly.
*/
public void close() {
if (mBluetoothGatt == null) {
return;
}
mBluetoothGatt.close();
mBluetoothGatt = null;
}
/**
* Request a read on a given {#code BluetoothGattCharacteristic}. The read result is reported
* asynchronously through the {#code BluetoothGattCallback#onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int)}
* callback.
*
* #param characteristic The characteristic to read from.
*/
public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.readCharacteristic(characteristic);
}
/**
* Enables notification on a given characteristic.
**/
public void setPuckCharacteristicNotification() {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
//Start getting data
BluetoothGattService gattService = mBluetoothGatt.getService(G.PUCK_SERVICE_UUID);
if (gattService != null) {
BluetoothGattCharacteristic gattCharacteristic = gattService.getCharacteristic(G.PUCK_RX_UUID);
if (gattCharacteristic != null) {
Log.i(TAG, "Setting Characteristic " + gattCharacteristic.getUuid());
mBluetoothGatt.setCharacteristicNotification(gattCharacteristic, true);
BluetoothGattDescriptor clientDescriptor = gattCharacteristic.getDescriptor(G.CLIENT_CHARACTERISTIC_CONFIG);
clientDescriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(clientDescriptor);
}
}
}
/**
* Retrieves a list of supported GATT services on the connected device. This should be
* invoked only after {#code BluetoothGatt#discoverServices()} completes successfully.
*
* #return A {#code List} of supported services.
*/
public List<BluetoothGattService> getSupportedGattServices() {
if (mBluetoothGatt == null) return null;
return mBluetoothGatt.getServices();
}
public int getElement(byte[] arrayOfBytes, int index) {
return arrayOfBytes[index];
}
}
I've followed the guide listed at https://developer.android.com/samples/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/DeviceScanActivity.html
I can't figure out how to trigger a notify when the characteristic value changes. The method onCharacteristicChanged is never called but I know for a fact the value changes every 2 seconds. I am getting around this fact by calling readCharacteristic when I discover the service and then repeatedly afterwards. I don't believe this is the correct way rather I should only read when the onCharacteristicChanged method sends a broadcast. Is it possible to get notify to work or is this the best method?
Device Controller:
public class WarningActivity extends AppCompatActivity {
private static final String TAG = "WarningActivity Class";
private BluetoothLeService mBluetoothLeService;
public static WarningActivity wInstance;
private boolean mConnected = false;
private String mDeviceAddress;
private boolean quitService;
private TextView connectStatus;
private Button connectButton;
private Button cameraButton;
private BluetoothManager mBluetoothManager;
private Vibrator vib;
private Uri notification;
private Ringtone ring;
private final ServiceConnection mServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService();
if (!mBluetoothLeService.initialize()) {
Log.e(TAG, "Unable to initialize Bluetooth");
finish();
}
mBluetoothLeService.connect(mDeviceAddress);
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
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;
} else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
mConnected = false;
} else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
Log.i("Data: ", mBluetoothLeService.getSupportedGattService().toString());
BluetoothGattService mService = mBluetoothLeService.getSupportedGattService();
BluetoothGattCharacteristic characteristic = mService.getCharacteristic(mBluetoothLeService.ALERT_UUID);
mBluetoothLeService.setCharacteristicNotification(characteristic, true);
mBluetoothLeService.readCharacteristic(characteristic);
} else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
BluetoothGattService mService = mBluetoothLeService.getSupportedGattService();
BluetoothGattCharacteristic characteristic = mService.getCharacteristic(mBluetoothLeService.ALERT_UUID);
byte[] temp = intent.getByteArrayExtra(BluetoothLeService.EXTRA_DATA);
String tempString = Arrays.toString(temp);
Log.i("Data: ", Arrays.toString(temp));
mBluetoothLeService.readCharacteristic(characteristic);
}
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ColorDrawable colorDrawable = new ColorDrawable(Color.parseColor("#268011"));
getSupportActionBar().setBackgroundDrawable(colorDrawable);
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);
connectButton = (Button) findViewById(R.id.connectButton);
connectButton.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.connected_logo, 0, 0);
connectButton.setClickable(false);
Intent gattServiceIntent = new Intent(this, BluetoothLeService.class);
bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
Intent intent = getIntent();
mDeviceAddress = intent.getStringExtra("EXTRA_DEVICE_ADDRESS");
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
vib = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
ring = RingtoneManager.getRingtone(getApplicationContext(), notification);
wInstance = this;
quitService = false;
connectStatus = (TextView) findViewById(R.id.connectMessage);
connectStatus.setText("Connected to: \n " + mDeviceAddress);
}
#Override
protected void onResume() {
super.onResume();
registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
if (mBluetoothLeService != null) {
final boolean result = mBluetoothLeService.connect(mDeviceAddress);
Log.d(TAG, "Connect request result=" + result);
}
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(mGattUpdateReceiver);
}
#Override
protected void onDestroy() {
super.onDestroy();
unbindService(mServiceConnection);
mBluetoothLeService = null;
}
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;
}
}
BluetoothLeService
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;
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 = "ACTION_GATT_CONNECTED";
public final static String ACTION_GATT_DISCONNECTED = "ACTION_GATT_DISCONNECTED";
public final static String ACTION_GATT_SERVICES_DISCOVERED = "ACTION_GATT_SERVICES_DISCOVERED";
public final static String ACTION_DATA_AVAILABLE = "ACTION_DATA_AVAILABLE";
public final static String EXTRA_DATA = "EXTRA_DATA";
public final static UUID SERVICE_UUID = UUID.fromString(GattAttributes.BLE_SERVICE);
public final static UUID ALERT_UUID = UUID.fromString(GattAttributes.BLE_ALERT_CHARACTERISTIC);
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.");
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) {
Log.i("BlueToothService: ", "onCharacteristicRead " + characteristic.toString());
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
Log.i("BlueToothService: ", "onCharacteristicChanged " + characteristic.toString());
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
};
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
Log.i("BlueToothService: ", "BroadcastUpdate ActionOnly: " + action);
sendBroadcast(intent);
}
private void broadcastUpdate(final String action, final BluetoothGattCharacteristic characteristic) {
final Intent intent = new Intent(action);
Log.i("BlueToothService: ", "BroadcastUpdateLong " + characteristic.toString() + " Action:" + action);
intent.putExtra(EXTRA_DATA, characteristic.getValue());
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
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);
if (SERVICE_UUID.equals(characteristic.getUuid())) {
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(ALERT_UUID);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
}
}
public BluetoothGattService getSupportedGattService() {
if (mBluetoothGatt == null) return null;
return mBluetoothGatt.getService(SERVICE_UUID);
}
}
Solution Found: Classic Case of mistyping and wrong descriptor UUID. Where I found the answer BLE GATT onCharacteristicChanged not called after subscribing to notification. The mistype was in setCharacteristicNotification method. Changed to ALERT_UUID and to what article has me assuming the correct descriptor UUID
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
if (ALERT_UUID.equals(characteristic.getUuid())) {
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
}
}
I'm attempting to receive data from my Texas sensor tag, but so far I just managed to connect and write characteristics to it.
this is my setCharacteristicNotification();
the part commented below does not work and I didn't managed to use it.
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
boolean enabled) {
if(bluetoothAdapter == null || bluetoothGatt == null) return;
bluetoothGatt.setCharacteristicNotification(characteristic, enabled);
if(GattUUIDs.containsUuid(characteristic.getUuid())) {
// BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
// UUID.fromString(GattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(
GattUUIDs.UUID_CLIENT_CHAR_CONFIG, BluetoothGattDescriptor.PERMISSION_WRITE |
BluetoothGattDescriptor.PERMISSION_READ);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
bluetoothGatt.writeDescriptor(descriptor);
}
}
When I try to call the commented block, this is what I receive:
java.lang.NullPointerException: Attempt to invoke virtual method
'boolean android.bluetooth.BluetoothGattDescriptor.setValue(byte[])'
on a null object reference
This is my Client Characteristic Configuration UUID:
public static final UUID UUID_CLIENT_CHAR_CONFIG =
UUID.fromString(GattAttributes.CLIENT_CHARACTERISTIC_CONFIG);
public static String CLIENT_CHARACTERISTIC_CONFIG = "f0002902-0451-4000-b000-000000000000";
I think that it has some sort of problem in my descriptor because I can register it but I never got a callback from it.
If it helps, this is my Service:
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import java.util.List;
import java.util.UUID;
/**
* Created by alan on 2/23/16.
*/
public class DeviceService extends Service {
private final static String TAG = DeviceService.class.getSimpleName();
private BluetoothGatt bluetoothGatt;
private String deviceAddress;
private BluetoothManager bluetoothManager;
private BluetoothAdapter bluetoothAdapter;
private int connectionState = STATE_DISCONNECTED;
public final IBinder binder = new LocalBinder();
public static final int STATE_DISCONNECTED = 0;
public static final int STATE_CONNECTING = 1;
public static final int STATE_CONNECTED = 2;
public static final String ACTION_GATT_SERVICES_DISCOVERED = "action_gatt_services_discovered";
public static final String ACTION_GATT_DISCONNECTED = "action_gatt_disconnected";
public static final String ACTION_GATT_CONNECTED = "action_gatt_connected";
public static final String ACTION_DATA_AVAILABLE = "action_data_available";
public static final String ACTION_DATA_NOTIFY = "action_data_notify";
public static final String ACTION_DATA_WRITE = "action_data_write";
public static final String ACTION_DATA_READ = "action_data_read";
public static final String EXTRA_DATA = "extra_data";
#Override
public IBinder onBind(Intent intent) {
return binder;
}
#Override
public boolean onUnbind(Intent intent) {
close();
return super.onUnbind(intent);
}
public boolean initialize() {
if(bluetoothManager == null) {
bluetoothManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
if(bluetoothManager == null) {
Log.e(TAG,"CANNOT INITIALIZE BLUETOOTH");
return false;
}
}bluetoothAdapter = bluetoothManager.getAdapter();
if(bluetoothAdapter == null) {
Log.e(TAG,"CANNOT FIND AN ADAPTER");
return false;
}return true;
}
public boolean connect(final String address) {
Log.w(TAG,"CONNECT PROCESS INITIALIZED");
if(bluetoothAdapter == null || address == null) {
Log.e(TAG,"ADAPTER NOT INITIALIZED");
return false;
}
//previously connected device, attempt to reconnect
if(deviceAddress != null && deviceAddress.equals(address)
&&bluetoothGatt != null) {
Log.d(TAG, "TRYING TO USE EXISTING GATT");
if(bluetoothGatt.connect()) {
connectionState = STATE_CONNECTING;
bluetoothGatt.connect();
return true;
} else
return false;
}
final BluetoothDevice device = bluetoothAdapter.getRemoteDevice(address);
if(device == null) {
Log.e(TAG, "DEVICE NOT FOUND");
return false;
}
bluetoothGatt = device.connectGatt(this, false, gattCallback);
deviceAddress = address;
connectionState = STATE_CONNECTING;
return true;
}
public void disconnect() {
if(bluetoothAdapter == null || bluetoothGatt == null) {
Log.w(TAG, "BLUETOOTH NOT INITIALIZED");
return;
}
bluetoothGatt.disconnect();
}
public void close() {
if(bluetoothGatt == null)
return;
bluetoothGatt.close();
bluetoothGatt = null;
}
public class LocalBinder extends Binder {
DeviceService getService() {
return DeviceService.this;
}
}
private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
String intentAction;
if(newState == BluetoothProfile.STATE_CONNECTED) {
intentAction = ACTION_GATT_CONNECTED;
connectionState = STATE_CONNECTED;
broadcastUpdate(intentAction);
Log.i(TAG,"CONNECTED TO GATT SERVER!");
bluetoothGatt.discoverServices();
} else if(newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_GATT_DISCONNECTED;
connectionState = STATE_DISCONNECTED;
Log.i(TAG,"DISCONNECTED FROM GATT SERVER");
broadcastUpdate(intentAction);
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
Log.e(TAG,"STATUS: " + String.valueOf(status));
if (status == BluetoothGatt.GATT_SUCCESS)
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
}
#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) {
Log.e(TAG,"CHAR CHANGED \n" + gatt.toString() + "\n" + characteristic.getUuid().toString() + "\n");
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
#Override
public void onCharacteristicWrite(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
Log.e(TAG,"CHAR WROTE" + gatt.toString() + "\n" + characteristic.getUuid().toString() + "\n");
if(status == BluetoothGatt.GATT_SUCCESS)
broadcastUpdate(ACTION_DATA_WRITE, characteristic);
}
};
public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
if(bluetoothAdapter == null || bluetoothGatt == null) {
Log.e(TAG, "ADAPTER NOT INITIALIZED");
return;
}
bluetoothGatt.readCharacteristic(characteristic);
}
public void writeCharacteristic(BluetoothGattCharacteristic characteristic, byte[] value) {
if(bluetoothAdapter == null || bluetoothGatt == null) {
Log.e(TAG, "ADAPTER NOT INITIALIZED");
return;
}
characteristic.setValue(value);
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
bluetoothGatt.writeCharacteristic(characteristic);
System.out.println("Write value: " + value[0] + " on UUID: " + characteristic.getUuid().toString());
}
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
boolean enabled) {
if(bluetoothAdapter == null || bluetoothGatt == null) return;
bluetoothGatt.setCharacteristicNotification(characteristic, enabled);
if(GattUUIDs.containsUuid(characteristic.getUuid())) {
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
UUID.fromString(GattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
// BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(
// GattUUIDs.UUID_CLIENT_CHAR_CONFIG, BluetoothGattDescriptor.PERMISSION_WRITE |
// BluetoothGattDescriptor.PERMISSION_READ);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
bluetoothGatt.writeDescriptor(descriptor);
}
}
public void setCharacteristicIndication(BluetoothGattCharacteristic characteristic,
boolean enabled) {
if(bluetoothAdapter ==null || bluetoothGatt == null) return;
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
UUID.fromString(GattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
bluetoothGatt.writeDescriptor(descriptor);
bluetoothGatt.setCharacteristicNotification(characteristic, enabled);
}
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);
final UUID uuid = characteristic.getUuid();
Log.w(TAG,"BROADCAST UPDATE WITH ACTION: " + action);
if(GattUUIDs.containsUuid(uuid)) {
Log.e(TAG,"PASSOU AQUI");
int flag = characteristic.getProperties();
int format;
if((flag & 0x01) != 0)
format = BluetoothGattCharacteristic.FORMAT_UINT16;
else
format = BluetoothGattCharacteristic.FORMAT_UINT8;
byte[] data = characteristic.getValue();
if (GattUUIDs.UUID_IR_TEMPERATURE_MEASUREMENT.equals(uuid)) {
float objectTemperature = ((((float)data[1] * 256 + (float)data[0]) / (float)4)) * (float)0.03125;
float ambientTemperature = ((((float)data[3] * 256 + (float)data[2]) / (float)4)) * (float)0.03125;
// final int temp_data = characteristic.getIntValue(format, 1);
intent.putExtra(EXTRA_DATA, String.format("%.2f %.2f", objectTemperature, ambientTemperature));
} else if (GattUUIDs.UUID_IR_TEMPERATURE_CONFIG.equals(uuid)) {
if (data[0] == 0)
intent.putExtra(EXTRA_DATA, "IR DISABLED");
else
intent.putExtra(EXTRA_DATA, "IR ENABLED");
} else if (GattUUIDs.UUID_IR_TEMPERATURE_PERIOD.equals(uuid))
intent.putExtra(EXTRA_DATA, String.format("%d",data[0]*10));
else if (GattUUIDs.UUID_OPTICAL_MEASUREMENT.equals(uuid)) {
int m = (data[1] * 256 + data[0]) & 0x0FFF;
int e = ((data[1] * 256 + data[0]) & 0xF000) >> 12;
double lux = m * 0.01 * Math.pow(2.0,e);
intent.putExtra(EXTRA_DATA, String.format("%.2f",lux));
} else if (GattUUIDs.UUID_OPTICAL_CONFIG.equals(uuid)) {
if(data[0] == 0)
intent.putExtra(EXTRA_DATA, "OPTICAL DISABLED");
else
intent.putExtra(EXTRA_DATA, "OPTICAL ENABLED");
} else if (GattUUIDs.UUID_OPTICAL_PERIOD.equals(uuid))
intent.putExtra(EXTRA_DATA, String.format("%d",data[0] * 10));
else if (GattUUIDs.UUID_MOVEMENT_MEASUREMENT.equals(uuid))
intent.putExtra(EXTRA_DATA, String.format("%d %d %d %d %d %d %d %d %d",
(data[0] + data[1]*256),
(data[2] + data[3]*256),
(data[4] + data[5]*256),
(data[6] + data[7]*256),
(data[8] + data[9]*256),
(data[10] + data[11]*256),
(data[12] + data[13]*256),
(data[14] + data[15]*256),
(data[16] + data[17]*256)));
else if (GattUUIDs.UUID_MOVEMENT_CONFIG.equals(uuid)) {
if (data[0] == 0)
intent.putExtra(EXTRA_DATA, "MOVEMENT DISABLED");
else
intent.putExtra(EXTRA_DATA, "MOVEMENT ENABLEd");
} else if (GattUUIDs.UUID_MOVEMENT_PERIOD.equals(uuid))
intent.putExtra(EXTRA_DATA, String.format("%d",data[0] * 10));
else {
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);
}
public List<BluetoothGattService> getSupportedGattServices() {
if(bluetoothGatt == null) return null;
return bluetoothGatt.getServices();
}
}
and this is my device control:
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.CompoundButton;
import android.widget.Switch;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
/**
* Created by alan on 2/23/16.
*/
public class DeviceControl extends AppCompatActivity {
private final String TAG = DeviceControl.class.getSimpleName();
private ArrayList<ArrayList<BluetoothGattCharacteristic>> mGattCharacterics = new ArrayList<>();
private BluetoothGattCharacteristic bluetoothGattCharacteristic;
public static String ADDRESS;
private DeviceService deviceService;
private boolean connected = false;
private TextView dataText;
private Switch temperatureSwitch,
movementSwitch,
opticalSwitch;
private final String LIST_NAME = "NAME";
private final String LIST_UUID = "UUID";
private final ServiceConnection serviceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e(TAG,"ONSERVICECONNECTED");
deviceService = ((DeviceService.LocalBinder)service).getService();
if(!deviceService.initialize())
finish();
deviceService.connect(ADDRESS);
}
#Override
public void onServiceDisconnected(ComponentName name) {
deviceService = null;
}
};
#Override
public void onCreate(Bundle savedInstanceBundle) {
super.onCreate(savedInstanceBundle);
setContentView(R.layout.activity_device_control);
dataText = (TextView)findViewById(R.id.dataText);
temperatureSwitch = (Switch)findViewById(R.id.temperatureSwitch);
movementSwitch = (Switch)findViewById(R.id.movementSwitch);
opticalSwitch = (Switch)findViewById(R.id.opticalSwitch);
temperatureSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked && connected)
writeCharacteristic(GattUUIDs.UUID_IR_TEMPERATURE_CONFIG, true);
else if(!isChecked && connected)
writeCharacteristic(GattUUIDs.UUID_IR_TEMPERATURE_CONFIG, false);
}
});
Bundle extras = getIntent().getExtras();
if(extras != null) {
setTitle(extras.getString("title"));
ADDRESS = extras.getString("address");
Intent intent = new Intent(this, DeviceService.class);
bindService(intent, serviceConnection, BIND_AUTO_CREATE);
}
registerReceiver(broadcastReceiver, makeIntentFilter());
}
public void writeCharacteristic(UUID toFind, boolean read) {
BluetoothGattCharacteristic gattCharacteristic = null;
byte[] enable = {(byte)0x01},
disable = {(byte)0x00};
for(int i = 0; i < mGattCharacterics.size(); i++) {
for(int j = 0; j < mGattCharacterics.get(i).size(); j++) {
if(mGattCharacterics.get(i).get(j).getUuid().equals(toFind))
gattCharacteristic = mGattCharacterics.get(i).get(j);
}
}
if(gattCharacteristic != null) {
if(read)
deviceService.writeCharacteristic(gattCharacteristic, enable);
else
deviceService.writeCharacteristic(gattCharacteristic, disable);
deviceService.setCharacteristicNotification(gattCharacteristic, true);
} else
Log.e(TAG,"NOTHING FOUND");
}
#Override
protected void onResume() {
super.onResume();
registerReceiver(broadcastReceiver, makeIntentFilter());
Log.w(TAG,"REGISTER RECEIVER");
if (deviceService != null) {
final boolean result = deviceService.connect(ADDRESS);
Log.d(TAG,"CONNECT RESULT = " + result);
}
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(broadcastReceiver);
}
#Override
public void onBackPressed() {
super.onBackPressed();
deviceService.disconnect();
}
#Override
protected void onDestroy() {
super.onDestroy();
unbindService(serviceConnection);
deviceService = null;
}
private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
Log.e(TAG,"BROADCAST ACTION"+action);
switch (action) {
case DeviceService.ACTION_GATT_CONNECTED:
connected = true;
break;
case DeviceService.ACTION_GATT_DISCONNECTED:
connected = false;
break;
case DeviceService.ACTION_GATT_SERVICES_DISCOVERED:
getGattServices(deviceService.getSupportedGattServices());
break;
case DeviceService.ACTION_DATA_AVAILABLE:
displayData(intent.getStringExtra(DeviceService.EXTRA_DATA));
}
}
};
private void displayData(String data) {
if(data != null)
dataText.setText(data);
}
private void getGattServices(List<BluetoothGattService> gattServices) {
if(gattServices == null) return;
String uuid = null;
ArrayList<HashMap<String, String>> gattServiceData = new ArrayList<>();
ArrayList<ArrayList<HashMap<String, String>>> gattCharacteristicData
= new ArrayList<>();
mGattCharacterics = new ArrayList<>();
for (BluetoothGattService gattService : gattServices) {
HashMap<String, String> currentServiceData = new HashMap<>();
uuid = gattService.getUuid().toString();
currentServiceData.put(LIST_NAME, GattAttributes.lookup(uuid, "UnknownService"));
currentServiceData.put(LIST_UUID, uuid);
gattServiceData.add(currentServiceData);
ArrayList<HashMap<String, String>> gattCharacteristicGroupData = new ArrayList<>();
List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
ArrayList<BluetoothGattCharacteristic> charas = new ArrayList<>();
for(BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
charas.add(gattCharacteristic);
HashMap<String, String> currentCharaData = new HashMap<>();
uuid = gattCharacteristic.getUuid().toString();
currentCharaData.put(LIST_NAME, GattAttributes.lookup(uuid, "UnknownCharacteristic"));
currentCharaData.put(LIST_UUID, uuid);
gattCharacteristicGroupData.add(currentCharaData);
//System.out.println("GATTCHAR\n\n" + gattCharacteristic.toString()+"\n");
}
mGattCharacterics.add(charas);
gattCharacteristicData.add(gattCharacteristicGroupData);
}
}
private static IntentFilter makeIntentFilter() {
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(DeviceService.ACTION_GATT_CONNECTED);
intentFilter.addAction(DeviceService.ACTION_GATT_DISCONNECTED);
intentFilter.addAction(DeviceService.ACTION_GATT_SERVICES_DISCOVERED);
intentFilter.addAction(DeviceService.ACTION_DATA_AVAILABLE);
return intentFilter;
}
}
Thanks for your attention.