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.
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 have developed an android application to scan ble devices and have done reading and writing the gatt characteristic when the app is in User Interaction. I want to keep the connection to perticular ble device and want to read-write gatt charecteristic when the app is in foreground and background.Here is my BluetoothLeService class.
public class BluetoothLeService extends Service
{
public static final String ACTION_DATA_AVAILABLE = "com.example.tracker.service.ACTION_DATA_AVAILABLE";
public static final String ACTION_GATT_CONNECTED = "com.example.tracker.service.ACTION_GATT_CONNECTED";
public static final String ACTION_GATT_DISCONNECTED = "com.example.tracker.service.ACTION_GATT_DISCONNECTED";
public static final String ACTION_GATT_RSSI_UPDATE = "com.example.tracker.service.ACTION_GATT_RSSI_UPDATE";
public static final String ACTION_GATT_SERVICES_DISCOVERED = "com.example.tracker.service.ACTION_GATT_SERVICES_DISCOVERED";
public static final String ACTION_GATT_WRITE_FAILED = "com.example.tracker.service.ACTION_GATT_WRITE_FAILED";
protected static final UUID CHARACTERISTIC_UPDATE_NOTIFICATION_DESCRIPTOR_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
public static final String CHARACTERISTIC_UUID = "com.example.tracker.service.CHARACTERISTIC_UUID";
public static final String EXTRA_DATA = "com.example.tracker.service.EXTRA_DATA";
public static final String SIGNAL = "SIGNAL";
private static final String TAG = BluetoothLeService.class.getSimpleName();
private final IBinder mBinder = new LocalBinder();
private BluetoothAdapter mBluetoothAdapter;
private String mBluetoothDeviceAddress;
private BluetoothGatt mBluetoothGatt;
private BluetoothManager mBluetoothManager;
private BluetoothGattCharacteristic mFocusedCharacteristic;
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == 2) {
BluetoothLeService.this.broadcastUpdate(BluetoothLeService.ACTION_GATT_CONNECTED);
Log.i(BluetoothLeService.TAG, "Connected to GATT server.");
Log.i("MyActivity", "Connected to GATT server.");
Log.i("MyActivity", "Attempting to start service discovery:" + BluetoothLeService.this.mBluetoothGatt.discoverServices());
} else if (newState == 0) {
String intentAction = BluetoothLeService.ACTION_GATT_DISCONNECTED;
Log.i("MyActivity", "Disconnected from GATT server.");
BluetoothLeService.this.broadcastUpdate(intentAction);
}
}
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == 0) {
BluetoothLeService.this.broadcastUpdate(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED);
} else {
Log.w("MyActivity", "onServicesDiscovered received: " + status);
}
}
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (status == 0) {
BluetoothLeService.this.broadcastUpdate(BluetoothLeService.ACTION_DATA_AVAILABLE, characteristic);
Log.i("MyActivity", "Characteristic flags " + characteristic.getProperties());
BluetoothLeService.this.mFocusedCharacteristic = characteristic;
}
}
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (status == 0) {
BluetoothLeService.this.broadcastUpdate(BluetoothLeService.ACTION_DATA_AVAILABLE, characteristic);
if ((characteristic.getProperties() & 2) > 0) {
BluetoothLeService.this.readCharacteristic();
Log.i("MyActivity", "Characteristic permits read");
}
Log.i("MyActivity", "Characteristic was written");
return;
}
Log.i("MyActivity", "Failed to write characteristic");
BluetoothLeService.this.broadcastUpdate(BluetoothLeService.ACTION_GATT_WRITE_FAILED);
}
public void onReadRemoteRssi(BluetoothGatt gatt, int Rssi, int status) {
if (status == 0) {
BluetoothLeService.this.broadcastUpdate(BluetoothLeService.ACTION_GATT_RSSI_UPDATE, Rssi);
}
}
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
Log.i("MyActivity", "Characteristic has changed");
BluetoothLeService.this.broadcastUpdate(BluetoothLeService.ACTION_DATA_AVAILABLE, characteristic);
}
};
public class LocalBinder extends Binder {
public BluetoothLeService getService() {
return BluetoothLeService.this;
}
}
private void broadcastUpdate(String action) {
sendBroadcast(new Intent(action));
}
private void broadcastUpdate(String action, int Rssi) {
Intent intent = new Intent(action);
intent.putExtra(EXTRA_DATA, Rssi);
sendBroadcast(intent);
}
private void broadcastUpdate(String action, BluetoothGattCharacteristic characteristic) {
Intent intent = new Intent(action);
byte[] data = characteristic.getValue();
if (data != null && data.length > 0) {
StringBuilder stringBuilder = new StringBuilder(data.length);
int length = data.length;
for (int i = 0; i < length; i++) {
stringBuilder.append(String.format("%02X ", new Object[]{Byte.valueOf(data[i])}));
}
intent.putExtra(EXTRA_DATA, new StringBuilder(String.valueOf(new String(data))).append(" [ ").append(stringBuilder.toString()).toString());
intent.putExtra(CHARACTERISTIC_UUID, characteristic.getUuid().toString());
}
sendBroadcast(intent);
}
public IBinder onBind(Intent intent) {
return this.mBinder;
}
public boolean onUnbind(Intent intent) {
close();
return super.onUnbind(intent);
}
public boolean initialize() {
if (this.mBluetoothManager == null) {
this.mBluetoothManager = (BluetoothManager) getSystemService("bluetooth");
if (this.mBluetoothManager == null) {
Log.e(TAG, "Unable to initialize BluetoothManager.");
return false;
}
}
this.mBluetoothAdapter = this.mBluetoothManager.getAdapter();
if (this.mBluetoothAdapter != null) {
return true;
}
Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
return false;
}
public boolean connect(String address) {
if (this.mBluetoothAdapter == null || address == null) {
Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
return false;
} else if (this.mBluetoothDeviceAddress == null || !address.equals(this.mBluetoothDeviceAddress) || this.mBluetoothGatt == null) {
BluetoothDevice device = this.mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
Log.w(TAG, "LocalDevice not found. Unable to connect.");
return false;
}
this.mBluetoothGatt = device.connectGatt(this, false, this.mGattCallback);
Log.d(TAG, "Trying to create a new connection.");
this.mBluetoothDeviceAddress = address;
return true;
} else {
Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");
if (this.mBluetoothGatt.connect()) {
return true;
}
return false;
}
}
public void disconnect() {
if (this.mBluetoothAdapter == null || this.mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
} else {
this.mBluetoothGatt.disconnect();
}
}
public void readRemoteRssi() {
if (this.mBluetoothAdapter == null || this.mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
} else {
this.mBluetoothGatt.readRemoteRssi();
}
}
public BluetoothGattCharacteristic CurrentCharacteristic() {
return this.mFocusedCharacteristic;
}
public String getCurrentCharacteristicUuid() {
return this.mFocusedCharacteristic.getUuid().toString();
}
public void writeCharacteristic(byte[] c) {
mFocusedCharacteristic.setValue(c);
if (mBluetoothGatt!=null && mFocusedCharacteristic!=null){
mBluetoothGatt.writeCharacteristic(mFocusedCharacteristic);
}
}
public void readCharacteristic() {
Log.i("MyActivity", "Read Characteristic");
this.mBluetoothGatt.readCharacteristic(this.mFocusedCharacteristic);
}
public void notifyCharacteristic() {
Log.i("MyActivity", "Notify Characteristic");
setCharacteristicNotification(this.mFocusedCharacteristic, true);
}
public void setCurrentCharacteristic(BluetoothGattCharacteristic characteristic) {
this.mFocusedCharacteristic = characteristic;
}
public void close() {
if (this.mBluetoothGatt != null) {
this.mBluetoothGatt.close();
this.mBluetoothGatt = null;
}
}
public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
if (this.mBluetoothAdapter == null || this.mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
} else {
this.mBluetoothGatt.readCharacteristic(characteristic);
}
}
public boolean setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enable) {
Log.i("MyActivity", "setCharacteristicNotification");
this.mBluetoothGatt.setCharacteristicNotification(characteristic, enable);
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CHARACTERISTIC_UPDATE_NOTIFICATION_DESCRIPTOR_UUID);
descriptor.setValue(enable ? BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE : new byte[2]);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
SystemClock.sleep(200);
return this.mBluetoothGatt.writeDescriptor(descriptor);
}
public List<BluetoothGattService> getSupportedGattServices() {
if (this.mBluetoothGatt == null) {
return null;
}
return this.mBluetoothGatt.getServices();
}
}
The API is the same regardless if your app is in the foreground or background. The only thing you need to do is to make sure the system doesn't kill the app when it is in the background. To do that, simply have a Foreground Service running somewhere in your app process.
Use service to scan and connect ble devices when application is in background in android.
package com.example.tracker.service;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanSettings;
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.content.pm.PackageManager;
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.v4.widget.SwipeRefreshLayout;
import android.util.Log;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SeekBar;
import android.widget.Toast;
import com.google.firebase.auth.FirebaseAuth;
import com.example.tracker.R;
import com.example.tracker.utils.SampleGattAttributes;
import com.example.tracker.utils.SharedPreferencesUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import static com.example.tracker.constant.SharedFreferencesConstant.KEY_SP_MOBILE_NUMBER;
/**
* Created by Jprashant on 12/9/17.
*/
public class BackgroundService extends Service{
private int scanPeriod;
Context context;
String TAG="BackgroundService";
private BluetoothAdapter mBluetoothAdapter;
private boolean mScanning;
private Handler mHandler;
public String[] advDataTypes = new String[256];
ArrayList<BluetoothDevice> bluetoothDeviceArrayList=new ArrayList<>();
ArrayList<BluetoothDevice> bluetoothDeviceArrayListTwo=new ArrayList<>();
private static final int REQUEST_ENABLE_BT = 1;
// Stops scanning after 10 seconds.
private static final long SCAN_PERIOD = 10000;
/*Connect Ble Device*/
String deviceId;
public static String arrayDidOpnSec2;
BluetoothGattService gattService4;
public static ArrayList<BluetoothGattCharacteristic> lastCharacteristic;
// AlertDialog.Builder alertDialog;
private float avgRssi = 0.0f;
// private Dialog dialog;
private BluetoothLeService mBluetoothLeService;
private boolean mConnected = false;
private ArrayList<ArrayList<BluetoothGattCharacteristic>> mGattCharacteristics = new ArrayList();
//service and char uuid
private static final int TRACKER_ON_OFF = 2;
private static final UUID TRACER_TRIPPLE_PRESS_SERVICE=UUID.fromString("edfec62e-9910-0bac-5241-d8bda6932a2f");
private static final UUID TRACKER_TRIPPLE_PRESS_CHAR=UUID.fromString("772ae377-b3d2-4f8e-4042-5481d1e0098c");
private static final UUID IMMEDIATE_ALERT_UUID = UUID.fromString("00001802-0000-1000-8000-00805f9b34fb");
private static final UUID ALERT_LEVEL_UUID = UUID.fromString("00002a06-0000-1000-8000-00805f9b34fb");
private Button btnSMS;
public static String mDeviceName,mDeviceAddress,connectionStatus;
/*-------------------------------------------------------------------------------*/
public static final String PREFS_NAME = "PreferencesFile";
public int deviceCount = 0;
public String[] mData = new String[400];
private Handler mHandler1;
private ListView listItems;
/*--------for > 21--------------*/
private BluetoothLeScanner mLEScanner;
private ScanSettings settings;
private List<ScanFilter> filters;
private BluetoothGatt mGatt;
public BackgroundService() {
}
public BackgroundService(Context context) {
this.context = context;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// getting systems default ringtone
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(),"CALL YOUR METHOD",Toast.LENGTH_LONG).show();
mHandler = new Handler();
// Use this check to determine whether BLE is supported on the device. Then you can
// selectively disable BLE-related features.
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(context, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
}
// Initializes a Bluetooth adapter. For API level 18 and above, get a reference to
// BluetoothAdapter through BluetoothManager.
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
// Checks if Bluetooth is supported on the device.
if (mBluetoothAdapter == null) {
Toast.makeText(context, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();
return;
}
for (int i = 0; i < 256; i += REQUEST_ENABLE_BT) {
advDataTypes[i] = "Unknown Data Type";
}
advDataTypes[REQUEST_ENABLE_BT] = "Flags";
advDataTypes[2] = "Incomplete List of 16-bit Service Class UUIDs";
advDataTypes[3] = "Complete List of 16-bit Service Class UUIDs";
advDataTypes[4] = "Incomplete List of 32-bit Service Class UUIDs";
advDataTypes[5] = "Complete List of 32-bit Service Class UUIDs";
advDataTypes[6] = "Incomplete List of 128-bit Service Class UUIDs";
advDataTypes[7] = "Complete List of 128-bit Service Class UUIDs";
advDataTypes[8] = "Shortened Local Name";
advDataTypes[9] = "Complete Local Name";
advDataTypes[10] = "Tx Power Level";
advDataTypes[13] = "Class of LocalDevice";
advDataTypes[14] = "Simple Pairing Hash";
advDataTypes[15] = "Simple Pairing Randomizer R";
advDataTypes[16] = "LocalDevice ID";
advDataTypes[17] = "Security Manager Out of Band Flags";
advDataTypes[18] = "Slave Connection Interval Range";
advDataTypes[20] = "List of 16-bit Solicitaion UUIDs";
advDataTypes[21] = "List of 128-bit Solicitaion UUIDs";
advDataTypes[22] = "Service Data";
advDataTypes[23] = "Public Target Address";
advDataTypes[24] = "Random Target Address";
advDataTypes[25] = "Appearance";
advDataTypes[26] = "Advertising Interval";
advDataTypes[61] = "3D Information Data";
advDataTypes[255] = "Manufacturer Specific Data";
scanPeriod = getApplicationContext().getSharedPreferences(PREFS_NAME, 0).getInt("scan_interval", 6000);
scanTrackerDevices();
}
}, 10000);
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
}
public void scanTrackerDevices(){
Log.e(TAG,"scanTrackerDevices");
if (!mBluetoothAdapter.isEnabled()) {
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
}
}
scanLeDevice(true);
}
private void scanLeDevice(final boolean enable) {
bluetoothDeviceArrayList.clear();
if (enable) {
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
int arraySize=bluetoothDeviceArrayListTwo.size();
Log.e(TAG,"bluetoothDeviceArrayListTwo Size in scan :"+arraySize);
for (int i=0;i<bluetoothDeviceArrayListTwo.size();i++){
BluetoothDevice bluetoothDevice=bluetoothDeviceArrayListTwo.get(i);
Log.e(TAG,"Device Name in scan :"+bluetoothDevice.getName());
Log.e(TAG,"Device Address in scan :"+bluetoothDevice.getAddress());
if (i==0){
mBluetoothLeService.connect(bluetoothDevice.getAddress());
}
}
}
}, scanPeriod);
mScanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {
String d = "";
String rd = "";
String h = "0123456789ABCDEF";
int ln = 0;
int i = 0;
while (i < scanRecord.length) {
int x = scanRecord[i] & 255;
rd = new StringBuilder(String.valueOf(rd)).append(h.substring(x / 16, (x / 16) + REQUEST_ENABLE_BT)).append(h.substring(x % 16, (x % 16) +REQUEST_ENABLE_BT)).toString();
if (i == ln) {
ln = (i + x) + REQUEST_ENABLE_BT;
if (x == 0) {
break;
}
d = new StringBuilder(String.valueOf(d)).append("\r\n Length: ").append(h.substring(x / 16, (x / 16) + REQUEST_ENABLE_BT)).append(h.substring(x % 16, (x % 16) +REQUEST_ENABLE_BT)).toString();
i += REQUEST_ENABLE_BT;
x = scanRecord[i] & 255;
d = new StringBuilder(String.valueOf(d)).append(", Type :").append(h.substring(x / 16, (x / 16) + REQUEST_ENABLE_BT)).append(h.substring(x % 16, (x % 16) + REQUEST_ENABLE_BT)).append(" = ").append(advDataTypes[x]).append(", Value: ").toString();
rd = new StringBuilder(String.valueOf(rd)).append(h.substring(x / 16, (x / 16) + REQUEST_ENABLE_BT)).append(h.substring(x % 16, (x % 16) + REQUEST_ENABLE_BT)).toString();
} else {
d = new StringBuilder(String.valueOf(d)).append(" ").append(h.substring(x / 16, (x / 16) + REQUEST_ENABLE_BT)).append(h.substring(x % 16, (x % 16) +REQUEST_ENABLE_BT)).toString();
}
i += REQUEST_ENABLE_BT;
}
Log.e(TAG,"UUID : "+device.getUuids());
String[] arrayDeviceName=String.valueOf(device.getName()).split(" ");
String deviceName0=arrayDeviceName[0];
bluetoothDeviceArrayListTwo.add(device);
}
};
/*-------------------Connect BLE---------------------------------------------*/
private Handler mHandler2;
public final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent)
{
String action = intent.getAction();
if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action))
{
numberOfRssi = 0;
avgRssi = 0.0f;
mConnected = true;
updateConnectionState(R.string.connected);
mHandler2.postDelayed(startRssi, 300);
Log.e(TAG,"ACTION_GATT_CONNECTED");
}
else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
mConnected = false;
updateConnectionState(R.string.disconnected);
Log.e(TAG,"ACTION_GATT_DISCONNECTED");
} else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
displayGattServicesForDimmer(mBluetoothLeService.getSupportedGattServices());// For dimmer
Log.e(TAG,"ACTION_GATT_SERVICES_DISCOVERED");
} else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
Log.e(TAG,"ACTION_DATA_AVAILABLE");
String unknownServiceString = context.getResources().getString(R.string.unknown_service);
displayDimmerData("<<" + SampleGattAttributes.lookup(intent.getStringExtra(BluetoothLeService.CHARACTERISTIC_UUID), unknownServiceString) + ">> Value: " + intent.getStringExtra(BluetoothLeService.EXTRA_DATA) + "]");
displayDimmer2(intent.getStringExtra(BluetoothLeService.EXTRA_DATA));
} else if (BluetoothLeService.ACTION_GATT_RSSI_UPDATE.equals(action)) {
updateRssi(intent.getIntExtra(BluetoothLeService.EXTRA_DATA, -400));
} else if (BluetoothLeService.ACTION_GATT_WRITE_FAILED.equals(action)) {
Log.e(TAG,"ACTION_GATT_WRITE_FAILED");
}
}
};
/*------------------------------------------------------------------------*/
#Override
public void onCreate() {
super.onCreate();
// -------------------Connect Ble--------------------------------------
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);
intentFilter.addAction(BluetoothLeService.ACTION_GATT_RSSI_UPDATE);
intentFilter.addAction(BluetoothLeService.ACTION_GATT_WRITE_FAILED);
Log.e(TAG,"OnResume()");
getApplicationContext().registerReceiver(mGattUpdateReceiver, intentFilter);
getApplicationContext().bindService(new Intent(getApplicationContext(), BluetoothLeService.class), mServiceConnection, 1);
mHandler2=new Handler();
}
private BluetoothGattCharacteristic mNotifyCharacteristic;
private final ServiceConnection mServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName componentName, IBinder service) {
mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService();
if (!mBluetoothLeService.initialize()) {
Log.e(TAG, "Unable to initialize Bluetooth");
}
}
public void onServiceDisconnected(ComponentName componentName) {
mBluetoothLeService = null;
}
};
private boolean notificationActive = true;
private int numberOfRssi = 0;
private Runnable startRssi = new Runnable() {
public void run() {
if (mConnected) {
mBluetoothLeService.readRemoteRssi();
mHandler2.postDelayed(startRssi, 200);
}
}
};
public BluetoothGatt getmGatt() {
return mGatt;
}
//code from DeviceControlActivity
private void updateConnectionState(final int resourceId) {
connectionStatus= String.valueOf(resourceId);
Log.e(TAG,"Resource ID"+resourceId);
}
private void displayDimmerData(String data){
Log.e(TAG,"Display Data :"+data);
}
private void displayDimmer2(String data){
Log.e(TAG,"display Dimmer2"+data);
String sosString = data.substring(0, Math.min(data.length(), 3));
Log.e(TAG,"SOS String :"+sosString);
if (sosString.equals("SOS")){
Intent callIntent = new Intent(Intent.ACTION_CALL);
callIntent.setData(Uri.parse("tel:"+ SharedPreferencesUtils.getStringFromSharedPreferences(KEY_SP_MOBILE_NUMBER,getApplicationContext())));
callIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getApplicationContext().startActivity(callIntent);
}
}
private void updateRssi(int data) {
if (data > -400) {
if (this.numberOfRssi > 10) {
this.avgRssi = ((9.0f * this.avgRssi) + ((float) data)) / 10.0f;
} else {
this.avgRssi = (this.avgRssi + ((float) data)) / 2.0f;
this.numberOfRssi++;
}
connectionStatus="Connected, RSSI:" + data + ", Avg:" + Math.round(this.avgRssi);
}
}
/*-------------------------disaplay gatt service for dimmer----------------------*/
private void displayGattServicesForDimmer(List<BluetoothGattService> gattServices) {
if (gattServices != null) {
String unknownServiceString = getResources().getString(R.string.unknown_service);
String unknownCharaString = getResources().getString(R.string.unknown_characteristic);
ArrayList<HashMap<String, String>> gattServiceData = new ArrayList();
ArrayList<ArrayList<HashMap<String, String>>> gattCharacteristicData = new ArrayList();
this.mGattCharacteristics = new ArrayList();
for (BluetoothGattService gattService : gattServices) {
HashMap<String, String> currentServiceData = new HashMap();
String uuid = gattService.getUuid().toString();
currentServiceData.put("NAME", SampleGattAttributes.lookup(uuid, unknownServiceString));
currentServiceData.put("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("NAME", "\t\t\t<<" + SampleGattAttributes.lookup(uuid, unknownCharaString) + ">>");
currentCharaData.put("UUID", "\t\t\tUUID: 0x" + uuid.substring(4, 8) + ", Properties: " + translateProperties(gattCharacteristic.getProperties()));
gattCharacteristicGroupData.add(currentCharaData);
Log.i(TAG,"CUrrent CHARACTERISTIC DATA"+currentCharaData);
Log.i(TAG,"UUID : "+uuid.substring(4, 8));
Log.i(TAG,"Proprties : "+gattCharacteristic.getProperties());
Log.i(TAG,"Translate Proprties : "+translateProperties(gattCharacteristic.getProperties()));
Log.i(TAG,"char list"+gattCharacteristicData.toString());
}
gattService4=gattService;
this.mGattCharacteristics.add(charas);
}
if (mGattCharacteristics.get(3)!=null) {
lastCharacteristic = new ArrayList<>(mGattCharacteristics.get(3));
enableNotifyOfCharcteristicForDimmer(lastCharacteristic);
}
}
}
private String translateProperties(int properties) {
String s = "";
if ((properties & 1) > 0) {
s = new StringBuilder(String.valueOf(s)).append("/Broadcast").toString();
}
if ((properties & 2) > 0) {
s = new StringBuilder(String.valueOf(s)).append("/Read").toString();
}
if ((properties & 4) > 0) {
s = new StringBuilder(String.valueOf(s)).append("/WriteWithoutResponse").toString();
}
if ((properties & 8) > 0) {
s = new StringBuilder(String.valueOf(s)).append("/Write").toString();
}
if ((properties & 16) > 0) {
s = new StringBuilder(String.valueOf(s)).append("/Notify").toString();
}
if ((properties & 32) > 0) {
s = new StringBuilder(String.valueOf(s)).append("/Indicate").toString();
}
if ((properties & 64) > 0) {
s = new StringBuilder(String.valueOf(s)).append("/SignedWrite").toString();
}
if ((properties & 128) > 0) {
s = new StringBuilder(String.valueOf(s)).append("/ExtendedProperties").toString();
}
if (s.length() > 1) {
return s.substring(1);
}
return s;
}
// Enable Characteristic for dimmer
public void enableNotifyOfCharcteristicForDimmer(ArrayList<BluetoothGattCharacteristic> lastCharacteristic){
if(mGattCharacteristics!=null) {
checkCharacteristicPresent(lastCharacteristic.get(0));
mBluetoothLeService.setCharacteristicNotification(lastCharacteristic.get(0), true);
notificationActive = true;
Log.e(TAG,"Characteristic index : "+0+":\nM GATT CHARACTERISTIC AT "+"Service 4 : CHAR"+ 0 +" :" +lastCharacteristic.get(0).toString());
checkCharacteristicPresent(lastCharacteristic.get(1));
mBluetoothLeService.setCharacteristicNotification(lastCharacteristic.get(1), true);
notificationActive = true;
Log.e(TAG,"Characteristic index : "+1+":\nM GATT CHARACTERISTIC AT "+"Service 4 : CHAR"+ 1 +" :" +lastCharacteristic.get(1).toString());
checkCharacteristicPresent(lastCharacteristic.get(2));
mBluetoothLeService.setCharacteristicNotification(lastCharacteristic.get(2), true);
notificationActive = true;
Log.e(TAG,"Characteristic index : "+2+":\nM GATT CHARACTERISTIC AT "+"Service 4 : CHAR"+ 2 +" :" +lastCharacteristic.get(2).toString());
checkCharacteristicPresent(lastCharacteristic.get(3));
mBluetoothLeService.setCharacteristicNotification(lastCharacteristic.get(3), true);
notificationActive = true;
Log.e(TAG,"Characteristic index : "+3+":\nM GATT CHARACTERISTIC AT "+"Service 4 : CHAR"+ 3 +" :" +lastCharacteristic.get(3).toString());
checkCharacteristicPresent(lastCharacteristic.get(4));
mBluetoothLeService.setCharacteristicNotification(lastCharacteristic.get(4), true);
notificationActive = true;
Log.e(TAG,"Characteristic index : "+4+":\nM GATT CHARACTERISTIC AT "+"Service 4 : CHAR"+ 4 +" :" +lastCharacteristic.get(4).toString());
checkCharacteristicPresent(lastCharacteristic.get(5));
mBluetoothLeService.setCharacteristicNotification(lastCharacteristic.get(5), true);
notificationActive = true;
Log.e(TAG,"Characteristic index : "+5+":\nM GATT CHARACTERISTIC AT "+"Service 4 : CHAR"+ 5 +" :" +lastCharacteristic.get(5).toString());
checkCharacteristicPresent(lastCharacteristic.get(2));
mBluetoothLeService.setCharacteristicNotification(lastCharacteristic.get(2), true);
notificationActive = true;
Log.e(TAG,"Characteristic index : "+2+":\nM GATT CHARACTERISTIC AT "+"Service 4 : CHAR"+ 2 +" :" +lastCharacteristic.get(2).toString());
}
}
// Check the type of characteristic i.e READ/WRITE/NOTIFY
public void checkCharacteristicPresent(BluetoothGattCharacteristic characteristic) {
int charaProp = characteristic.getProperties();
Log.e(TAG, "checkCharacteristicPresent Prop : " + charaProp);
mBluetoothLeService.setCurrentCharacteristic(characteristic);
if ((charaProp & 2) > 0) {
Log.e(TAG, "CharProp & 2 : " + charaProp);
mBluetoothLeService.readCharacteristic(characteristic);
}
if ((charaProp & 16) > 0) {
Log.e(TAG, "CharProp & 16 : " + charaProp);
mNotifyCharacteristic = characteristic;
} else {
if (mNotifyCharacteristic != null) {
mBluetoothLeService.setCharacteristicNotification(mNotifyCharacteristic, false);
mNotifyCharacteristic = null;
}
}
if ((charaProp & 8) > 0 || (charaProp & 4) > 0) {
Log.e(TAG, "CharProp & 4 : " + charaProp);
} else {
Log.e(TAG, "Else : " + charaProp);
}
}
}
I am developing an android app that is going to communicate with a BLE device(RN4020) connected with a target board(micro controller). I developed the app that can able to send data to the target board through RN4020 and it received successfully through UART.But I am unable to receive data to the app from target device. I am sending data for every one second from microcontroller. But with the app MLDP perminal downloaded from play store can able to send and receive data simultaneously.
While debugging it doesn't reach onCharacteristicRead.
How to receive data from the device to app?
package com.example.designemb5.tempworking;
import android.Manifest;
import android.app.AlertDialog;
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.BluetoothProfile;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.ParcelUuid;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;
public class MainActivity extends AppCompatActivity {
BluetoothManager btManager;
BluetoothAdapter btAdapter;
BluetoothLeScanner btScanner;
BluetoothDevice mBluetoothDevice;
public BluetoothAdapter mBluetoothAdapter;
public BluetoothGatt mBluetoothGatt;
public BluetoothGattService mBluetoothGattService;
private int mConnectionState = STATE_DISCONNECTED;
private BluetoothGattCharacteristic mWriteCharacteristic;
private static final int STATE_DISCONNECTED = 0;
private static final int STATE_CONNECTING = 1;
private static final int STATE_CONNECTED = 2;
Button startScanningButton;
Button stopScanningButton;
Button connectButton;
Button disconnectButton;
public boolean mConnected = false;
public boolean mCharacteristics = true;
private static final String TAG = "BLUETOOTH_LE";
public static List<ParcelUuid> MY_UUID;
public final static String ACTION_GATT_CONNECTED = "com.example.designemb5.tempworking.ACTION_GATT_CONNECTED";
public final static String ACTION_GATT_DISCONNECTED = "com.example.designemb5.tempworking.ACTION_GATT_DISCONNECTED";
public final static String ACTION_GATT_SERVICES_DISCOVERED = "com.example.designemb5.tempworking.ACTION_GATT_SERVICES_DISCOVERED";
public final static String ACTION_DATA_AVAILABLE = "com.example.designemb5.tempworking.ACTION_DATA_AVAILABLE";
public final static String EXTRA_DATA = "com.example.designemb5.tempworking.EXTRA_DATA";
public final static UUID MY_UUID_RN4020_SERVICE = UUID.fromString("00035b03-58e6-07dd-021a-08123a000300");
public final static UUID MY_UUID_RN4020_CHARACTERISTIC_WRITE = UUID.fromString("00035b03-58e6-07dd-021a-08123a000301");
public final static UUID MY_UUID_RN4020_CHARACTERISTIC_READ = UUID.fromString("00035b03-58e6-07dd-021a-08123a0003ff");
TextView peripheralTextView;
private final static int REQUEST_ENABLE_BT = 1;
private static final int PERMISSION_REQUEST_COARSE_LOCATION = 1;
public String mDeviceAddress;
public int mTestVal = 1;
public static Map<ParcelUuid, byte[]> mDeviceData;
#RequiresApi(api = Build.VERSION_CODES.M)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
connectButton = (Button) findViewById(R.id.ConnectButton);
disconnectButton = (Button) findViewById(R.id.disonnectButton);
peripheralTextView = (TextView) findViewById(R.id.PeripheralTextView);
peripheralTextView.setMovementMethod(new ScrollingMovementMethod());
startScanningButton = (Button) findViewById(R.id.StartScanButton);
startScanningButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
startScanning();
}
});
stopScanningButton = (Button) findViewById(R.id.StopScanButton);
stopScanningButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
stopScanning();
}
});
stopScanningButton.setVisibility(View.INVISIBLE);
btManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
btAdapter = btManager.getAdapter();
btScanner = btAdapter.getBluetoothLeScanner();
if (btAdapter != null && !btAdapter.isEnabled()) {
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent,REQUEST_ENABLE_BT);
}
// Make sure we have access coarse location enabled, if not, prompt the user to enable it
if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("This app needs location access");
builder.setMessage("Please grant location access so this app can detect peripherals.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);
}
});
builder.show();
}
}
public void startScanning() {
System.out.println("start scanning");
peripheralTextView.setText("");
startScanningButton.setVisibility(View.INVISIBLE);
stopScanningButton.setVisibility(View.VISIBLE);
AsyncTask.execute(new Runnable() {
#Override
public void run() {
btScanner.startScan(leScanCallback);
}
});
}
public void stopScanning() {
System.out.println("stopping scanning");
peripheralTextView.append("Stopped Scanning");
startScanningButton.setVisibility(View.VISIBLE);
stopScanningButton.setVisibility(View.INVISIBLE);
AsyncTask.execute(new Runnable() {
#Override
public void run() {
btScanner.stopScan(leScanCallback);
}
});
}
public void connect(View view) {
connectButton.setVisibility(View.INVISIBLE);
disconnectButton.setVisibility(View.VISIBLE);
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
final BluetoothDevice device = btAdapter
.getRemoteDevice(mDeviceAddress);
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
}
public void disconnect(View view) {
connectButton.setVisibility(View.VISIBLE);
disconnectButton.setVisibility(View.INVISIBLE);
mBluetoothGatt.disconnect();
}
public void senddata(View view) {
{
int value = 0x01;
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
/*check if the service is available on the device*/
BluetoothGattService mCustomService = mBluetoothGatt.getService(MY_UUID_RN4020_SERVICE);
if (mCustomService == null) {
Log.w(TAG, "Custom BLE Service not found");
return;
}
/*get the read characteristic from the service*/
BluetoothGattCharacteristic mWriteCharacteristic = mCustomService.getCharacteristic(MY_UUID_RN4020_CHARACTERISTIC_WRITE);
mWriteCharacteristic.setValue(value, BluetoothGattCharacteristic.FORMAT_UINT8, 0);
if (mBluetoothGatt.writeCharacteristic(mWriteCharacteristic) == false) {
Log.w(TAG, "Failed to write characteristic");
}
}
}
public void receivedata(View view) {
{
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
/*check if the service is available on the device*/
BluetoothGattService mCustomService = mBluetoothGatt.getService(MY_UUID_RN4020_SERVICE);
if (mCustomService == null) {
Log.w(TAG, "Custom BLE Service not found");
return;
}
BluetoothGattCharacteristic mReadCharacteristic = mCustomService.getCharacteristic(MY_UUID_RN4020_CHARACTERISTIC_READ);
if (mBluetoothGatt.readCharacteristic(mReadCharacteristic) == false) {
Log.w(TAG, "Failed to read characteristic");
}
mBluetoothGatt.readCharacteristic(mReadCharacteristic);
}
}
// Device scan callback.
private ScanCallback leScanCallback = new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
processResult(result);
}
private void processResult(ScanResult result){
mBluetoothDevice = result.getDevice();
mDeviceAddress = result.getDevice().getAddress();
mDeviceData = result.getScanRecord().getServiceData();
MY_UUID = result.getScanRecord().getServiceUuids();
peripheralTextView.append("Device Name: " + mDeviceAddress + "\n");
stopScanning();
}
};
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
// updateStatus(characteristic);
Log.e("gatt", "writeChar");
}
#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());
TimerTask task = new TimerTask() {
#Override
public void run() {
if (mBluetoothGatt != null)
mBluetoothGatt.readRemoteRssi();
}
};
Timer mRssiTimer = new Timer();
mRssiTimer.schedule(task, 1000, 1000);
} 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);
}
BluetoothGattService mCustomService = mBluetoothGatt.getService(MY_UUID_RN4020_SERVICE);
BluetoothGattCharacteristic mReadCharacteristic = mCustomService.getCharacteristic(MY_UUID_RN4020_CHARACTERISTIC_READ);
gatt.readCharacteristic(mReadCharacteristic);
gatt.setCharacteristicNotification(mReadCharacteristic, true);
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
gatt.readCharacteristic(characteristic);
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
};
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_COARSE_LOCATION: {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
System.out.println("coarse location permission granted");
} else {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Functionality limited");
builder.setMessage("Since location access has not been granted, this app will not be able to discover beacons when in the background.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
}
});
builder.show();
}
return;
}
}
}
public void writeCharacteristic(BluetoothGattCharacteristic characteristic) {
mBluetoothGatt.writeCharacteristic(characteristic);
}
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
sendBroadcast(intent);
}
private void broadcastUpdate(final String action,
final BluetoothGattCharacteristic characteristic) {
final Intent intent = new Intent(action);
// This is special handling for the Heart Rate Measurement profile. Data
// parsing is
// carried out as per profile specifications:
// http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml
/* if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
int flag = characteristic.getProperties();
int format = -1;
if ((flag & 0x01) != 0) {
format = BluetoothGattCharacteristic.FORMAT_UINT16;
Log.d(TAG, "Heart rate format UINT16.");
} else {
format = BluetoothGattCharacteristic.FORMAT_UINT8;
Log.d(TAG, "Heart rate format UINT8.");
}
final int heartRate = characteristic.getIntValue(format, 1);
Log.d(TAG, String.format("Received heart rate: %d", heartRate));
intent.putExtra(EXTRA_DATA, String.valueOf(heartRate));
} else {
// For all other profiles, writes the data formatted in HEX.
final byte[] data = characteristic.getValue();
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());
}
}*/
final byte[] data = characteristic.getValue();
Log.v(TAG, "data.length: " + data.length);
if (data != null && data.length > 0) {
final StringBuilder stringBuilder = new StringBuilder(data.length);
for(byte byteChar : data) {
stringBuilder.append(String.format("%02X ", byteChar));
Log.v(TAG, String.format("%02X ", byteChar));
}
intent.putExtra(EXTRA_DATA, new String(data) + "\n" + stringBuilder.toString());
}
sendBroadcast(intent);
}
private void showMessage(String str){
Toast.makeText(MainActivity.this, str, Toast.LENGTH_SHORT).show();
}
}
To enable notifications:
gatt.setCharacteristicNotification(yourCharacteristic, true);
BluetoothGattDescriptor desc = yourCharacteristic.getDescriptor(UUID);
then:
desc.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(desc);
After doing this, onCharacteristicChanged() should be called every time data is sent. Confirm that enabling notifications was successful by overriding the onDescriptorWrite() method.
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.